diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 7fd444a1a4162..ec3208e5b7377 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1628,29 +1628,21 @@ config_timeZoneRulesUpdateTrackingEnabled are true.] --> 5 - + true @null - + true @@ -1669,25 +1661,10 @@ --> - - true - - com.android.location.fused - true @@ -1698,9 +1675,7 @@ true @@ -1711,9 +1686,7 @@ true @@ -1721,19 +1694,8 @@ config_enableActivityRecognitionHardwareOverlay is false. --> @null - + com.android.location.fused diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 357b1f069107c..81ef872e3f0ae 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1869,7 +1869,6 @@ - @@ -2019,7 +2018,6 @@ - diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index e9db9c819ab71..003525c91c32f 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -18,6 +18,8 @@ package com.android.server; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.location.LocationManager.FUSED_PROVIDER; import static android.location.LocationManager.GPS_PROVIDER; @@ -35,14 +37,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.ResolveInfo; -import android.content.pm.Signature; -import android.content.res.Resources; -import android.hardware.location.ActivityRecognitionHardware; import android.location.Address; import android.location.Criteria; import android.location.GeocoderParams; @@ -52,6 +47,7 @@ import android.location.IBatchedLocationCallback; import android.location.IGnssMeasurementsListener; import android.location.IGnssNavigationMessageListener; import android.location.IGnssStatusListener; +import android.location.IGpsGeofenceHardware; import android.location.ILocationListener; import android.location.ILocationManager; import android.location.Location; @@ -91,11 +87,11 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.location.AbstractLocationProvider; import com.android.server.location.AbstractLocationProvider.State; -import com.android.server.location.ActivityRecognitionProxy; import com.android.server.location.CallerIdentity; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; +import com.android.server.location.HardwareActivityRecognitionProxy; import com.android.server.location.LocationFudger; import com.android.server.location.LocationProviderProxy; import com.android.server.location.LocationRequestStatistics; @@ -114,7 +110,6 @@ import java.io.FileDescriptor; import java.io.PrintStream; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -542,77 +537,6 @@ public class LocationManagerService extends ILocationManager.Stub { } } - @GuardedBy("mLock") - private void ensureFallbackFusedProviderPresentLocked(String[] pkgs) { - PackageManager pm = mContext.getPackageManager(); - String systemPackageName = mContext.getPackageName(); - ArrayList> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs); - - List rInfos = pm.queryIntentServicesAsUser( - new Intent(FUSED_LOCATION_SERVICE_ACTION), - PackageManager.GET_META_DATA, mUserInfoStore.getCurrentUserId()); - for (ResolveInfo rInfo : rInfos) { - String packageName = rInfo.serviceInfo.packageName; - - // Check that the signature is in the list of supported sigs. If it's not in - // this list the standard provider binding logic won't bind to it. - try { - PackageInfo pInfo; - pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); - if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) { - Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION + - ", but has wrong signature, ignoring"); - continue; - } - } catch (NameNotFoundException e) { - Log.e(TAG, "missing package: " + packageName); - continue; - } - - // Get the version info - if (rInfo.serviceInfo.metaData == null) { - Log.w(TAG, "Found fused provider without metadata: " + packageName); - continue; - } - - int version = rInfo.serviceInfo.metaData.getInt( - ServiceWatcher.EXTRA_SERVICE_VERSION, -1); - if (version == 0) { - // This should be the fallback fused location provider. - - // Make sure it's in the system partition. - if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { - if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName); - continue; - } - - // Check that the fallback is signed the same as the OS - // as a proxy for coreApp="true" - if (pm.checkSignatures(systemPackageName, packageName) - != PackageManager.SIGNATURE_MATCH) { - if (D) { - Log.d(TAG, "Fallback candidate not signed the same as system: " - + packageName); - } - continue; - } - - // Found a valid fallback. - if (D) Log.d(TAG, "Found fallback provider: " + packageName); - return; - } else { - if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName); - } - } - - throw new IllegalStateException("Unable to find a fused location provider that is in the " - + "system partition with version 0 and signed with the platform certificate. " - + "Such a package is needed to provide a default fused location provider in the " - + "event that no other fused location provider has been installed or is currently " - + "available. For example, coreOnly boot mode when decrypting the data " - + "partition. The fallback must also be marked coreApp=\"true\" in the manifest"); - } - @GuardedBy("mLock") private void initializeProvidersLocked() { if (GnssManagerService.isGnssSupported()) { @@ -622,33 +546,11 @@ public class LocationManagerService extends ILocationManager.Stub { gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider()); } - /* - Load package name(s) containing location provider support. - These packages can contain services implementing location providers: - Geocoder Provider, Network Location Provider, and - Fused Location Provider. They will each be searched for - service components implementing these providers. - The location framework also has support for installation - of new location providers at run-time. The new package does not - have to be explicitly listed here, however it must have a signature - that matches the signature of at least one package on this list. - */ - Resources resources = mContext.getResources(); - String[] pkgs = resources.getStringArray( - com.android.internal.R.array.config_locationProviderPackageNames); - if (D) { - Log.d(TAG, "certificates for location providers pulled from: " + - Arrays.toString(pkgs)); - } - - ensureFallbackFusedProviderPresentLocked(pkgs); - - LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind( + LocationProviderProxy networkProvider = LocationProviderProxy.createAndRegister( mContext, NETWORK_LOCATION_SERVICE_ACTION, com.android.internal.R.bool.config_enableNetworkLocationOverlay, - com.android.internal.R.string.config_networkLocationProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames); + com.android.internal.R.string.config_networkLocationProviderPackageName); if (networkProvider != null) { LocationProviderManager networkManager = new LocationProviderManager(NETWORK_PROVIDER); mProviderManagers.add(networkManager); @@ -657,13 +559,18 @@ public class LocationManagerService extends ILocationManager.Stub { Slog.w(TAG, "no network location provider found"); } + // ensure that a fused provider exists which will work in direct boot + Preconditions.checkState(!mContext.getPackageManager().queryIntentServicesAsUser( + new Intent(FUSED_LOCATION_SERVICE_ACTION), + MATCH_DIRECT_BOOT_AWARE | MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).isEmpty(), + "Unable to find a direct boot aware fused location provider"); + // bind to fused provider - LocationProviderProxy fusedProvider = LocationProviderProxy.createAndBind( + LocationProviderProxy fusedProvider = LocationProviderProxy.createAndRegister( mContext, FUSED_LOCATION_SERVICE_ACTION, com.android.internal.R.bool.config_enableFusedLocationOverlay, - com.android.internal.R.string.config_fusedLocationProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames); + com.android.internal.R.string.config_fusedLocationProviderPackageName); if (fusedProvider != null) { LocationProviderManager fusedManager = new LocationProviderManager(FUSED_PROVIDER); mProviderManagers.add(fusedManager); @@ -674,47 +581,30 @@ public class LocationManagerService extends ILocationManager.Stub { } // bind to geocoder provider - mGeocodeProvider = GeocoderProxy.createAndBind(mContext, - com.android.internal.R.bool.config_enableGeocoderOverlay, - com.android.internal.R.string.config_geocoderProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames); + mGeocodeProvider = GeocoderProxy.createAndRegister(mContext); if (mGeocodeProvider == null) { Slog.e(TAG, "no geocoder provider found"); } + // bind to geofence proxy if (mGnssManagerService != null) { - // bind to geofence provider - GeofenceProxy provider = GeofenceProxy.createAndBind( - mContext, com.android.internal.R.bool.config_enableGeofenceOverlay, - com.android.internal.R.string.config_geofenceProviderPackageName, - com.android.internal.R.array.config_locationProviderPackageNames, - mGnssManagerService.getGpsGeofenceProxy(), - null); - if (provider == null) { - Slog.d(TAG, "Unable to bind FLP Geofence proxy."); + IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy(); + if (gpsGeofenceHardware != null) { + GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware); + if (provider == null) { + Slog.d(TAG, "unable to bind to GeofenceProxy"); + } } } // bind to hardware activity recognition - boolean activityRecognitionHardwareIsSupported = ActivityRecognitionHardware.isSupported(); - ActivityRecognitionHardware activityRecognitionHardware = null; - if (activityRecognitionHardwareIsSupported) { - activityRecognitionHardware = ActivityRecognitionHardware.getInstance(mContext); - } else { - Slog.d(TAG, "Hardware Activity-Recognition not supported."); - } - ActivityRecognitionProxy proxy = ActivityRecognitionProxy.createAndBind( - mContext, - activityRecognitionHardwareIsSupported, - activityRecognitionHardware, - com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay, - com.android.internal.R.string.config_activityRecognitionHardwarePackageName, - com.android.internal.R.array.config_locationProviderPackageNames); - if (proxy == null) { - Slog.d(TAG, "Unable to bind ActivityRecognitionProxy."); + HardwareActivityRecognitionProxy hardwareActivityRecognitionProxy = + HardwareActivityRecognitionProxy.createAndRegister(mContext); + if (hardwareActivityRecognitionProxy == null) { + Log.e(TAG, "unable to bind ActivityRecognitionProxy"); } - String[] testProviderStrings = resources.getStringArray( + String[] testProviderStrings = mContext.getResources().getStringArray( com.android.internal.R.array.config_testLocationProviders); for (String testProviderString : testProviderStrings) { String[] fragments = testProviderString.split(","); diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java index 7f51aa9068fca..8564cb456ba64 100644 --- a/services/core/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/ServiceWatcher.java @@ -16,7 +16,19 @@ package com.android.server; +import static android.content.Context.BIND_AUTO_CREATE; +import static android.content.Context.BIND_NOT_FOREGROUND; +import static android.content.Context.BIND_NOT_VISIBLE; +import static android.content.pm.PackageManager.GET_META_DATA; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; + +import android.annotation.BoolRes; import android.annotation.Nullable; +import android.annotation.StringRes; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -24,11 +36,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; -import android.content.pm.Signature; import android.content.res.Resources; import android.os.Bundle; import android.os.Handler; @@ -37,15 +45,10 @@ import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; -import android.util.Slog; import com.android.internal.content.PackageMonitor; import com.android.internal.util.Preconditions; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.concurrent.Callable; @@ -55,16 +58,16 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** - * Find the best Service, and bind to it. - * Handles run-time package changes. + * Maintains a binding to the best service that matches the given intent information. Bind and + * unbind callbacks, as well as all binder operations, will all be run on the given handler. */ public class ServiceWatcher implements ServiceConnection { private static final String TAG = "ServiceWatcher"; - private static final boolean D = false; + private static final boolean D = Log.isLoggable(TAG, Log.DEBUG); - public static final String EXTRA_SERVICE_VERSION = "serviceVersion"; - public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser"; + private static final String EXTRA_SERVICE_VERSION = "serviceVersion"; + private static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser"; private static final long BLOCKING_BINDER_TIMEOUT_MS = 30 * 1000; @@ -83,280 +86,300 @@ public class ServiceWatcher implements ServiceConnection { T run(IBinder binder) throws RemoteException; } - public static ArrayList> getSignatureSets(Context context, - String... packageNames) { - PackageManager pm = context.getPackageManager(); + /** + * Information on the service ServiceWatcher has selected as the best option for binding. + */ + public static final class ServiceInfo implements Comparable { - ArrayList> signatureSets = new ArrayList<>(packageNames.length); - for (String packageName : packageNames) { - try { - Signature[] signatures = pm.getPackageInfo(packageName, - PackageManager.MATCH_SYSTEM_ONLY - | PackageManager.GET_SIGNATURES).signatures; + public static final ServiceInfo NONE = new ServiceInfo(Integer.MIN_VALUE, null, + UserHandle.USER_NULL); - HashSet set = new HashSet<>(); - Collections.addAll(set, signatures); - signatureSets.add(set); - } catch (NameNotFoundException e) { - Log.w(TAG, packageName + " not found"); + public final int version; + @Nullable public final ComponentName component; + @UserIdInt public final int userId; + + private ServiceInfo(ResolveInfo resolveInfo, int currentUserId) { + Preconditions.checkArgument(resolveInfo.serviceInfo.getComponentName() != null); + + Bundle metadata = resolveInfo.serviceInfo.metaData; + boolean isMultiuser; + if (metadata != null) { + version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE); + isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false); + } else { + version = Integer.MIN_VALUE; + isMultiuser = false; } + + component = resolveInfo.serviceInfo.getComponentName(); + userId = isMultiuser ? UserHandle.USER_SYSTEM : currentUserId; } - return signatureSets; - } - /** Checks if signatures match. */ - public static boolean isSignatureMatch(Signature[] signatures, - List> sigSets) { - if (signatures == null) return false; + private ServiceInfo(int version, @Nullable ComponentName component, int userId) { + Preconditions.checkArgument(component != null || version == Integer.MIN_VALUE); + this.version = version; + this.component = component; + this.userId = userId; + } - // build hashset of input to test against - HashSet inputSet = new HashSet<>(); - Collections.addAll(inputSet, signatures); - - // test input against each of the signature sets - for (HashSet referenceSet : sigSets) { - if (referenceSet.equals(inputSet)) { + @Override + public boolean equals(Object o) { + if (this == o) { return true; } + if (!(o instanceof ServiceInfo)) { + return false; + } + ServiceInfo that = (ServiceInfo) o; + return version == that.version && userId == that.userId + && Objects.equals(component, that.component); + } + + @Override + public int hashCode() { + return Objects.hash(version, component, userId); + } + + @Override + public int compareTo(ServiceInfo that) { + // ServiceInfos with higher version numbers always win (having a version number > + // MIN_VALUE implies having a non-null component). if version numbers are equal, a + // non-null component wins over a null component. if the version numbers are equal and + // both components exist then we prefer components that work for all users vs components + // that only work for a single user at a time. otherwise everything's equal. + int ret = Integer.compare(version, that.version); + if (ret == 0) { + if (component == null && that.component != null) { + ret = -1; + } else if (component != null && that.component == null) { + ret = 1; + } else { + if (userId != UserHandle.USER_SYSTEM && that.userId == UserHandle.USER_SYSTEM) { + ret = -1; + } else if (userId == UserHandle.USER_SYSTEM + && that.userId != UserHandle.USER_SYSTEM) { + ret = 1; + } + } + } + return ret; + } + + @Override + public String toString() { + return component + "@" + version + "[u" + userId + "]"; } - return false; } private final Context mContext; - private final String mTag; - private final String mAction; - private final String mServicePackageName; - private final List> mSignatureSets; - private final Handler mHandler; + private final Intent mIntent; - // read/write from handler thread - private IBinder mBestService; + @Nullable private final BinderRunner mOnBind; + @Nullable private final Runnable mOnUnbind; + + // read/write from handler thread only private int mCurrentUserId; - // read from any thread, write from handler thread - private volatile ComponentName mBestComponent; - private volatile int mBestVersion; - private volatile int mBestUserId; + // write from handler thread only, read anywhere + private volatile ServiceInfo mServiceInfo; - public ServiceWatcher(Context context, String logTag, String action, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, Handler handler) { - Resources resources = context.getResources(); + // read/write from handler thread only + private IBinder mBinder; + public ServiceWatcher(Context context, Handler handler, String action, + @Nullable BinderRunner onBind, @Nullable Runnable onUnbind, + @BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) { mContext = context; - mTag = logTag; - mAction = action; + mHandler = FgThread.getHandler(); + mIntent = new Intent(Objects.requireNonNull(action)); - boolean enableOverlay = resources.getBoolean(overlaySwitchResId); - if (enableOverlay) { - String[] pkgs = resources.getStringArray(initialPackageNamesResId); - mServicePackageName = null; - mSignatureSets = getSignatureSets(context, pkgs); - if (D) Log.d(mTag, "Overlay enabled, packages=" + Arrays.toString(pkgs)); - } else { - mServicePackageName = resources.getString(defaultServicePackageNameResId); - mSignatureSets = getSignatureSets(context, mServicePackageName); - if (D) Log.d(mTag, "Overlay disabled, default package=" + mServicePackageName); + Resources resources = context.getResources(); + boolean enableOverlay = resources.getBoolean(enableOverlayResId); + if (!enableOverlay) { + mIntent.setPackage(resources.getString(nonOverlayPackageResId)); } - mHandler = handler; + mOnBind = onBind; + mOnUnbind = onUnbind; - mBestComponent = null; - mBestVersion = Integer.MIN_VALUE; - mBestUserId = UserHandle.USER_NULL; + mCurrentUserId = UserHandle.USER_NULL; - mBestService = null; + mServiceInfo = ServiceInfo.NONE; + mBinder = null; } - protected void onBind() {} - - protected void onUnbind() {} - /** - * Start this watcher, including binding to the current best match and - * re-binding to any better matches down the road. - *

- * Note that if there are no matching encryption-aware services, we may not - * bind to a real service until after the current user is unlocked. - * - * @return {@code true} if a potential service implementation was found. + * Register this class, which will start the process of determining the best matching service + * and maintaining a binding to it. Will return false and fail if there are no possible matching + * services at the time this functions is called. */ - public final boolean start() { - // if we have to return false, do it before registering anything - if (isServiceMissing()) return false; - - // listen for relevant package changes if service overlay is enabled on handler - if (mServicePackageName == null) { - new PackageMonitor() { - @Override - public void onPackageUpdateFinished(String packageName, int uid) { - bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); - } - - @Override - public void onPackageAdded(String packageName, int uid) { - bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); - } - - @Override - public void onPackageRemoved(String packageName, int uid) { - bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); - } - - @Override - public boolean onPackageChanged(String packageName, int uid, String[] components) { - bindBestPackage(Objects.equals(packageName, getCurrentPackageName())); - return super.onPackageChanged(packageName, uid, components); - } - }.register(mContext, UserHandle.ALL, true, mHandler); + public boolean register() { + if (mContext.getPackageManager().queryIntentServicesAsUser(mIntent, + MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE | MATCH_SYSTEM_ONLY, + UserHandle.USER_SYSTEM).isEmpty()) { + return false; } - // listen for user change on handler + new PackageMonitor() { + @Override + public void onPackageUpdateFinished(String packageName, int uid) { + ServiceWatcher.this.onPackageChanged(packageName); + } + + @Override + public void onPackageAdded(String packageName, int uid) { + ServiceWatcher.this.onPackageChanged(packageName); + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + ServiceWatcher.this.onPackageChanged(packageName); + } + + @Override + public boolean onPackageChanged(String packageName, int uid, String[] components) { + ServiceWatcher.this.onPackageChanged(packageName); + return super.onPackageChanged(packageName, uid, components); + } + }.register(mContext, UserHandle.ALL, true, mHandler); + IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_SWITCHED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, - UserHandle.USER_NULL); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - mCurrentUserId = userId; - bindBestPackage(false); - } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) { - if (userId == mCurrentUserId) { - bindBestPackage(false); - } + String action = intent.getAction(); + if (action == null) { + return; } + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + if (userId == UserHandle.USER_NULL) { + return; + } + + switch (action) { + case Intent.ACTION_USER_SWITCHED: + onUserSwitched(userId); + break; + case Intent.ACTION_USER_UNLOCKED: + onUserUnlocked(userId); + break; + default: + break; + } + } }, UserHandle.ALL, intentFilter, null, mHandler); mCurrentUserId = ActivityManager.getCurrentUser(); - mHandler.post(() -> bindBestPackage(false)); + mHandler.post(() -> onBestServiceChanged(false)); return true; } - /** Returns the name of the currently connected package or null. */ - @Nullable - public String getCurrentPackageName() { - ComponentName bestComponent = mBestComponent; - return bestComponent == null ? null : bestComponent.getPackageName(); + /** + * Returns information on the currently selected service. + */ + public ServiceInfo getBoundService() { + return mServiceInfo; } - private boolean isServiceMissing() { - return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction), - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - UserHandle.USER_SYSTEM).isEmpty(); - } - - private void bindBestPackage(boolean forceRebind) { + private void onBestServiceChanged(boolean forceRebind) { Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); - Intent intent = new Intent(mAction); - if (mServicePackageName != null) { - intent.setPackage(mServicePackageName); - } - - List rInfos = mContext.getPackageManager().queryIntentServicesAsUser(intent, - PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AUTO, + List resolveInfos = mContext.getPackageManager().queryIntentServicesAsUser( + mIntent, + GET_META_DATA | MATCH_DIRECT_BOOT_AUTO | MATCH_SYSTEM_ONLY, mCurrentUserId); - if (rInfos == null) { - rInfos = Collections.emptyList(); - } - ComponentName bestComponent = null; - int bestVersion = Integer.MIN_VALUE; - boolean bestIsMultiuser = false; - - for (ResolveInfo rInfo : rInfos) { - ComponentName component = rInfo.serviceInfo.getComponentName(); - String packageName = component.getPackageName(); - - // check signature - try { - PackageInfo pInfo = mContext.getPackageManager().getPackageInfo(packageName, - PackageManager.GET_SIGNATURES - | PackageManager.MATCH_DIRECT_BOOT_AUTO); - if (!isSignatureMatch(pInfo.signatures, mSignatureSets)) { - Log.w(mTag, packageName + " resolves service " + mAction - + ", but has wrong signature, ignoring"); - continue; - } - } catch (NameNotFoundException e) { - Log.wtf(mTag, e); - continue; - } - - // check metadata - Bundle metadata = rInfo.serviceInfo.metaData; - int version = Integer.MIN_VALUE; - boolean isMultiuser = false; - if (metadata != null) { - version = metadata.getInt(EXTRA_SERVICE_VERSION, Integer.MIN_VALUE); - isMultiuser = metadata.getBoolean(EXTRA_SERVICE_IS_MULTIUSER, false); - } - - if (version > bestVersion) { - bestComponent = component; - bestVersion = version; - bestIsMultiuser = isMultiuser; + ServiceInfo bestServiceInfo = ServiceInfo.NONE; + for (ResolveInfo resolveInfo : resolveInfos) { + ServiceInfo serviceInfo = new ServiceInfo(resolveInfo, mCurrentUserId); + if (serviceInfo.compareTo(bestServiceInfo) > 0) { + bestServiceInfo = serviceInfo; } } - if (D) { - Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction, - (mServicePackageName == null ? "" - : "(" + mServicePackageName + ") "), rInfos.size(), - (bestComponent == null ? "no new best component" - : "new best component: " + bestComponent))); + if (forceRebind || !bestServiceInfo.equals(mServiceInfo)) { + rebind(bestServiceInfo); + } + } + + private void rebind(ServiceInfo newServiceInfo) { + Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); + + if (!mServiceInfo.equals(ServiceInfo.NONE)) { + if (D) { + Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mServiceInfo); + } + + mContext.unbindService(this); + mServiceInfo = ServiceInfo.NONE; } - if (bestComponent == null) { - Slog.w(mTag, "Odd, no component found for service " + mAction); - unbind(); + mServiceInfo = newServiceInfo; + if (mServiceInfo.equals(ServiceInfo.NONE)) { return; } - int userId = bestIsMultiuser ? UserHandle.USER_SYSTEM : mCurrentUserId; - boolean alreadyBound = Objects.equals(bestComponent, mBestComponent) - && bestVersion == mBestVersion && userId == mBestUserId; - if (forceRebind || !alreadyBound) { - unbind(); - bind(bestComponent, bestVersion, userId); + Preconditions.checkState(mServiceInfo.component != null); + + if (D) { + Log.i(TAG, getLogPrefix() + " binding to " + mServiceInfo); + } + + Intent bindIntent = new Intent(mIntent).setComponent(mServiceInfo.component); + mContext.bindServiceAsUser(bindIntent, this, + BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_NOT_VISIBLE, + mHandler, UserHandle.of(mServiceInfo.userId)); + } + + @Override + public final void onServiceConnected(ComponentName component, IBinder binder) { + Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); + + if (D) { + Log.i(TAG, getLogPrefix() + " connected to " + component); + } + + mBinder = binder; + if (mOnBind != null) { + runOnBinder(mOnBind); } } - private void bind(ComponentName component, int version, int userId) { + @Override + public final void onServiceDisconnected(ComponentName component) { Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); - Intent intent = new Intent(mAction); - intent.setComponent(component); - - mBestComponent = component; - mBestVersion = version; - mBestUserId = userId; - - if (D) Log.d(mTag, "binding " + component + " (v" + version + ") (u" + userId + ")"); - mContext.bindServiceAsUser(intent, this, - Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE, - UserHandle.of(userId)); - } - - private void unbind() { - Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); - - if (mBestComponent != null) { - if (D) Log.d(mTag, "unbinding " + mBestComponent); - mContext.unbindService(this); + if (D) { + Log.i(TAG, getLogPrefix() + " disconnected from " + component); } - mBestComponent = null; - mBestVersion = Integer.MIN_VALUE; - mBestUserId = UserHandle.USER_NULL; + mBinder = null; + if (mOnUnbind != null) { + mOnUnbind.run(); + } + } + + private void onUserSwitched(@UserIdInt int userId) { + mCurrentUserId = userId; + onBestServiceChanged(false); + } + + private void onUserUnlocked(@UserIdInt int userId) { + if (userId == mCurrentUserId) { + onBestServiceChanged(false); + } + } + + private void onPackageChanged(String packageName) { + // force a rebind if the changed package was the currently connected package + String currentPackageName = + mServiceInfo.component != null ? mServiceInfo.component.getPackageName() : null; + onBestServiceChanged(packageName.equals(currentPackageName)); } /** @@ -365,26 +388,26 @@ public class ServiceWatcher implements ServiceConnection { */ public final void runOnBinder(BinderRunner runner) { runOnHandler(() -> { - if (mBestService == null) { + if (mBinder == null) { return; } try { - runner.run(mBestService); - } catch (RuntimeException e) { - // the code being run is privileged, but may be outside the system server, and thus - // we cannot allow runtime exceptions to crash the system server - Log.e(TAG, "exception while while running " + runner + " on " + mBestService - + " from " + this, e); - } catch (RemoteException e) { - // do nothing + runner.run(mBinder); + } catch (RuntimeException | RemoteException e) { + // binders may propagate some specific non-RemoteExceptions from the other side + // through the binder as well - we cannot allow those to crash the system server + Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e); } }); } /** * Runs the given function synchronously if currently connected, and returns the default value - * if not currently connected or if any exception is thrown. + * if not currently connected or if any exception is thrown. Do not obtain any locks within the + * BlockingBinderRunner, or risk deadlock. The default value will be returned if there is no + * service connection when this is run, if a RemoteException occurs, or if the operation times + * out. * * @deprecated Using this function is an indication that your AIDL API is broken. Calls from * system server to outside MUST be one-way, and so cannot return any result, and this @@ -395,13 +418,16 @@ public class ServiceWatcher implements ServiceConnection { public final T runOnBinderBlocking(BlockingBinderRunner runner, T defaultValue) { try { return runOnHandlerBlocking(() -> { - if (mBestService == null) { + if (mBinder == null) { return defaultValue; } try { - return runner.run(mBestService); - } catch (RemoteException e) { + return runner.run(mBinder); + } catch (RuntimeException | RemoteException e) { + // binders may propagate some specific non-RemoteExceptions from the other side + // through the binder as well - we cannot allow those to crash the system server + Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e); return defaultValue; } }); @@ -410,30 +436,6 @@ public class ServiceWatcher implements ServiceConnection { } } - @Override - public final void onServiceConnected(ComponentName component, IBinder binder) { - runOnHandler(() -> { - if (D) Log.d(mTag, component + " connected"); - mBestService = binder; - onBind(); - }); - } - - @Override - public final void onServiceDisconnected(ComponentName component) { - runOnHandler(() -> { - if (D) Log.d(mTag, component + " disconnected"); - mBestService = null; - onUnbind(); - }); - } - - @Override - public String toString() { - ComponentName bestComponent = mBestComponent; - return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion; - } - private void runOnHandler(Runnable r) { if (Looper.myLooper() == mHandler.getLooper()) { r.run(); @@ -467,4 +469,8 @@ public class ServiceWatcher implements ServiceConnection { } } } + + private String getLogPrefix() { + return "[" + mIntent.getAction() + "]"; + } } diff --git a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java b/services/core/java/com/android/server/location/ActivityRecognitionProxy.java deleted file mode 100644 index 80ab7903cef72..0000000000000 --- a/services/core/java/com/android/server/location/ActivityRecognitionProxy.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.location; - -import android.content.Context; -import android.hardware.location.ActivityRecognitionHardware; -import android.hardware.location.IActivityRecognitionHardwareClient; -import android.hardware.location.IActivityRecognitionHardwareWatcher; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; - -import com.android.server.FgThread; -import com.android.server.ServiceWatcher; - -/** - * Proxy class to bind GmsCore to the ActivityRecognitionHardware. - * - * @hide - */ -public class ActivityRecognitionProxy { - - private static final String TAG = "ActivityRecognitionProxy"; - - /** - * Creates an instance of the proxy and binds it to the appropriate FusedProvider. - * - * @return An instance of the proxy if it could be bound, null otherwise. - */ - public static ActivityRecognitionProxy createAndBind( - Context context, - boolean activityRecognitionHardwareIsSupported, - ActivityRecognitionHardware activityRecognitionHardware, - int overlaySwitchResId, - int defaultServicePackageNameResId, - int initialPackageNameResId) { - ActivityRecognitionProxy activityRecognitionProxy = new ActivityRecognitionProxy( - context, - activityRecognitionHardwareIsSupported, - activityRecognitionHardware, - overlaySwitchResId, - defaultServicePackageNameResId, - initialPackageNameResId); - - if (activityRecognitionProxy.mServiceWatcher.start()) { - return activityRecognitionProxy; - } else { - return null; - } - } - - private final ServiceWatcher mServiceWatcher; - private final boolean mIsSupported; - private final ActivityRecognitionHardware mInstance; - - private ActivityRecognitionProxy( - Context context, - boolean activityRecognitionHardwareIsSupported, - ActivityRecognitionHardware activityRecognitionHardware, - int overlaySwitchResId, - int defaultServicePackageNameResId, - int initialPackageNameResId) { - mIsSupported = activityRecognitionHardwareIsSupported; - mInstance = activityRecognitionHardware; - - mServiceWatcher = new ServiceWatcher( - context, - TAG, - "com.android.location.service.ActivityRecognitionProvider", - overlaySwitchResId, - defaultServicePackageNameResId, - initialPackageNameResId, - FgThread.getHandler()) { - @Override - protected void onBind() { - runOnBinder(ActivityRecognitionProxy.this::initializeService); - } - }; - } - - private void initializeService(IBinder binder) { - try { - String descriptor = binder.getInterfaceDescriptor(); - - if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals( - descriptor)) { - IActivityRecognitionHardwareWatcher watcher = - IActivityRecognitionHardwareWatcher.Stub.asInterface(binder); - if (mInstance != null) { - watcher.onInstanceChanged(mInstance); - } - } else if (IActivityRecognitionHardwareClient.class.getCanonicalName() - .equals(descriptor)) { - IActivityRecognitionHardwareClient client = - IActivityRecognitionHardwareClient.Stub.asInterface(binder); - client.onAvailabilityChanged(mIsSupported, mInstance); - } else { - Log.e(TAG, "Invalid descriptor found on connection: " + descriptor); - } - } catch (RemoteException e) { - Log.w(TAG, e); - } - } -} diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java index e6f0ed9d14b06..536f95a40431b 100644 --- a/services/core/java/com/android/server/location/GeocoderProxy.java +++ b/services/core/java/com/android/server/location/GeocoderProxy.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.annotation.Nullable; import android.content.Context; import android.location.Address; import android.location.GeocoderParams; @@ -28,40 +29,38 @@ import java.util.List; /** * Proxy for IGeocodeProvider implementations. + * + * @hide */ public class GeocoderProxy { - private static final String TAG = "GeocoderProxy"; private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider"; - private final ServiceWatcher mServiceWatcher; - - public static GeocoderProxy createAndBind(Context context, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId) { - GeocoderProxy proxy = new GeocoderProxy(context, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId); - if (proxy.bind()) { + /** + * Creates and registers this proxy. If no suitable service is available for the proxy, returns + * null. + */ + @Nullable + public static GeocoderProxy createAndRegister(Context context) { + GeocoderProxy proxy = new GeocoderProxy(context); + if (proxy.register()) { return proxy; } else { return null; } } - private GeocoderProxy(Context context, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId) { - mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, - BackgroundThread.getHandler()); + private final ServiceWatcher mServiceWatcher; + + private GeocoderProxy(Context context) { + mServiceWatcher = new ServiceWatcher(context, BackgroundThread.getHandler(), SERVICE_ACTION, + null, null, + com.android.internal.R.bool.config_enableGeocoderOverlay, + com.android.internal.R.string.config_geocoderProviderPackageName); } - private boolean bind() { - return mServiceWatcher.start(); - } - - public String getConnectedPackageName() { - return mServiceWatcher.getCurrentPackageName(); + private boolean register() { + return mServiceWatcher.register(); } public String getFromLocation(double latitude, double longitude, int maxResults, @@ -83,5 +82,4 @@ public class GeocoderProxy { maxResults, params, addrs); }, "Service not Available"); } - } diff --git a/services/core/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java index ce93661a8810c..f006fb177382c 100644 --- a/services/core/java/com/android/server/location/GeofenceProxy.java +++ b/services/core/java/com/android/server/location/GeofenceProxy.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.ServiceConnection; import android.hardware.location.GeofenceHardwareService; import android.hardware.location.IGeofenceHardware; -import android.location.IFusedGeofenceHardware; import android.location.IGeofenceProvider; import android.location.IGpsGeofenceHardware; import android.os.IBinder; @@ -33,6 +32,8 @@ import android.util.Log; import com.android.server.FgThread; import com.android.server.ServiceWatcher; +import java.util.Objects; + /** * @hide */ @@ -41,64 +42,41 @@ public final class GeofenceProxy { private static final String TAG = "GeofenceProxy"; private static final String SERVICE_ACTION = "com.android.location.service.GeofenceProvider"; - private final Context mContext; - private final ServiceWatcher mServiceWatcher; - @Nullable - private final IGpsGeofenceHardware mGpsGeofenceHardware; - @Nullable - private final IFusedGeofenceHardware mFusedGeofenceHardware; - - private volatile IGeofenceHardware mGeofenceHardware; - - private final ServiceWatcher.BinderRunner mUpdateGeofenceHardware = (binder) -> { - IGeofenceProvider provider = IGeofenceProvider.Stub.asInterface(binder); - try { - provider.setGeofenceHardware(mGeofenceHardware); - } catch (RemoteException e) { - Log.w(TAG, e); - } - }; - - public static GeofenceProxy createAndBind(Context context, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence, - @Nullable IFusedGeofenceHardware fusedGeofenceHardware) { - GeofenceProxy proxy = new GeofenceProxy(context, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, gpsGeofence, - fusedGeofenceHardware); - - if (proxy.bind()) { + public static GeofenceProxy createAndBind(Context context, IGpsGeofenceHardware gpsGeofence) { + GeofenceProxy proxy = new GeofenceProxy(context, gpsGeofence); + if (proxy.register(context)) { return proxy; } else { return null; } } - private GeofenceProxy(Context context, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId, @Nullable IGpsGeofenceHardware gpsGeofence, - @Nullable IFusedGeofenceHardware fusedGeofenceHardware) { - mContext = context; - mServiceWatcher = new ServiceWatcher(context, TAG, SERVICE_ACTION, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, - FgThread.getHandler()) { - @Override - protected void onBind() { - runOnBinder(mUpdateGeofenceHardware); - } - }; + private final IGpsGeofenceHardware mGpsGeofenceHardware; + private final ServiceWatcher mServiceWatcher; - mGpsGeofenceHardware = gpsGeofence; - mFusedGeofenceHardware = fusedGeofenceHardware; + private volatile IGeofenceHardware mGeofenceHardware; + + private GeofenceProxy(Context context, IGpsGeofenceHardware gpsGeofence) { + mGpsGeofenceHardware = Objects.requireNonNull(gpsGeofence); + mServiceWatcher = new ServiceWatcher(context, FgThread.getHandler(), SERVICE_ACTION, + this::updateGeofenceHardware, null, + com.android.internal.R.bool.config_enableGeofenceOverlay, + com.android.internal.R.string.config_geofenceProviderPackageName); mGeofenceHardware = null; } - private boolean bind() { - if (mServiceWatcher.start()) { - mContext.bindServiceAsUser(new Intent(mContext, GeofenceHardwareService.class), - new GeofenceProxyServiceConnection(), Context.BIND_AUTO_CREATE, + private void updateGeofenceHardware(IBinder binder) throws RemoteException { + IGeofenceProvider.Stub.asInterface(binder).setGeofenceHardware(mGeofenceHardware); + } + + private boolean register(Context context) { + if (mServiceWatcher.register()) { + context.bindServiceAsUser( + new Intent(context, GeofenceHardwareService.class), + new GeofenceProxyServiceConnection(), + Context.BIND_AUTO_CREATE, UserHandle.SYSTEM); return true; } @@ -113,24 +91,18 @@ public final class GeofenceProxy { IGeofenceHardware geofenceHardware = IGeofenceHardware.Stub.asInterface(service); try { - if (mGpsGeofenceHardware != null) { - geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware); - } - if (mFusedGeofenceHardware != null) { - geofenceHardware.setFusedGeofenceHardware(mFusedGeofenceHardware); - } - + geofenceHardware.setGpsGeofenceHardware(mGpsGeofenceHardware); mGeofenceHardware = geofenceHardware; - mServiceWatcher.runOnBinder(mUpdateGeofenceHardware); - } catch (Exception e) { - Log.w(TAG, e); + mServiceWatcher.runOnBinder(GeofenceProxy.this::updateGeofenceHardware); + } catch (RemoteException e) { + Log.w(TAG, "unable to initialize geofence hardware", e); } } @Override public void onServiceDisconnected(ComponentName name) { mGeofenceHardware = null; - mServiceWatcher.runOnBinder(mUpdateGeofenceHardware); + mServiceWatcher.runOnBinder(GeofenceProxy.this::updateGeofenceHardware); } } } diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java new file mode 100644 index 0000000000000..9d9852ba5da3a --- /dev/null +++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.location; + +import android.annotation.Nullable; +import android.content.Context; +import android.hardware.location.ActivityRecognitionHardware; +import android.hardware.location.IActivityRecognitionHardwareClient; +import android.hardware.location.IActivityRecognitionHardwareWatcher; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.server.FgThread; +import com.android.server.ServiceWatcher; + +/** + * Proxy class to bind GmsCore to the ActivityRecognitionHardware. + * + * @hide + */ +public class HardwareActivityRecognitionProxy { + + private static final String TAG = "ARProxy"; + private static final String SERVICE_ACTION = + "com.android.location.service.ActivityRecognitionProvider"; + + /** + * Creates and registers this proxy. If no suitable service is available for the proxy, returns + * null. + */ + @Nullable + public static HardwareActivityRecognitionProxy createAndRegister(Context context) { + HardwareActivityRecognitionProxy arProxy = new HardwareActivityRecognitionProxy(context); + if (arProxy.register()) { + return arProxy; + } else { + return null; + } + } + + private final boolean mIsSupported; + private final ActivityRecognitionHardware mInstance; + + private final ServiceWatcher mServiceWatcher; + + private HardwareActivityRecognitionProxy(Context context) { + mIsSupported = ActivityRecognitionHardware.isSupported(); + if (mIsSupported) { + mInstance = ActivityRecognitionHardware.getInstance(context); + } else { + mInstance = null; + } + + mServiceWatcher = new ServiceWatcher(context, + FgThread.getHandler(), + SERVICE_ACTION, + this::onBind, + null, + com.android.internal.R.bool.config_enableActivityRecognitionHardwareOverlay, + com.android.internal.R.string.config_activityRecognitionHardwarePackageName); + } + + private boolean register() { + return mServiceWatcher.register(); + } + + private void onBind(IBinder binder) throws RemoteException { + String descriptor = binder.getInterfaceDescriptor(); + + if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) { + IActivityRecognitionHardwareWatcher watcher = + IActivityRecognitionHardwareWatcher.Stub.asInterface(binder); + if (mInstance != null) { + watcher.onInstanceChanged(mInstance); + } + } else if (IActivityRecognitionHardwareClient.class.getCanonicalName().equals(descriptor)) { + IActivityRecognitionHardwareClient client = + IActivityRecognitionHardwareClient.Stub.asInterface(binder); + client.onAvailabilityChanged(mIsSupported, mInstance); + } else { + Log.e(TAG, "Unknown descriptor: " + descriptor); + } + } +} diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 8a149afa62383..805b018a8f45f 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -19,12 +19,11 @@ package com.android.server.location; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import android.annotation.Nullable; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.location.Location; import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerExecutor; import android.os.IBinder; import android.os.RemoteException; import android.util.ArraySet; @@ -35,7 +34,6 @@ import com.android.internal.location.ILocationProviderManager; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.server.FgThread; -import com.android.server.LocationManagerService; import com.android.server.ServiceWatcher; import java.io.FileDescriptor; @@ -49,17 +47,31 @@ import java.util.List; public class LocationProviderProxy extends AbstractLocationProvider { private static final String TAG = "LocationProviderProxy"; - private static final boolean D = LocationManagerService.D; private static final int MAX_ADDITIONAL_PACKAGES = 2; + /** + * Creates and registers this proxy. If no suitable service is available for the proxy, returns + * null. + */ + @Nullable + public static LocationProviderProxy createAndRegister(Context context, String action, + int enableOverlayResId, int nonOverlayPackageResId) { + LocationProviderProxy proxy = new LocationProviderProxy(context, action, enableOverlayResId, + nonOverlayPackageResId); + if (proxy.register()) { + return proxy; + } else { + return null; + } + } + private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() { // executed on binder thread @Override public void onSetAdditionalProviderPackages(List packageNames) { - int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size()) + 1; + int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size()); ArraySet allPackages = new ArraySet<>(maxCount); - allPackages.add(mServiceWatcher.getCurrentPackageName()); for (String packageName : packageNames) { if (packageNames.size() >= maxCount) { return; @@ -74,6 +86,12 @@ public class LocationProviderProxy extends AbstractLocationProvider { } } + // add the binder package + ComponentName service = mServiceWatcher.getBoundService().component; + if (service != null) { + allPackages.add(service.getPackageName()); + } + setPackageNames(allPackages); } @@ -100,63 +118,39 @@ public class LocationProviderProxy extends AbstractLocationProvider { @Nullable private ProviderRequest mRequest; - /** - * Creates a new LocationProviderProxy and immediately begins binding to the best applicable - * service. - */ - @Nullable - public static LocationProviderProxy createAndBind(Context context, String action, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId) { - LocationProviderProxy proxy = new LocationProviderProxy(context, FgThread.getHandler(), - action, overlaySwitchResId, defaultServicePackageNameResId, - initialPackageNamesResId); - if (proxy.bind()) { - return proxy; - } else { - return null; - } - } + private LocationProviderProxy(Context context, String action, int enableOverlayResId, + int nonOverlayPackageResId) { + super(context, FgThread.getExecutor()); - private LocationProviderProxy(Context context, Handler handler, String action, - int overlaySwitchResId, int defaultServicePackageNameResId, - int initialPackageNamesResId) { - super(context, new HandlerExecutor(handler), Collections.emptySet()); - - mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId, - defaultServicePackageNameResId, initialPackageNamesResId, handler) { - - @Override - protected void onBind() { - runOnBinder(LocationProviderProxy.this::initializeService); - } - - @Override - protected void onUnbind() { - setState(State.EMPTY_STATE); - } - }; + mServiceWatcher = new ServiceWatcher(context, FgThread.getHandler(), action, this::onBind, + this::onUnbind, enableOverlayResId, nonOverlayPackageResId); mRequest = null; } - private boolean bind() { - return mServiceWatcher.start(); + private boolean register() { + return mServiceWatcher.register(); } - private void initializeService(IBinder binder) throws RemoteException { - ILocationProvider service = ILocationProvider.Stub.asInterface(binder); - if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher); + private void onBind(IBinder binder) throws RemoteException { + ILocationProvider provider = ILocationProvider.Stub.asInterface(binder); - setPackageNames(Collections.singleton(mServiceWatcher.getCurrentPackageName())); + ComponentName service = mServiceWatcher.getBoundService().component; + if (service != null) { + setPackageNames(Collections.singleton(service.getPackageName())); + } - service.setLocationProviderManager(mManager); + provider.setLocationProviderManager(mManager); if (mRequest != null) { - service.setRequest(mRequest, mRequest.workSource); + provider.setRequest(mRequest, mRequest.workSource); } } + private void onUnbind() { + setState(State.EMPTY_STATE); + } + @Override public void onSetRequest(ProviderRequest request) { mServiceWatcher.runOnBinder(binder -> {