diff options
author | 2025-03-19 17:26:05 -0700 | |
---|---|---|
committer | 2025-03-19 17:26:05 -0700 | |
commit | d872ad7f84c0d5af72e709f2e3f7913a785c9cae (patch) | |
tree | 8db6797045b32b61e9c5f5f57459509516d6d90b | |
parent | 4bae066de0e2249d74022e90eed3e33dd78171a3 (diff) | |
parent | fca4bcdd90f2bb276dd9869e99c3912546b37887 (diff) |
Merge changes I11204b07,I8ad3fb6f into main
* changes:
Add missing attribution tags to com.android.location.fused
Add an unstable fallback for the gnss/fused location provider overlay
13 files changed, 228 insertions, 9 deletions
diff --git a/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java b/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java index e8aeb8653d06..d8093c4b1f1c 100644 --- a/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java +++ b/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java @@ -233,6 +233,7 @@ public final class CurrentUserServiceSupplier extends BroadcastReceiver implemen private final boolean mMatchSystemAppsOnly; private volatile ServiceChangedListener mListener; + private @Nullable String mUnstableService; private CurrentUserServiceSupplier(Context context, String action, @Nullable String explicitPackage, @Nullable String callerPermission, @@ -330,6 +331,20 @@ public final class CurrentUserServiceSupplier extends BroadcastReceiver implemen } } + // Prefer any service over the unstable service. + if (mUnstableService != null && serviceInfo != null && bestServiceInfo != null) { + if (mUnstableService.equals(serviceInfo.toString())) { + Log.d(TAG, "Not choosing unstable service " + mUnstableService + + " as we already have a service " + bestServiceInfo.toString()); + continue; + } else if (mUnstableService.equals(bestServiceInfo.toString())) { + Log.d(TAG, "Choosing service " + serviceInfo.toString() + + " over the unstable service " + mUnstableService); + bestServiceInfo = serviceInfo; + continue; + } + } + if (sBoundServiceInfoComparator.compare(serviceInfo, bestServiceInfo) > 0) { bestServiceInfo = serviceInfo; } @@ -338,6 +353,17 @@ public final class CurrentUserServiceSupplier extends BroadcastReceiver implemen return bestServiceInfo; } + /** + * Alerts the supplier that the given service is unstable. + * + * The service marked as unstable will be unpreferred over any other services, + * which will last until the next device restart. + */ + @Override + public void alertUnstableService(String unstableService) { + mUnstableService = unstableService; + } + @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); diff --git a/core/java/com/android/server/servicewatcher/ServiceWatcher.java b/core/java/com/android/server/servicewatcher/ServiceWatcher.java index 38872c996596..12dad359dd92 100644 --- a/core/java/com/android/server/servicewatcher/ServiceWatcher.java +++ b/core/java/com/android/server/servicewatcher/ServiceWatcher.java @@ -140,6 +140,11 @@ public interface ServiceWatcher { * null if no service currently meets the criteria. Only invoked while registered. */ @Nullable TBoundServiceInfo getServiceInfo(); + + /** + * Alerts the supplier that the given service is unstable. + */ + void alertUnstableService(String unstableService); } /** @@ -230,6 +235,19 @@ public interface ServiceWatcher { } /** + * Creates a new ServiceWatcher instance. + */ + static <TBoundServiceInfo extends BoundServiceInfo> ServiceWatcher create( + Context context, + String tag, + boolean unstableFallbackEnabled, + ServiceSupplier<TBoundServiceInfo> serviceSupplier, + @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener) { + return create(context, FgThread.getHandler(), tag, unstableFallbackEnabled, + serviceSupplier, serviceListener); + } + + /** * Creates a new ServiceWatcher instance that runs on the given handler. */ static <TBoundServiceInfo extends BoundServiceInfo> ServiceWatcher create( @@ -242,6 +260,20 @@ public interface ServiceWatcher { } /** + * Creates a new ServiceWatcher instance that runs on the given handler. + */ + static <TBoundServiceInfo extends BoundServiceInfo> ServiceWatcher create( + Context context, + Handler handler, + String tag, + boolean unstableFallbackEnabled, + ServiceSupplier<TBoundServiceInfo> serviceSupplier, + @Nullable ServiceListener<? super TBoundServiceInfo> serviceListener) { + return new ServiceWatcherImpl<>(context, handler, tag, unstableFallbackEnabled, + serviceSupplier, serviceListener); + } + + /** * Returns true if there is at least one service that the ServiceWatcher could hypothetically * bind to, as selected by the {@link ServiceSupplier}. */ diff --git a/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java b/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java index ccbab9fdba12..30d8710a3f12 100644 --- a/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java +++ b/core/java/com/android/server/servicewatcher/ServiceWatcherImpl.java @@ -21,11 +21,13 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.location.flags.Flags; import android.os.DeadObjectException; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.os.SystemClock; import android.os.UserHandle; import android.util.Log; @@ -52,12 +54,22 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements static final boolean D = Log.isLoggable(TAG, Log.DEBUG); static final long RETRY_DELAY_MS = 15 * 1000; + /* Used for the unstable fallback logic, it is the time period in milliseconds where the number + * of disconnections is tracked in order to determine if the service is unstable. */ + private static final long UNSTABLE_TIME_PERIOD_MS = 60 * 1000; + /* Used for the unstable fallback logic, it is the number of disconnections within the time + * period that will mark the service as unstable and allow the fallback to a stable service. */ + private static final int DISCONNECTED_COUNT_BEFORE_MARKED_AS_UNSTABLE = 10; final Context mContext; final Handler mHandler; final String mTag; final ServiceSupplier<TBoundServiceInfo> mServiceSupplier; final @Nullable ServiceListener<? super TBoundServiceInfo> mServiceListener; + private boolean mUnstableFallbackEnabled; + private @Nullable String mDisconnectedService; + private long mDisconnectedStartTime; + private int mDisconnectedCount; private final PackageMonitor mPackageMonitor = new PackageMonitor() { @Override @@ -86,6 +98,20 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements mServiceListener = serviceListener; } + ServiceWatcherImpl(Context context, Handler handler, String tag, + boolean unstableFallbackEnabled, + ServiceSupplier<TBoundServiceInfo> serviceSupplier, + ServiceListener<? super TBoundServiceInfo> serviceListener) { + mContext = context; + mHandler = handler; + mTag = tag; + if (Flags.serviceWatcherUnstableFallback()) { + mUnstableFallbackEnabled = unstableFallbackEnabled; + } + mServiceSupplier = serviceSupplier; + mServiceListener = serviceListener; + } + @Override public boolean checkServiceResolves() { return mServiceSupplier.hasMatchingService(); @@ -178,6 +204,7 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements // volatile so that isConnected can be called from any thread easily private volatile @Nullable IBinder mBinder; private @Nullable Runnable mRebinder; + private boolean mForcingRebind; MyServiceConnection(@Nullable TBoundServiceInfo boundServiceInfo) { mBoundServiceInfo = boundServiceInfo; @@ -269,6 +296,11 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements Log.i(TAG, "[" + mTag + "] connected to " + component.toShortString()); mBinder = binder; + /* Used to keep track of whether we are forcing a rebind, so that we don't force a + * rebind while in the process of already forcing a rebind. This is needed because + * onServiceDisconnected and onBindingDied can happen in quick succession and we only + * want one rebind to happen in this case. */ + mForcingRebind = false; if (mServiceListener != null) { try { @@ -295,6 +327,44 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements if (mServiceListener != null) { mServiceListener.onUnbind(); } + + // If unstable fallback is not enabled or no current service is bound, then avoid the + // unstable fallback logic below and return early. + if (!mUnstableFallbackEnabled + || mBoundServiceInfo == null + || mBoundServiceInfo.toString() == null) { + return; + } + + String currentService = mBoundServiceInfo.toString(); + // If the service has already disconnected within the time period, increment the count. + // Otherwise, set the service as disconnected, set the start time, and reset the count. + if (Objects.equals(mDisconnectedService, currentService) + && mDisconnectedStartTime > 0 + && (SystemClock.elapsedRealtime() - mDisconnectedStartTime + <= UNSTABLE_TIME_PERIOD_MS)) { + mDisconnectedCount++; + } else { + mDisconnectedService = currentService; + mDisconnectedStartTime = SystemClock.elapsedRealtime(); + mDisconnectedCount = 1; + } + Log.d(TAG, "[" + mTag + "] Service disconnected : " + currentService + " Count = " + + mDisconnectedCount); + if (mDisconnectedCount >= DISCONNECTED_COUNT_BEFORE_MARKED_AS_UNSTABLE) { + Log.i(TAG, "[" + mTag + "] Service disconnected too many times, set as unstable : " + + mDisconnectedService); + // Alert this service as unstable will last until the next device restart. + mServiceSupplier.alertUnstableService(mDisconnectedService); + mDisconnectedService = null; + mDisconnectedStartTime = 0; + mDisconnectedCount = 0; + // Force rebind to allow the possibility of fallback to a stable service. + if (!mForcingRebind) { + mForcingRebind = true; + onServiceChanged(/*forceRebind=*/ true); + } + } } @Override @@ -305,7 +375,10 @@ class ServiceWatcherImpl<TBoundServiceInfo extends BoundServiceInfo> implements // introduce a small delay to prevent spamming binding over and over, since the likely // cause of a binding dying is some package event that may take time to recover from - mHandler.postDelayed(() -> onServiceChanged(true), 500); + if (!mForcingRebind) { + mForcingRebind = true; + mHandler.postDelayed(() -> onServiceChanged(/*forceRebind=*/ true), 500); + } } @Override diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 7bb799a24ef1..828461c66a1f 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2125,14 +2125,27 @@ <!-- Package name providing fused location support. Used only when config_enableFusedLocationOverlay is false. --> <string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string> + <!-- If true, will fallback to use a different app if the chosen overlay app is determined to + be unstable. Used only when config_enableFusedLocationOverlay is true. --> + <bool name="config_fusedLocationOverlayUnstableFallback" translatable="false">false</bool> <!-- If true will use the GNSS hardware implementation to service the GPS_PROVIDER. If false will allow the GPS_PROVIDER to be replaced by an app at run-time (restricted to the package specified by config_gnssLocationProviderPackageName). --> <bool name="config_useGnssHardwareProvider" translatable="false">true</bool> + <!-- Whether to enable gnss location provider overlay which allows gnss location provider to + be replaced by an app at run-time. When disabled, only the + config_gnssLocationProviderPackageName package will be searched for gnss location + provider, otherwise any system package is eligible. Anyone who wants to disable the overlay + mechanism can set it to false. Used only when config_useGnssHardwareProvider is false --> + <bool name="config_enableGnssLocationOverlay" translatable="false">true</bool> <!-- Package name providing GNSS location support. Used only when config_useGnssHardwareProvider is false. --> <string name="config_gnssLocationProviderPackageName" translatable="false">@null</string> + <!-- If true, will fallback to use a different app if the chosen overlay app is determined to + be unstable. Used only when config_useGnssHardwareProvider is false and + config_enableGnssLocationOverlay is true. --> + <bool name="config_gnssLocationOverlayUnstableFallback" translatable="false">false</bool> <!-- Default value for the ADAS GNSS Location Enabled setting if this setting has never been set before. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2dc5687a1253..219ac3f89997 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2050,6 +2050,9 @@ <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" /> <java-symbol type="bool" name="config_defaultAdasGnssLocationEnabled" /> <java-symbol type="bool" name="config_enableFusedLocationOverlay" /> + <java-symbol type="bool" name="config_enableGnssLocationOverlay" /> + <java-symbol type="bool" name="config_fusedLocationOverlayUnstableFallback" /> + <java-symbol type="bool" name="config_gnssLocationOverlayUnstableFallback" /> <java-symbol type="bool" name="config_useGnssHardwareProvider" /> <java-symbol type="bool" name="config_enableGeocoderOverlay" /> <java-symbol type="bool" name="config_enableGeofenceOverlay" /> diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig index f26e72fa79f1..9cc58ae35692 100644 --- a/location/java/android/location/flags/location.aconfig +++ b/location/java/android/location/flags/location.aconfig @@ -205,3 +205,17 @@ flag { bug: "209078566" } +flag { + name: "service_watcher_unstable_fallback" + namespace: "location" + description: "Flag for service watcher to fallback on an unstable service" + bug: "402997842" + is_fixed_read_only: true +} + +flag { + name: "missing_attribution_tags_in_overlay" + namespace: "location" + description: "Adds missing attribution tags in the Fused and Gnss overlay" + bug: "403337028" +} diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml index 158c33ae2035..56fe38905660 100644 --- a/packages/FusedLocation/AndroidManifest.xml +++ b/packages/FusedLocation/AndroidManifest.xml @@ -30,6 +30,9 @@ <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> + <attribution android:tag="FusedOverlayService" android:label="@string/fused_overlay_service"/> + <attribution android:tag="GnssOverlayService" android:label="@string/gnss_overlay_service"/> + <application android:label="@string/app_label" android:process="system" diff --git a/packages/FusedLocation/res/values/strings.xml b/packages/FusedLocation/res/values/strings.xml index 5b78e39d1ba6..25e1fe7677bb 100644 --- a/packages/FusedLocation/res/values/strings.xml +++ b/packages/FusedLocation/res/values/strings.xml @@ -2,4 +2,8 @@ <resources> <!-- Name of the application. [CHAR LIMIT=35] --> <string name="app_label">Fused Location</string> + <!-- Attribution for Fused Overlay Service. [CHAR LIMIT=NONE]--> + <string name="fused_overlay_service">Fused Overlay Service</string> + <!-- Attribution for GNSS Overlay Service. [CHAR LIMIT=NONE]--> + <string name="gnss_overlay_service">GNSS Overlay Service</string> </resources> diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java index a0e008c9437f..78b2f7e52ca5 100644 --- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java +++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java @@ -53,6 +53,7 @@ import java.util.concurrent.atomic.AtomicInteger; public class FusedLocationProvider extends LocationProviderBase { private static final String TAG = "FusedLocationProvider"; + private static final String ATTRIBUTION_TAG = "FusedOverlayService"; private static final ProviderProperties PROPERTIES = new ProviderProperties.Builder() .setHasAltitudeSupport(true) @@ -89,8 +90,12 @@ public class FusedLocationProvider extends LocationProviderBase { public FusedLocationProvider(Context context) { super(context, TAG, PROPERTIES); - mContext = context; - mLocationManager = Objects.requireNonNull(context.getSystemService(LocationManager.class)); + if (Flags.missingAttributionTagsInOverlay()) { + mContext = context.createAttributionContext(ATTRIBUTION_TAG); + } else { + mContext = context; + } + mLocationManager = Objects.requireNonNull(mContext.getSystemService(LocationManager.class)); mGpsListener = new ChildLocationListener(GPS_PROVIDER); mNetworkListener = new ChildLocationListener(NETWORK_PROVIDER); diff --git a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java index c6576e39de99..86bcd99822fc 100644 --- a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java +++ b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java @@ -21,6 +21,7 @@ import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH; import android.annotation.Nullable; import android.content.Context; +import android.location.flags.Flags; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; @@ -41,6 +42,7 @@ import java.util.List; public class GnssOverlayLocationProvider extends LocationProviderBase { private static final String TAG = "GnssOverlay"; + private static final String ATTRIBUTION_TAG = "GnssOverlayService"; private static final ProviderProperties PROPERTIES = new ProviderProperties.Builder() .setHasAltitudeSupport(true) @@ -87,7 +89,13 @@ public class GnssOverlayLocationProvider extends LocationProviderBase { public GnssOverlayLocationProvider(Context context) { super(context, TAG, PROPERTIES); - mLocationManager = context.getSystemService(LocationManager.class); + + if (Flags.missingAttributionTagsInOverlay()) { + Context contextWithAttribution = context.createAttributionContext(ATTRIBUTION_TAG); + mLocationManager = contextWithAttribution.getSystemService(LocationManager.class); + } else { + mLocationManager = context.getSystemService(LocationManager.class); + } } void start() { diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt index ed77e6f5d7ea..b86c23bc3e71 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerServiceSupplier.kt @@ -62,6 +62,10 @@ constructor( userTracker.removeCallback(this) } + override fun alertUnstableService(unstableService: String?) { + // Unused. Do nothing. + } + override fun onBeforeUserSwitching(newUser: Int) { userAboutToSwitch = true listener?.onServiceChanged() diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 6780866d4038..6dff2d8d0a98 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -475,7 +475,8 @@ public class LocationManagerService extends ILocationManager.Stub implements FUSED_PROVIDER, ACTION_FUSED_PROVIDER, com.android.internal.R.bool.config_enableFusedLocationOverlay, - com.android.internal.R.string.config_fusedLocationProviderPackageName); + com.android.internal.R.string.config_fusedLocationProviderPackageName, + com.android.internal.R.bool.config_fusedLocationOverlayUnstableFallback); if (fusedProvider != null) { LocationProviderManager fusedManager = new LocationProviderManager(mContext, mInjector, FUSED_PROVIDER, mPassiveManager); @@ -498,14 +499,13 @@ public class LocationManagerService extends ILocationManager.Stub implements com.android.internal.R.bool.config_useGnssHardwareProvider); AbstractLocationProvider gnssProvider = null; if (!useGnssHardwareProvider) { - // TODO: Create a separate config_enableGnssLocationOverlay config resource - // if we want to selectively enable a GNSS overlay but disable a fused overlay. gnssProvider = ProxyLocationProvider.create( mContext, GPS_PROVIDER, ACTION_GNSS_PROVIDER, - com.android.internal.R.bool.config_enableFusedLocationOverlay, - com.android.internal.R.string.config_gnssLocationProviderPackageName); + com.android.internal.R.bool.config_enableGnssLocationOverlay, + com.android.internal.R.string.config_gnssLocationProviderPackageName, + com.android.internal.R.bool.config_gnssLocationOverlayUnstableFallback); } if (gnssProvider == null) { gnssProvider = mGnssManagerService.getGnssLocationProvider(); diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java index 8fdc22b81769..a52b948dc53f 100644 --- a/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java +++ b/services/core/java/com/android/server/location/provider/proxy/ProxyLocationProvider.java @@ -77,6 +77,22 @@ public class ProxyLocationProvider extends AbstractLocationProvider implements } } + /** + * Creates and registers this proxy. If no suitable service is available for the proxy, returns + * null. + */ + @Nullable + public static ProxyLocationProvider create(Context context, String provider, String action, + int enableOverlayResId, int nonOverlayPackageResId, int unstableOverlayFallbackResId) { + ProxyLocationProvider proxy = new ProxyLocationProvider(context, provider, action, + enableOverlayResId, nonOverlayPackageResId, unstableOverlayFallbackResId); + if (proxy.checkServiceResolves()) { + return proxy; + } else { + return null; + } + } + final Object mLock = new Object(); final Context mContext; @@ -111,6 +127,24 @@ public class ProxyLocationProvider extends AbstractLocationProvider implements mRequest = ProviderRequest.EMPTY_REQUEST; } + private ProxyLocationProvider(Context context, String provider, String action, + int enableOverlayResId, int nonOverlayPackageResId, int unstableOverlayFallbackResId) { + // safe to use direct executor since our locks are not acquired in a code path invoked by + // our owning provider + super(DIRECT_EXECUTOR, null, null, Collections.emptySet()); + + mContext = context; + boolean unstableFallbackEnabled = + context.getResources().getBoolean(unstableOverlayFallbackResId); + mServiceWatcher = ServiceWatcher.create(context, provider, unstableFallbackEnabled, + CurrentUserServiceSupplier.createFromConfig(context, action, enableOverlayResId, + nonOverlayPackageResId), this); + mName = provider; + + mProxy = null; + mRequest = ProviderRequest.EMPTY_REQUEST; + } + private boolean checkServiceResolves() { return mServiceWatcher.checkServiceResolves(); } |