diff options
38 files changed, 600 insertions, 435 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index a0144ad825f1..b5fb5387ec87 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4164,7 +4164,8 @@ package android.location { method public boolean isExtraLocationControllerPackageEnabled(); method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle); method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle); - method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String); + method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); diff --git a/api/test-current.txt b/api/test-current.txt index 352297c95d42..2da651ecf20c 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1387,7 +1387,7 @@ package android.location { method @NonNull public String[] getBackgroundThrottlingWhitelist(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>); method @NonNull public String[] getIgnoreSettingsWhitelist(); - method @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String); + method @Deprecated @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String); method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 885117018c50..c2dbf4711ee0 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4987,9 +4987,10 @@ <feature android:featureId="CountryDetector" android:label="@string/country_detector"/> <!-- Feature Id for Location service. --> <feature android:featureId="LocationService" android:label="@string/location_service"/> + <!-- Feature Id for Gnss service. --> + <feature android:featureId="GnssService" android:label="@string/gnss_service"/> <!-- Feature Id for Sensor Notification service. --> - <feature android:featureId="SensorNotificationService" - android:label="@string/sensor_notification_service"/> + <feature android:featureId="SensorNotificationService" android:label="@string/sensor_notification_service"/> <!-- Feature Id for Twilight service. --> <feature android:featureId="TwilightService" android:label="@string/twilight_service"/> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 9483bf209108..74b602de69d0 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -425,6 +425,8 @@ <string name="country_detector">Country Detector</string> <!-- Feature Id for Location service. [CHAR LIMIT=NONE]--> <string name="location_service">Location Service</string> + <!-- Feature Id for Gnss service. [CHAR LIMIT=NONE]--> + <string name="gnss_service">GNSS Service</string> <!-- Feature Id for Sensor Notification service. [CHAR LIMIT=NONE]--> <string name="sensor_notification_service">Sensor Notification Service</string> <!-- Feature Id for Twilight service. [CHAR LIMIT=NONE]--> diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index b7346308042f..6f543c31d9a3 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -96,7 +96,7 @@ interface ILocationManager List<String> getProviders(in Criteria criteria, boolean enabledOnly); String getBestProvider(in Criteria criteria, boolean enabledOnly); ProviderProperties getProviderProperties(String provider); - boolean isProviderPackage(String packageName); + boolean isProviderPackage(String provider, String packageName); List<String> getProviderPackages(String provider); void setExtraLocationControllerPackage(String packageName); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 7523f07674ea..0bf7add422cf 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -64,7 +64,6 @@ import com.android.internal.location.ProviderProperties; import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledRunnable; -import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; @@ -313,10 +312,9 @@ public class LocationManager { private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000; - private final Context mContext; - + final Context mContext; @UnsupportedAppUsage - private final ILocationManager mService; + final ILocationManager mService; @GuardedBy("mListeners") private final ArrayMap<LocationListener, LocationListenerTransport> mListeners = @@ -1403,15 +1401,36 @@ public class LocationManager { * otherwise. * * @hide + * @deprecated Prefer {@link #isProviderPackage(String, String)} instead. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String packageName) { try { - return mService.isProviderPackage(packageName); + return mService.isProviderPackage(null, packageName); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return false; + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns true if the given provider corresponds to the given package name. If the given + * provider is null, this will return true if any provider corresponds to the given package + * name. + * + * @param provider a provider listed by {@link #getAllProviders()} or null + * @param packageName the package name to test if it is a provider + * @return true if the given arguments correspond to a provider + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) + public boolean isProviderPackage(@Nullable String provider, @NonNull String packageName) { + try { + return mService.isProviderPackage(provider, packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -1420,16 +1439,17 @@ public class LocationManager { * and an empty list if no package is associated with the provider. * * @hide + * @deprecated Prefer {@link #isProviderPackage(String, String)} instead. */ @TestApi + @Deprecated @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) @Nullable public List<String> getProviderPackages(@NonNull String provider) { try { return mService.getProviderPackages(provider); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return Collections.emptyList(); + throw e.rethrowFromSystemServer(); } } @@ -2470,7 +2490,7 @@ public class LocationManager { @Nullable private ICancellationSignal mRemoteCancellationSignal; - private GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer) { + GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer) { Preconditions.checkArgument(executor != null, "illegal null executor"); Preconditions.checkArgument(consumer != null, "illegal null consumer"); mExecutor = executor; @@ -2595,7 +2615,7 @@ public class LocationManager { private final LocationListener mListener; @Nullable private volatile Executor mExecutor = null; - private LocationListenerTransport(@NonNull LocationListener listener) { + LocationListenerTransport(@NonNull LocationListener listener) { Preconditions.checkArgument(listener != null, "invalid null listener"); mListener = listener; } @@ -2769,7 +2789,7 @@ public class LocationManager { private final OnNmeaMessageListener mListener; - private NmeaAdapter(OnNmeaMessageListener listener) { + NmeaAdapter(OnNmeaMessageListener listener) { mListener = listener; } @@ -2783,7 +2803,7 @@ public class LocationManager { private final GpsStatus.Listener mGpsListener; - private GpsAdapter(GpsStatus.Listener gpsListener) { + GpsAdapter(GpsStatus.Listener gpsListener) { mGpsListener = gpsListener; } @@ -2813,8 +2833,11 @@ public class LocationManager { private @Nullable IGnssStatusListener mListenerTransport; - private volatile @Nullable GnssStatus mGnssStatus; - private volatile int mTtff; + volatile @Nullable GnssStatus mGnssStatus; + volatile int mTtff; + + GnssStatusListenerManager() { + } public GnssStatus getGnssStatus() { return mGnssStatus; @@ -2862,6 +2885,9 @@ public class LocationManager { } private class GnssStatusListener extends IGnssStatusListener.Stub { + GnssStatusListener() { + } + @Override public void onGnssStarted() { deliverToListeners(GnssStatus.Callback::onStarted); @@ -2905,6 +2931,9 @@ public class LocationManager { @Nullable private IGnssMeasurementsListener mListenerTransport; + GnssMeasurementsListenerManager() { + } + @Override protected boolean registerService(GnssRequest request) { Preconditions.checkState(mListenerTransport == null); @@ -2947,6 +2976,9 @@ public class LocationManager { } private class GnssMeasurementsListener extends IGnssMeasurementsListener.Stub { + GnssMeasurementsListener() { + } + @Override public void onGnssMeasurementsReceived(final GnssMeasurementsEvent event) { deliverToListeners((callback) -> callback.onGnssMeasurementsReceived(event)); @@ -2965,6 +2997,9 @@ public class LocationManager { @Nullable private IGnssNavigationMessageListener mListenerTransport; + GnssNavigationMessageListenerManager() { + } + @Override protected boolean registerService(Void ignored) { Preconditions.checkState(mListenerTransport == null); @@ -2994,6 +3029,9 @@ public class LocationManager { } private class GnssNavigationMessageListener extends IGnssNavigationMessageListener.Stub { + GnssNavigationMessageListener() { + } + @Override public void onGnssNavigationMessageReceived(GnssNavigationMessage event) { deliverToListeners((listener) -> listener.onGnssNavigationMessageReceived(event)); @@ -3012,6 +3050,9 @@ public class LocationManager { @Nullable private IGnssAntennaInfoListener mListenerTransport; + GnssAntennaInfoListenerManager() { + } + @Override protected boolean registerService(Void ignored) { Preconditions.checkState(mListenerTransport == null); @@ -3041,6 +3082,9 @@ public class LocationManager { } private class GnssAntennaInfoListener extends IGnssAntennaInfoListener.Stub { + GnssAntennaInfoListener() { + } + @Override public void onGnssAntennaInfoReceived(List<GnssAntennaInfo> infos) { deliverToListeners(callback -> callback.onGnssAntennaInfoReceived(infos)); @@ -3055,6 +3099,9 @@ public class LocationManager { @Nullable private IBatchedLocationCallback mListenerTransport; + BatchedLocationCallbackManager() { + } + @Override protected boolean registerService(Void ignored) { Preconditions.checkState(mListenerTransport == null); @@ -3083,6 +3130,9 @@ public class LocationManager { } private class BatchedLocationCallback extends IBatchedLocationCallback.Stub { + BatchedLocationCallback() { + } + @Override public void onLocationBatch(List<Location> locations) { deliverToListeners((listener) -> listener.onLocationBatch(locations)); diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java index 6006d5079b07..542737b479e2 100644 --- a/location/java/android/location/LocationManagerInternal.java +++ b/location/java/android/location/LocationManagerInternal.java @@ -18,6 +18,8 @@ package android.location; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.location.util.identity.CallerIdentity; /** * Location manager local system service interface. @@ -36,13 +38,14 @@ public abstract class LocationManagerInternal { public abstract boolean isProviderEnabledForUser(@NonNull String provider, int userId); /** - * Returns true if the given package belongs to a location provider, and so should be afforded - * some special privileges. + * Returns true if the given identity is a location provider. * - * @param packageName The package name to check - * @return True is the given package belongs to a location provider, false otherwise + * @param provider The provider to check, or null to check every provider + * @param identity The identity to match + * @return True if the given identity matches either the given location provider or any + * provider, and false otherwise */ - public abstract boolean isProviderPackage(@NonNull String packageName); + public abstract boolean isProvider(@Nullable String provider, @NonNull CallerIdentity identity); /** * Should only be used by GNSS code. diff --git a/services/core/java/com/android/server/location/CallerIdentity.java b/location/java/android/location/util/identity/CallerIdentity.java index b84fd13415fc..15641eb3bb6f 100644 --- a/services/core/java/com/android/server/location/CallerIdentity.java +++ b/location/java/android/location/util/identity/CallerIdentity.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.location; +package android.location.util.identity; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.os.Binder; +import android.os.Process; import android.os.UserHandle; import com.android.internal.annotations.VisibleForTesting; @@ -36,7 +37,9 @@ import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** - * Represents the calling process's uid, pid, and package name. + * Identifying information on a caller. + * + * @hide */ public final class CallerIdentity { @@ -77,6 +80,26 @@ public final class CallerIdentity { } /** + * Construct a CallerIdentity for test purposes. + */ + @VisibleForTesting + public static CallerIdentity forTest(int uid, int pid, String packageName, + @Nullable String featureId, @PermissionLevel int permissionLevel) { + + return new CallerIdentity(uid, pid, packageName, featureId, + permissionLevel); + } + + /** + * Creates a CallerIdentity for the current process and context. + */ + public static CallerIdentity fromContext(Context context) { + return new CallerIdentity(Process.myUid(), Process.myPid(), + context.getPackageName(), context.getFeatureId(), + getPermissionLevel(context, Binder.getCallingPid(), Binder.getCallingUid())); + } + + /** * Creates a CallerIdentity from the current binder identity, using the given package and * feature id. The package will be checked to enforce it belongs to the calling uid, and a * security exception will be thrown if it is invalid. @@ -100,42 +123,55 @@ public final class CallerIdentity { public static CallerIdentity fromBinderUnsafe(Context context, String packageName, @Nullable String featureId) { return new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), - UserHandle.getCallingUserId(), packageName, featureId, - getBinderPermissionLevel(context)); + packageName, featureId, + getPermissionLevel(context, Binder.getCallingPid(), Binder.getCallingUid())); } /** * Throws a security exception if the caller does not hold a location permission. */ - public static void enforceCallingOrSelfLocationPermission(Context context) { - enforceLocationPermission(Binder.getCallingUid(), getBinderPermissionLevel(context)); + public static void enforceCallingOrSelfLocationPermission(Context context, + @PermissionLevel int desiredPermissionLevel) { + enforceLocationPermission(Binder.getCallingUid(), + getPermissionLevel(context, Binder.getCallingPid(), Binder.getCallingUid()), + desiredPermissionLevel); } /** * Returns false if the caller does not hold a location permission, true otherwise. */ - public static boolean checkCallingOrSelfLocationPermission(Context context) { - return checkLocationPermission(getBinderPermissionLevel(context)); + public static boolean checkCallingOrSelfLocationPermission(Context context, + @PermissionLevel int desiredPermissionLevel) { + return checkLocationPermission( + getPermissionLevel(context, Binder.getCallingPid(), Binder.getCallingUid()), + desiredPermissionLevel); } - private static void enforceLocationPermission(int uid, @PermissionLevel int permissionLevel) { - if (checkLocationPermission(permissionLevel)) { + private static void enforceLocationPermission(int uid, @PermissionLevel int permissionLevel, + @PermissionLevel int desiredPermissionLevel) { + if (checkLocationPermission(permissionLevel, desiredPermissionLevel)) { return; } - throw new SecurityException("uid " + uid + " does not have " + ACCESS_COARSE_LOCATION - + " or " + ACCESS_FINE_LOCATION + "."); + if (desiredPermissionLevel == PERMISSION_COARSE) { + throw new SecurityException("uid " + uid + " does not have " + ACCESS_COARSE_LOCATION + + " or " + ACCESS_FINE_LOCATION + "."); + } else if (desiredPermissionLevel == PERMISSION_FINE) { + throw new SecurityException("uid " + uid + " does not have " + ACCESS_FINE_LOCATION + + "."); + } } - private static boolean checkLocationPermission(@PermissionLevel int permissionLevel) { - return permissionLevel >= PERMISSION_COARSE; + private static boolean checkLocationPermission(@PermissionLevel int permissionLevel, + @PermissionLevel int desiredPermissionLevel) { + return permissionLevel >= desiredPermissionLevel; } - private static @PermissionLevel int getBinderPermissionLevel(Context context) { - if (context.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) == PERMISSION_GRANTED) { + private static @PermissionLevel int getPermissionLevel(Context context, int pid, int uid) { + if (context.checkPermission(ACCESS_FINE_LOCATION, pid, uid) == PERMISSION_GRANTED) { return PERMISSION_FINE; } - if (context.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED) { + if (context.checkPermission(ACCESS_COARSE_LOCATION, pid, uid) == PERMISSION_GRANTED) { return PERMISSION_COARSE; } @@ -164,12 +200,11 @@ public final class CallerIdentity { */ public final @PermissionLevel int permissionLevel; - @VisibleForTesting - public CallerIdentity(int uid, int pid, int userId, String packageName, + private CallerIdentity(int uid, int pid, String packageName, @Nullable String featureId, @PermissionLevel int permissionLevel) { this.uid = uid; this.pid = pid; - this.userId = userId; + this.userId = UserHandle.getUserId(uid); this.packageName = Objects.requireNonNull(packageName); this.featureId = featureId; this.permissionLevel = Preconditions.checkArgumentInRange(permissionLevel, PERMISSION_NONE, @@ -179,8 +214,8 @@ public final class CallerIdentity { /** * Throws a security exception if the CallerIdentity does not hold a location permission. */ - public void enforceLocationPermission() { - enforceLocationPermission(uid, permissionLevel); + public void enforceLocationPermission(@PermissionLevel int desiredPermissionLevel) { + enforceLocationPermission(uid, permissionLevel, desiredPermissionLevel); } @Override diff --git a/location/java/android/location/util/listeners/AbstractListenerManager.java b/location/java/android/location/util/listeners/AbstractListenerManager.java index facb74766f2c..09c1eb2ae153 100644 --- a/location/java/android/location/util/listeners/AbstractListenerManager.java +++ b/location/java/android/location/util/listeners/AbstractListenerManager.java @@ -156,8 +156,15 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, // this class does not support adding listeners reentrantly Preconditions.checkState(!mReentrancyGuard.isReentrant()); + if (mRegistrations.isEmpty()) { + onRegister(); + } + if (!registration.register()) { registration.unregister(); + if (mRegistrations.isEmpty()) { + onUnregister(); + } return; } @@ -210,6 +217,10 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, onRegistrationRemoved(key, registration); registration.unregister(); updateService(); + + if (mRegistrations.isEmpty()) { + onUnregister(); + } } /** @@ -316,10 +327,26 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, protected abstract void unregisterService(); /** + * Invoked before the first registration occurs. This is a convenient entry point for + * registering listeners, etc, which only need to be present while there are any registrations. + * This method will always be invoked before a corresponding call to + * {@link Registration#onRegister()} and {@link #onActive()}. + */ + protected void onRegister() {} + + /** + * Invoked after the last unregistration occurs. This is a convenient entry point for + * unregistering listeners, etc, which only need to be present while there are any + * registrations. This method will always be after a corresponding call to + * {@link Registration#onUnregister()} and {@link #onInactive()}. + */ + protected void onUnregister() {} + + /** * Invoked when the listener goes from having no active registrations to having some active * registrations. This is a convenient entry point for registering listeners, etc, which only * need to be present while there are active registrations. This method will always be invoked - * before a corrosponding call to {@link #registerService(Object)}. + * before a corresponding call to {@link #registerService(Object)}. */ protected void onActive() {} @@ -327,7 +354,7 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, * Invoked when the listener goes from having some active registrations to having no active * registrations. This is a convenient entry point for unregistering listeners, etc, which only * need to be present while there are active registrations. This method will always be invoked - * after a corrosponding call to {@link #unregisterService()}. + * after a corresponding call to {@link #unregisterService()}. */ protected void onInactive() {} diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl index 439039148773..1bdedd57f321 100644 --- a/location/java/com/android/internal/location/ILocationProviderManager.aidl +++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl @@ -26,7 +26,7 @@ import com.android.internal.location.ProviderProperties; */ interface ILocationProviderManager { - void onSetAdditionalProviderPackages(in List<String> packageNames); + void onSetFeatureId(String featureId); @UnsupportedAppUsage void onSetAllowed(boolean allowed); diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt index 9cc30d0d751e..4d0acea15263 100644 --- a/location/lib/api/current.txt +++ b/location/lib/api/current.txt @@ -7,7 +7,8 @@ package com.android.location.provider { } public abstract class LocationProviderBase { - ctor public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled); + ctor @Deprecated public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled); + ctor @RequiresApi(android.os.Build.VERSION_CODES.R) public LocationProviderBase(android.content.Context, String, com.android.location.provider.ProviderPropertiesUnbundled); method public android.os.IBinder getBinder(); method @RequiresApi(android.os.Build.VERSION_CODES.R) public boolean isAllowed(); method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled(); @@ -20,11 +21,11 @@ package com.android.location.provider { method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle); method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); method public void reportLocation(android.location.Location); - method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>); + method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>); method @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean); method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean); method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled); - field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; + field @Deprecated public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; field public static final String FUSED_PROVIDER = "fused"; } diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java index d3fb58fe257e..624e8d1b702b 100644 --- a/location/lib/java/com/android/location/provider/LocationProviderBase.java +++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java @@ -39,7 +39,6 @@ import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.List; /** @@ -65,7 +64,10 @@ public abstract class LocationProviderBase { * Bundle key for a version of the location containing no GPS data. * Allows location providers to flag locations as being safe to * feed to LocationFudger. + * + * @deprecated Do not use from Android R onwards. */ + @Deprecated public static final String EXTRA_NO_GPS_LOCATION = Location.EXTRA_NO_GPS_LOCATION; /** @@ -76,8 +78,9 @@ public abstract class LocationProviderBase { */ public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER; - private final String mTag; - private final IBinder mBinder; + final String mTag; + final String mFeatureId; + final IBinder mBinder; /** * This field may be removed in the future, do not rely on it. @@ -90,13 +93,30 @@ public abstract class LocationProviderBase { protected final ILocationManager mLocationManager; // write locked on mBinder, read lock is optional depending on atomicity requirements - @Nullable private volatile ILocationProviderManager mManager; - private volatile ProviderProperties mProperties; - private volatile boolean mAllowed; - private final ArrayList<String> mAdditionalProviderPackages; + @Nullable + volatile ILocationProviderManager mManager; + volatile ProviderProperties mProperties; + volatile boolean mAllowed; + /** + * @deprecated Prefer + * {@link #LocationProviderBase(Context, String, ProviderPropertiesUnbundled)}. + */ + @Deprecated public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) { + this(null, tag, properties); + } + + /** + * This constructor associates the feature id of the given context with this location provider. + * The location service may afford special privileges to incoming calls identified as belonging + * to this location provider. + */ + @RequiresApi(VERSION_CODES.R) + public LocationProviderBase(Context context, String tag, + ProviderPropertiesUnbundled properties) { mTag = tag; + mFeatureId = context != null ? context.getFeatureId() : null; mBinder = new Service(); mLocationManager = ILocationManager.Stub.asInterface( @@ -105,7 +125,6 @@ public abstract class LocationProviderBase { mManager = null; mProperties = properties.getProviderProperties(); mAllowed = true; - mAdditionalProviderPackages = new ArrayList<>(0); } public IBinder getBinder() { @@ -183,23 +202,12 @@ public abstract class LocationProviderBase { * another package may issue location requests on behalf of this package in the course of * providing location. This will inform location services to treat the other packages as * location providers as well. + * + * @deprecated On Android R and above this has no effect. */ + @Deprecated @RequiresApi(VERSION_CODES.Q) - public void setAdditionalProviderPackages(List<String> packageNames) { - synchronized (mBinder) { - mAdditionalProviderPackages.clear(); - mAdditionalProviderPackages.addAll(packageNames); - } - - ILocationProviderManager manager = mManager; - if (manager != null) { - try { - manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); - } catch (RemoteException | RuntimeException e) { - Log.w(mTag, e); - } - } - } + public void setAdditionalProviderPackages(List<String> packageNames) {} /** * @deprecated Use {@link #isAllowed()} instead. @@ -317,12 +325,15 @@ public abstract class LocationProviderBase { private final class Service extends ILocationProvider.Stub { + Service() { + } + @Override public void setLocationProviderManager(ILocationProviderManager manager) { synchronized (mBinder) { try { - if (!mAdditionalProviderPackages.isEmpty()) { - manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); + if (mFeatureId != null) { + manager.onSetFeatureId(mFeatureId); } manager.onSetProperties(mProperties); manager.onSetAllowed(mAllowed); diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java index fb7dbc8aca5c..781efc118429 100644 --- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java +++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java @@ -30,9 +30,7 @@ import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; -import android.os.Bundle; import android.os.Looper; -import android.os.Parcelable; import android.os.WorkSource; import com.android.internal.annotations.GuardedBy; @@ -64,7 +62,7 @@ public class FusedLocationProvider extends LocationProviderBase { private static final long MAX_LOCATION_COMPARISON_NS = 11 * 1000000000L; // 11 seconds - private final Object mLock = new Object(); + final Object mLock = new Object(); private final Context mContext; private final LocationManager mLocationManager; @@ -73,7 +71,7 @@ public class FusedLocationProvider extends LocationProviderBase { private final BroadcastReceiver mUserChangeReceiver; @GuardedBy("mLock") - private ProviderRequestUnbundled mRequest; + ProviderRequestUnbundled mRequest; @GuardedBy("mLock") private WorkSource mWorkSource; @GuardedBy("mLock") @@ -84,12 +82,12 @@ public class FusedLocationProvider extends LocationProviderBase { @GuardedBy("mLock") @Nullable private Location mFusedLocation; @GuardedBy("mLock") - @Nullable private Location mGpsLocation; + @Nullable Location mGpsLocation; @GuardedBy("mLock") - @Nullable private Location mNetworkLocation; + @Nullable Location mNetworkLocation; public FusedLocationProvider(Context context) { - super(TAG, PROPERTIES); + super(context, TAG, PROPERTIES); mContext = context; mLocationManager = context.getSystemService(LocationManager.class); @@ -232,7 +230,7 @@ public class FusedLocationProvider extends LocationProviderBase { } @GuardedBy("mLock") - private void reportBestLocationLocked() { + void reportBestLocationLocked() { Location bestLocation = chooseBestLocation(mGpsLocation, mNetworkLocation); if (bestLocation == mFusedLocation) { return; @@ -243,28 +241,10 @@ public class FusedLocationProvider extends LocationProviderBase { return; } - // copy NO_GPS_LOCATION extra from mNetworkLocation into mFusedLocation - if (mNetworkLocation != null) { - Bundle srcExtras = mNetworkLocation.getExtras(); - if (srcExtras != null) { - Parcelable srcParcelable = - srcExtras.getParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION); - if (srcParcelable instanceof Location) { - Bundle dstExtras = mFusedLocation.getExtras(); - if (dstExtras == null) { - dstExtras = new Bundle(); - mFusedLocation.setExtras(dstExtras); - } - dstExtras.putParcelable(LocationProviderBase.EXTRA_NO_GPS_LOCATION, - srcParcelable); - } - } - } - reportLocation(mFusedLocation); } - private void onUserChanged() { + void onUserChanged() { // clear cached locations when the user changes to prevent leaking user information synchronized (mLock) { mFusedLocation = null; diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java index d1a379afa25e..38f3bcdb62fe 100644 --- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java +++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java @@ -52,7 +52,6 @@ import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.Collections; -import java.util.List; import java.util.Random; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -200,7 +199,7 @@ public class FusedLocationServiceTest { } @Override - public void onSetAdditionalProviderPackages(List<String> packageNames) { + public void onSetFeatureId(String featureId) { } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 2c4309fb1610..cf0b3af07aee 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -24,11 +24,10 @@ import static android.location.LocationManager.FUSED_PROVIDER; import static android.location.LocationManager.GPS_PROVIDER; import static android.location.LocationManager.NETWORK_PROVIDER; import static android.location.LocationManager.PASSIVE_PROVIDER; +import static android.location.util.identity.CallerIdentity.PERMISSION_COARSE; +import static android.location.util.identity.CallerIdentity.PERMISSION_FINE; import static android.os.PowerManager.locationPowerSaveModeToString; -import static com.android.server.location.CallerIdentity.PERMISSION_COARSE; -import static com.android.server.location.CallerIdentity.PERMISSION_FINE; - import static java.util.concurrent.TimeUnit.NANOSECONDS; import android.Manifest; @@ -62,6 +61,8 @@ import android.location.LocationManagerInternal; import android.location.LocationProvider; import android.location.LocationRequest; import android.location.LocationTime; +import android.location.util.identity.CallerIdentity; +import android.location.util.identity.CallerIdentity.PermissionLevel; import android.os.Binder; import android.os.Bundle; import android.os.CancellationSignal; @@ -95,8 +96,6 @@ import com.android.server.location.AbstractLocationProvider; import com.android.server.location.AbstractLocationProvider.State; import com.android.server.location.AppForegroundHelper; import com.android.server.location.AppOpsHelper; -import com.android.server.location.CallerIdentity; -import com.android.server.location.CallerIdentity.PermissionLevel; import com.android.server.location.GeocoderProxy; import com.android.server.location.GeofenceManager; import com.android.server.location.GeofenceProxy; @@ -128,7 +127,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import java.util.Set; import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -229,7 +227,7 @@ public class LocationManagerService extends ILocationManager.Stub { // @GuardedBy("mLock") // hold lock for write or to prevent write, no lock for read - private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers = + final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers = new CopyOnWriteArrayList<>(); @GuardedBy("mLock") @@ -243,7 +241,7 @@ public class LocationManagerService extends ILocationManager.Stub { @PowerManager.LocationPowerSaveMode private int mBatterySaverMode; - private LocationManagerService(Context context) { + LocationManagerService(Context context) { mContext = context.createFeatureContext(FEATURE_ID); mHandler = FgThread.getHandler(); mLocalService = new LocalService(); @@ -278,7 +276,7 @@ public class LocationManagerService extends ILocationManager.Stub { // most startup is deferred until systemReady() } - private void onSystemReady() { + void onSystemReady() { mAppOpsHelper.onSystemReady(); mUserInfoHelper.onSystemReady(); mSettingsHelper.onSystemReady(); @@ -358,7 +356,7 @@ public class LocationManagerService extends ILocationManager.Stub { } } - private void onSystemThirdPartyAppsCanStart() { + void onSystemThirdPartyAppsCanStart() { synchronized (mLock) { // prepare providers initializeProvidersLocked(); @@ -666,7 +664,7 @@ public class LocationManagerService extends ILocationManager.Stub { // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary protected final MockableLocationProvider mProvider; - private LocationProviderManager(String name) { + LocationProviderManager(String name) { mName = name; mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM()); mEnabled = new SparseArray<>(2); @@ -716,8 +714,9 @@ public class LocationManagerService extends ILocationManager.Stub { } } - public Set<String> getPackages() { - return mProvider.getState().providerPackageNames; + @Nullable + public CallerIdentity getProviderIdentity() { + return mProvider.getState().identity; } @Nullable @@ -1395,7 +1394,7 @@ public class LocationManagerService extends ILocationManager.Stub { } @Nullable - private LocationProviderManager getLocationProviderManager(String providerName) { + LocationProviderManager getLocationProviderManager(String providerName) { for (LocationProviderManager manager : mProviderManagers) { if (providerName.equals(manager.getName())) { return manager; @@ -1419,7 +1418,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public List<String> getProviders(Criteria criteria, boolean enabledOnly) { - if (!CallerIdentity.checkCallingOrSelfLocationPermission(mContext)) { + if (!CallerIdentity.checkCallingOrSelfLocationPermission(mContext, PERMISSION_COARSE)) { return Collections.emptyList(); } @@ -1653,7 +1652,7 @@ public class LocationManagerService extends ILocationManager.Stub { return true; } - return mLocalService.isProviderPackage(callerIdentity.packageName); + return mLocalService.isProvider(null, callerIdentity); } @@ -1667,8 +1666,7 @@ public class LocationManagerService extends ILocationManager.Stub { return true; } - return mLocalService.isProviderPackage(record.mReceiver.mCallerIdentity.packageName); - + return mLocalService.isProvider(null, record.mReceiver.mCallerIdentity); } private class UpdateRecord { @@ -1850,7 +1848,7 @@ public class LocationManagerService extends ILocationManager.Stub { } CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); - identity.enforceLocationPermission(); + identity.enforceLocationPermission(PERMISSION_COARSE); WorkSource workSource = request.getWorkSource(); if (workSource != null && !workSource.isEmpty()) { @@ -2002,7 +2000,7 @@ public class LocationManagerService extends ILocationManager.Stub { // unsafe is ok because app ops will verify the package name CallerIdentity identity = CallerIdentity.fromBinderUnsafe(mContext, packageName, featureId); - identity.enforceLocationPermission(); + identity.enforceLocationPermission(PERMISSION_COARSE); if (mSettingsHelper.isLocationPackageBlacklisted(identity.userId, identity.packageName)) { return null; @@ -2114,7 +2112,7 @@ public class LocationManagerService extends ILocationManager.Stub { } CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); - identity.enforceLocationPermission(); + identity.enforceLocationPermission(PERMISSION_COARSE); Objects.requireNonNull(intent); @@ -2254,7 +2252,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public boolean sendExtraCommand(String provider, String command, Bundle extras) { - CallerIdentity.enforceCallingOrSelfLocationPermission(mContext); + CallerIdentity.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_COARSE); mContext.enforceCallingOrSelfPermission( Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null); @@ -2288,16 +2286,40 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public boolean isProviderPackage(String packageName) { + public boolean isProviderPackage(String provider, String packageName) { mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null); - return mLocalService.isProviderPackage(packageName); + + for (LocationProviderManager manager : mProviderManagers) { + if (provider != null && !provider.equals(manager.getName())) { + continue; + } + CallerIdentity identity = manager.getProviderIdentity(); + if (identity == null) { + continue; + } + if (identity.packageName.equals(packageName)) { + return true; + } + } + + return false; } @Override - public List<String> getProviderPackages(String providerName) { + public List<String> getProviderPackages(String provider) { mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null); - LocationProviderManager manager = getLocationProviderManager(providerName); - return manager == null ? Collections.emptyList() : new ArrayList<>(manager.getPackages()); + + LocationProviderManager manager = getLocationProviderManager(provider); + if (manager == null) { + return Collections.emptyList(); + } + + CallerIdentity identity = manager.getProviderIdentity(); + if (identity == null) { + return Collections.emptyList(); + } + + return Collections.singletonList(identity.packageName); } @Override @@ -2426,7 +2448,7 @@ public class LocationManagerService extends ILocationManager.Stub { } if (!mUserInfoHelper.isCurrentUserId(identity.userId) - && !isProviderPackage(identity.packageName)) { + && !mLocalService.isProvider(null, identity)) { continue; } @@ -2725,6 +2747,8 @@ public class LocationManagerService extends ILocationManager.Stub { private class LocalService extends LocationManagerInternal { + LocalService() {} + @Override public boolean isProviderEnabledForUser(@NonNull String provider, int userId) { userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), @@ -2739,12 +2763,16 @@ public class LocationManagerService extends ILocationManager.Stub { } @Override - public boolean isProviderPackage(String packageName) { + public boolean isProvider(String provider, CallerIdentity identity) { for (LocationProviderManager manager : mProviderManagers) { - if (manager.getPackages().contains(packageName)) { + if (provider != null && !provider.equals(manager.getName())) { + continue; + } + if (identity.equals(manager.getProviderIdentity())) { return true; } } + return false; } diff --git a/services/core/java/com/android/server/LocationManagerServiceUtils.java b/services/core/java/com/android/server/LocationManagerServiceUtils.java index f50a885dd20c..7ffbc31bc949 100644 --- a/services/core/java/com/android/server/LocationManagerServiceUtils.java +++ b/services/core/java/com/android/server/LocationManagerServiceUtils.java @@ -17,11 +17,10 @@ package com.android.server; import android.annotation.NonNull; +import android.location.util.identity.CallerIdentity; import android.os.IBinder; import android.os.RemoteException; -import com.android.server.location.CallerIdentity; - import java.util.NoSuchElementException; /** diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java index e9d94a5430fe..d45ab561f3c6 100644 --- a/services/core/java/com/android/server/location/AbstractLocationProvider.java +++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java @@ -19,21 +19,18 @@ package com.android.server.location; import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable; import android.annotation.Nullable; -import android.content.Context; import android.location.Location; +import android.location.util.identity.CallerIdentity; import android.os.Binder; import android.os.Bundle; -import android.util.ArraySet; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; @@ -78,8 +75,7 @@ public abstract class AbstractLocationProvider { * Default state value for a location provider that is disabled with no properties and an * empty provider package list. */ - public static final State EMPTY_STATE = new State(false, null, - Collections.emptySet()); + public static final State EMPTY_STATE = new State(false, null, null); /** * The provider's allowed state. @@ -92,39 +88,37 @@ public abstract class AbstractLocationProvider { @Nullable public final ProviderProperties properties; /** - * The provider's package name list - provider packages may be afforded special privileges. + * The provider's identity - providers may be afforded special privileges. */ - public final Set<String> providerPackageNames; + @Nullable public final CallerIdentity identity; - private State(boolean allowed, ProviderProperties properties, - Set<String> providerPackageNames) { + private State(boolean allowed, ProviderProperties properties, CallerIdentity identity) { this.allowed = allowed; this.properties = properties; - this.providerPackageNames = Objects.requireNonNull(providerPackageNames); + this.identity = identity; } - private State withAllowed(boolean allowed) { + State withAllowed(boolean allowed) { if (allowed == this.allowed) { return this; } else { - return new State(allowed, properties, providerPackageNames); + return new State(allowed, properties, identity); } } - private State withProperties(ProviderProperties properties) { - if (properties.equals(this.properties)) { + State withProperties(@Nullable ProviderProperties properties) { + if (Objects.equals(properties, this.properties)) { return this; } else { - return new State(allowed, properties, providerPackageNames); + return new State(allowed, properties, identity); } } - private State withProviderPackageNames(Set<String> providerPackageNames) { - if (providerPackageNames.equals(this.providerPackageNames)) { + State withIdentity(@Nullable CallerIdentity identity) { + if (Objects.equals(identity, this.identity)) { return this; } else { - return new State(allowed, properties, - Collections.unmodifiableSet(new ArraySet<>(providerPackageNames))); + return new State(allowed, properties, identity); } } @@ -138,12 +132,12 @@ public abstract class AbstractLocationProvider { } State state = (State) o; return allowed == state.allowed && properties == state.properties - && providerPackageNames.equals(state.providerPackageNames); + && Objects.equals(identity, state.identity); } @Override public int hashCode() { - return Objects.hash(allowed, properties, providerPackageNames); + return Objects.hash(allowed, properties, identity); } } @@ -153,12 +147,12 @@ public abstract class AbstractLocationProvider { @Nullable public final Listener listener; public final State state; - private InternalState(@Nullable Listener listener, State state) { + InternalState(@Nullable Listener listener, State state) { this.listener = listener; this.state = state; } - private InternalState withListener(Listener listener) { + InternalState withListener(Listener listener) { if (listener == this.listener) { return this; } else { @@ -166,7 +160,7 @@ public abstract class AbstractLocationProvider { } } - private InternalState withState(State state) { + InternalState withState(State state) { if (state.equals(this.state)) { return this; } else { @@ -174,7 +168,7 @@ public abstract class AbstractLocationProvider { } } - private InternalState withState(UnaryOperator<State> operator) { + InternalState withState(UnaryOperator<State> operator) { return withState(operator.apply(state)); } } @@ -187,14 +181,17 @@ public abstract class AbstractLocationProvider { // before it was set, and should not miss any updates that occur after it was set). private final AtomicReference<InternalState> mInternalState; - protected AbstractLocationProvider(Executor executor, Context context) { - this(executor, Collections.singleton(context.getPackageName())); + + protected AbstractLocationProvider(Executor executor) { + mExecutor = executor; + mInternalState = new AtomicReference<>( + new InternalState(null, State.EMPTY_STATE)); } - protected AbstractLocationProvider(Executor executor, Set<String> packageNames) { + protected AbstractLocationProvider(Executor executor, CallerIdentity identity) { mExecutor = executor; mInternalState = new AtomicReference<>( - new InternalState(null, State.EMPTY_STATE.withProviderPackageNames(packageNames))); + new InternalState(null, State.EMPTY_STATE.withIdentity(identity))); } /** @@ -275,10 +272,11 @@ public abstract class AbstractLocationProvider { } /** - * The current package set of this provider. + * The current identity of this provider. */ - protected Set<String> getProviderPackages() { - return mInternalState.get().state.providerPackageNames; + @Nullable + protected CallerIdentity getIdentity() { + return mInternalState.get().state.identity; } /** @@ -298,8 +296,8 @@ public abstract class AbstractLocationProvider { /** * Call this method to report a change in provider packages. */ - protected void setPackageNames(Set<String> packageNames) { - setState(state -> state.withProviderPackageNames(packageNames)); + protected void setIdentity(CallerIdentity identity) { + setState(state -> state.withIdentity(identity)); } /** diff --git a/services/core/java/com/android/server/location/AppOpsHelper.java b/services/core/java/com/android/server/location/AppOpsHelper.java index 9c279166ac8a..1df40f2e9ffc 100644 --- a/services/core/java/com/android/server/location/AppOpsHelper.java +++ b/services/core/java/com/android/server/location/AppOpsHelper.java @@ -25,6 +25,7 @@ import static com.android.server.LocationManagerService.TAG; import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; +import android.location.util.identity.CallerIdentity; import android.os.Binder; import android.util.Log; @@ -85,7 +86,7 @@ public class AppOpsHelper { }); } - private void onAppOpChanged(String packageName) { + void onAppOpChanged(String packageName) { if (D) { Log.v(TAG, "location appop changed for " + packageName); } diff --git a/services/core/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java index 195b059b7374..1607283de33b 100644 --- a/services/core/java/com/android/server/location/GeofenceManager.java +++ b/services/core/java/com/android/server/location/GeofenceManager.java @@ -25,6 +25,7 @@ import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; +import android.location.util.identity.CallerIdentity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; diff --git a/services/core/java/com/android/server/location/GeofenceState.java b/services/core/java/com/android/server/location/GeofenceState.java index 13318bfa6492..7d0a90b0f589 100644 --- a/services/core/java/com/android/server/location/GeofenceState.java +++ b/services/core/java/com/android/server/location/GeofenceState.java @@ -20,6 +20,7 @@ package com.android.server.location; import android.app.PendingIntent; import android.location.Geofence; import android.location.Location; +import android.location.util.identity.CallerIdentity; /** * Represents state associated with a geofence diff --git a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java index 4926a1c7f6e0..1dc34556402a 100644 --- a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java +++ b/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java @@ -18,12 +18,13 @@ package com.android.server.location; import android.location.GnssAntennaInfo; import android.location.IGnssAntennaInfoListener; +import android.location.util.identity.CallerIdentity; import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.gnss.GnssListenerManager; import com.android.server.location.gnss.GnssManagerService; -import com.android.server.location.util.listeners.GnssListenerManager; import java.util.List; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 8984ba8e034b..010e86960a14 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -39,6 +39,7 @@ import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; +import android.location.util.identity.CallerIdentity; import android.os.AsyncTask; import android.os.BatteryStats; import android.os.Binder; @@ -620,7 +621,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements public GnssLocationProvider(Context context, UserInfoHelper userInfoHelper, SettingsHelper settingsHelper, AppOpsHelper appOpsHelper, AppForegroundHelper appForegroundHelper, LocationUsageLogger logger) { - super(FgThread.getExecutor(), context); + super(FgThread.getExecutor(), CallerIdentity.fromContext(context)); ensureInitialized(); diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java index c3e055d2efb2..52391d3e55a8 100644 --- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java @@ -19,14 +19,15 @@ package com.android.server.location; import android.location.GnssMeasurementsEvent; import android.location.GnssRequest; import android.location.IGnssMeasurementsListener; +import android.location.util.identity.CallerIdentity; import android.os.IBinder; import android.os.RemoteException; import android.stats.location.LocationStatsEnums; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.gnss.GnssListenerManager; import com.android.server.location.gnss.GnssManagerService; -import com.android.server.location.util.listeners.GnssListenerManager; import java.util.List; import java.util.Objects; diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java index 10f7c4cb34eb..85d3b66d4213 100644 --- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java +++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java @@ -18,12 +18,13 @@ package com.android.server.location; import android.location.GnssNavigationMessage; import android.location.IGnssNavigationMessageListener; +import android.location.util.identity.CallerIdentity; import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.gnss.GnssListenerManager; import com.android.server.location.gnss.GnssManagerService; -import com.android.server.location.util.listeners.GnssListenerManager; /** * An base implementation for GPS navigation messages provider. diff --git a/services/core/java/com/android/server/location/GnssStatusProvider.java b/services/core/java/com/android/server/location/GnssStatusProvider.java index 7d9ff2c55907..ab2c40e0478c 100644 --- a/services/core/java/com/android/server/location/GnssStatusProvider.java +++ b/services/core/java/com/android/server/location/GnssStatusProvider.java @@ -17,13 +17,14 @@ package com.android.server.location; import android.location.IGnssStatusListener; +import android.location.util.identity.CallerIdentity; import android.os.IBinder; import android.os.RemoteException; import android.stats.location.LocationStatsEnums; import android.util.Log; +import com.android.server.location.gnss.GnssListenerManager; import com.android.server.location.gnss.GnssManagerService; -import com.android.server.location.util.listeners.GnssListenerManager; /** * Implementation of a handler for {@link IGnssStatusListener}. diff --git a/services/core/java/com/android/server/location/LocationPermissionUtil.java b/services/core/java/com/android/server/location/LocationPermissionUtil.java deleted file mode 100644 index 80b93b5e8ef6..000000000000 --- a/services/core/java/com/android/server/location/LocationPermissionUtil.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 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.content.pm.PackageManager; - -/** - * Encapsulates utility functions and classes related to location permission checking. - */ -public final class LocationPermissionUtil { - /** - * Returns true if the calling process identified by {@code callerIdentity} is enabled to - * report location to AppOps service before providing device location identifiable information - * to its clients. Packages with these permissions must report any reporting of location - * information to apps, via AppOps. - * - * <p>The calling package represented by {@code callerIdentity} is considered a part of the - * extended Location Manager Service if it has all of the permissions below. - * <ul> - * <li>{@link android.Manifest.permission#LOCATION_HARDWARE} - * <li>{@link android.Manifest.permission#UPDATE_APP_OPS_STATS} - * </ul> - * - * <p>Any package with these permissions, that passes along location information from Android - * framework to apps, must report to AppOps, similarly to Location Manager Service - i.e. - * whenever it reports device location or location identifiable information such as - * GNSS status, GNSS measurements, etc. to its clients. - */ - public static boolean doesCallerReportToAppOps(Context context, CallerIdentity callerIdentity) { - return hasPermissionLocationHardware(context, callerIdentity) - && hasPermissionUpdateAppOpsStats(context, callerIdentity); - } - - private static boolean hasPermissionLocationHardware(Context context, - CallerIdentity callerIdentity) { - return context.checkPermission(android.Manifest.permission.LOCATION_HARDWARE, - callerIdentity.pid, callerIdentity.uid) == PackageManager.PERMISSION_GRANTED; - } - - private static boolean hasPermissionUpdateAppOpsStats(Context context, - CallerIdentity callerIdentity) { - return context.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, - callerIdentity.pid, callerIdentity.uid) == PackageManager.PERMISSION_GRANTED; - } - - private LocationPermissionUtil() {} -} diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 87208a7f36f5..696b571f419a 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -16,20 +16,16 @@ package com.android.server.location; -import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; - import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageManager; import android.location.Location; +import android.location.util.identity.CallerIdentity; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; -import android.util.ArraySet; -import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.location.ILocationProvider; @@ -41,18 +37,12 @@ import com.android.server.ServiceWatcher; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Collections; -import java.util.List; /** * Proxy for ILocationProvider implementations. */ public class LocationProviderProxy extends AbstractLocationProvider { - private static final String TAG = "LocationProviderProxy"; - - private static final int MAX_ADDITIONAL_PACKAGES = 2; - /** * Creates and registers this proxy. If no suitable service is available for the proxy, returns * null. @@ -69,76 +59,13 @@ public class LocationProviderProxy extends AbstractLocationProvider { } } - private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() { - // executed on binder thread - @Override - public void onSetAdditionalProviderPackages(List<String> packageNames) { - int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size()); - ArraySet<String> allPackages = new ArraySet<>(maxCount + 1); - for (String packageName : packageNames) { - if (packageNames.size() >= maxCount) { - return; - } - - try { - mContext.getPackageManager().getPackageInfo(packageName, MATCH_SYSTEM_ONLY); - allPackages.add(packageName); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, mServiceWatcher + " specified unknown additional provider package: " - + packageName); - } - } - - synchronized (mLock) { - if (!mBound) { - return; - } - - // add the binder package - ComponentName service = mServiceWatcher.getBoundService().component; - if (service != null) { - allPackages.add(service.getPackageName()); - } - - setPackageNames(allPackages); - } - } - - // executed on binder thread - @Override - public void onSetAllowed(boolean allowed) { - synchronized (mLock) { - if (mBound) { - setAllowed(allowed); - } - } - } - - // executed on binder thread - @Override - public void onSetProperties(ProviderProperties properties) { - synchronized (mLock) { - if (mBound) { - setProperties(properties); - } - } - } - - // executed on binder thread - @Override - public void onReportLocation(Location location) { - reportLocation(location); - } - }; + final Object mLock = new Object(); - // also used to synchronized any state changes (setEnabled, setProperties, setState, etc) - private final Object mLock = new Object(); - - private final Context mContext; - private final ServiceWatcher mServiceWatcher; + final Context mContext; + final ServiceWatcher mServiceWatcher; @GuardedBy("mLock") - private boolean mBound; + Proxy mProxy; private volatile ProviderRequest mRequest; @@ -146,13 +73,13 @@ public class LocationProviderProxy extends AbstractLocationProvider { int nonOverlayPackageResId) { // safe to use direct executor since our locks are not acquired in a code path invoked by // our owning provider - super(DIRECT_EXECUTOR, Collections.emptySet()); + super(DIRECT_EXECUTOR); mContext = context; mServiceWatcher = new ServiceWatcher(context, FgThread.getHandler(), action, this::onBind, this::onUnbind, enableOverlayResId, nonOverlayPackageResId); - mBound = false; + mProxy = null; mRequest = ProviderRequest.EMPTY_REQUEST; } @@ -164,25 +91,19 @@ public class LocationProviderProxy extends AbstractLocationProvider { ILocationProvider provider = ILocationProvider.Stub.asInterface(binder); synchronized (mLock) { - mBound = true; - - provider.setLocationProviderManager(mManager); + mProxy = new Proxy(); + provider.setLocationProviderManager(mProxy); ProviderRequest request = mRequest; if (!request.equals(ProviderRequest.EMPTY_REQUEST)) { provider.setRequest(request, request.workSource); } - - ComponentName service = mServiceWatcher.getBoundService().component; - if (service != null) { - setPackageNames(Collections.singleton(service.getPackageName())); - } } } private void onUnbind() { synchronized (mLock) { - mBound = false; + mProxy = null; setState(State.EMPTY_STATE); } } @@ -208,4 +129,76 @@ public class LocationProviderProxy extends AbstractLocationProvider { public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mServiceWatcher.dump(fd, pw, args); } + + private class Proxy extends ILocationProviderManager.Stub { + + Proxy() {} + + // executed on binder thread + @Override + public void onSetFeatureId(String featureId) { + synchronized (mLock) { + if (mProxy != this) { + return; + } + + ComponentName service = mServiceWatcher.getBoundService().component; + if (service == null) { + return; + } + + // we don't need to verify the package name because we're getting it straight from + // the service watcher + CallerIdentity identity = CallerIdentity.fromBinderUnsafe(mContext, + service.getPackageName(), featureId); + setIdentity(identity); + } + } + + // executed on binder thread + @Override + public void onSetProperties(ProviderProperties properties) { + synchronized (mLock) { + if (mProxy != this) { + return; + } + + // if no identity is set yet, set it now + if (getIdentity() == null) { + ComponentName service = mServiceWatcher.getBoundService().component; + if (service != null) { + // we don't need to verify the package name because we're getting it + // straight from the service watcher + setIdentity(CallerIdentity.fromBinderUnsafe(mContext, + service.getPackageName(), null)); + } + } + + setProperties(properties); + } + } + + // executed on binder thread + @Override + public void onSetAllowed(boolean allowed) { + synchronized (mLock) { + if (mProxy != this) { + return; + } + + setAllowed(allowed); + } + } + + // executed on binder thread + @Override + public void onReportLocation(Location location) { + synchronized (mLock) { + if (mProxy != this) { + return; + } + reportLocation(location); + } + } + } } diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index 5ec06ca25581..160e641aee9e 100644 --- a/services/core/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java @@ -27,7 +27,6 @@ import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Collections; /** * A mock location provider used by LocationManagerService to implement test providers. @@ -40,7 +39,7 @@ public class MockProvider extends AbstractLocationProvider { public MockProvider(ProviderProperties properties) { // using a direct executor is ok because this class has no locks that could deadlock - super(DIRECT_EXECUTOR, Collections.emptySet()); + super(DIRECT_EXECUTOR); setProperties(properties); } diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java index 0f358e97bc98..54af1c84d36b 100644 --- a/services/core/java/com/android/server/location/MockableLocationProvider.java +++ b/services/core/java/com/android/server/location/MockableLocationProvider.java @@ -28,7 +28,6 @@ import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Collections; import java.util.List; /** @@ -48,10 +47,10 @@ import java.util.List; */ public class MockableLocationProvider extends AbstractLocationProvider { - private final Object mOwnerLock; + final Object mOwnerLock; @GuardedBy("mOwnerLock") - @Nullable private AbstractLocationProvider mProvider; + @Nullable AbstractLocationProvider mProvider; @GuardedBy("mOwnerLock") @Nullable private AbstractLocationProvider mRealProvider; @GuardedBy("mOwnerLock") @@ -72,7 +71,7 @@ public class MockableLocationProvider extends AbstractLocationProvider { public MockableLocationProvider(Object ownerLock, Listener listener) { // using a direct executor is acceptable because all inbound calls are delegated to the // actual provider implementations which will use their own executors - super(DIRECT_EXECUTOR, Collections.emptySet()); + super(DIRECT_EXECUTOR); mOwnerLock = ownerLock; mRequest = ProviderRequest.EMPTY_REQUEST; @@ -236,8 +235,12 @@ public class MockableLocationProvider extends AbstractLocationProvider { synchronized (mOwnerLock) { provider = mProvider; pw.println("allowed=" + getState().allowed); - pw.println("properties=" + getState().properties); - pw.println("packages=" + getState().providerPackageNames); + if (getState().identity != null) { + pw.println("identity=" + getState().identity); + } + if (getState().properties != null) { + pw.println("properties=" + getState().properties); + } pw.println("request=" + mRequest); } @@ -254,7 +257,7 @@ public class MockableLocationProvider extends AbstractLocationProvider { private final AbstractLocationProvider mListenerProvider; - private ListenerWrapper(AbstractLocationProvider listenerProvider) { + ListenerWrapper(AbstractLocationProvider listenerProvider) { mListenerProvider = listenerProvider; } diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index 1ba38cc4d999..f37992a456ac 100644 --- a/services/core/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java @@ -21,6 +21,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.content.Context; import android.location.Criteria; import android.location.Location; +import android.location.util.identity.CallerIdentity; import android.os.Bundle; import com.android.internal.location.ProviderProperties; @@ -53,7 +54,7 @@ public class PassiveProvider extends AbstractLocationProvider { public PassiveProvider(Context context) { // using a direct executor is ok because this class has no locks that could deadlock - super(DIRECT_EXECUTOR, context); + super(DIRECT_EXECUTOR, CallerIdentity.fromContext(context)); mReportLocation = false; diff --git a/services/core/java/com/android/server/location/util/listeners/GnssListenerManager.java b/services/core/java/com/android/server/location/gnss/GnssListenerManager.java index 5da3542fe651..e4c8315a3f5c 100644 --- a/services/core/java/com/android/server/location/util/listeners/GnssListenerManager.java +++ b/services/core/java/com/android/server/location/gnss/GnssListenerManager.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package com.android.server.location.util.listeners; +package com.android.server.location.gnss; import android.annotation.Nullable; -import android.location.LocationManager; import android.location.LocationManagerInternal; +import android.location.util.identity.CallerIdentity; import android.location.util.listeners.AbstractListenerManager; import android.os.Binder; import android.os.IBinder; @@ -31,9 +31,9 @@ import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import com.android.server.location.AppForegroundHelper; import com.android.server.location.AppOpsHelper; -import com.android.server.location.CallerIdentity; import com.android.server.location.SettingsHelper; import com.android.server.location.UserInfoHelper; +import com.android.server.location.util.listeners.IdentifiedRegistration; import java.util.Objects; @@ -115,6 +115,18 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface return getIdentity().userId == userId; } + boolean onLocationEnabledChanged(int userId) { + if (userId == getIdentity().userId) { + return onActiveChanged(); + } + + return false; + } + + boolean onBackgroundThrottlePackageWhitelistChanged() { + return onActiveChanged(); + } + boolean onAppOpsChanged(String packageName) { if (getIdentity().packageName.equals(packageName)) { boolean appOpsAllowed = mAppOpsHelper.checkLocationAccess(getIdentity()); @@ -144,9 +156,11 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface private boolean onActiveChanged() { synchronized (this) { + // TODO: we should be checking if the gps provider is enabled, not location boolean active = mAppOpsAllowed && (mForeground || isBackgroundRestrictionExempt(getIdentity())) - && mUserInfoHelper.isCurrentUserId(getIdentity().userId); + && mUserInfoHelper.isCurrentUserId(getIdentity().userId) + && mSettingsHelper.isLocationEnabled(getIdentity().userId); if (active != mActive) { mActive = active; return true; @@ -156,6 +170,19 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface return false; } + private boolean isBackgroundRestrictionExempt(CallerIdentity identity) { + if (identity.uid == Process.SYSTEM_UID) { + return true; + } + + if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains( + identity.packageName)) { + return true; + } + + return mLocationManagerInternal.isProvider(null, identity); + } + @Override public void binderDied() { IBinder key = mKey; @@ -193,6 +220,16 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface protected final AppForegroundHelper mAppForegroundHelper; protected final LocationManagerInternal mLocationManagerInternal; + private final UserInfoHelper.UserListener mUserChangedListener = this::onUserChanged; + private final SettingsHelper.UserSettingChangedListener mLocationEnabledChangedListener = + this::onLocationEnabledChanged; + private final SettingsHelper.GlobalSettingChangedListener + mBackgroundThrottlePackageWhitelistChangedListener = + this::onBackgroundThrottlePackageWhitelistChanged; + private final AppOpsHelper.LocationAppOpListener mAppOpsChangedListener = this::onAppOpsChanged; + private final AppForegroundHelper.AppForegroundListener mAppForegroundChangedListener = + this::onAppForegroundChanged; + protected GnssListenerManager(UserInfoHelper userInfoHelper, SettingsHelper settingsHelper, AppOpsHelper appOpsHelper, AppForegroundHelper appForegroundHelper) { mUserInfoHelper = userInfoHelper; @@ -201,10 +238,6 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface mAppForegroundHelper = appForegroundHelper; mLocationManagerInternal = Objects.requireNonNull( LocalServices.getService(LocationManagerInternal.class)); - - mUserInfoHelper.addListener(this::onUserChanged); - mAppOpsHelper.addListener(this::onAppOpsChanged); - mAppForegroundHelper.addListener(this::onAppForegroundChanged); } /** @@ -236,8 +269,27 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface protected boolean isActive(GnssRegistration registration) { // we don't have an easy listener for provider enabled status changes available, so we // check it every time, which should be pretty cheap - return registration.isActive() && mLocationManagerInternal.isProviderEnabledForUser( - LocationManager.GPS_PROVIDER, registration.getIdentity().userId); + return registration.isActive(); + } + + @Override + protected void onRegister() { + mUserInfoHelper.addListener(mUserChangedListener); + mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener); + mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener( + mBackgroundThrottlePackageWhitelistChangedListener); + mAppOpsHelper.addListener(mAppOpsChangedListener); + mAppForegroundHelper.addListener(mAppForegroundChangedListener); + } + + @Override + protected void onUnregister() { + mUserInfoHelper.removeListener(mUserChangedListener); + mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener); + mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener( + mBackgroundThrottlePackageWhitelistChangedListener); + mAppOpsHelper.removeListener(mAppOpsChangedListener); + mAppForegroundHelper.removeListener(mAppForegroundChangedListener); } private void onUserChanged(int userId, int change) { @@ -246,6 +298,14 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface } } + private void onLocationEnabledChanged(int userId) { + updateRegistrations(registration -> registration.onLocationEnabledChanged(userId)); + } + + private void onBackgroundThrottlePackageWhitelistChanged() { + updateRegistrations(GnssRegistration::onBackgroundThrottlePackageWhitelistChanged); + } + private void onAppOpsChanged(String packageName) { updateRegistrations(registration -> registration.onAppOpsChanged(packageName)); } @@ -254,19 +314,6 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface updateRegistrations(registration -> registration.onForegroundChanged(uid, foreground)); } - boolean isBackgroundRestrictionExempt(CallerIdentity callerIdentity) { - if (callerIdentity.uid == Process.SYSTEM_UID) { - return true; - } - - if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains( - callerIdentity.packageName)) { - return true; - } - - return mLocationManagerInternal.isProviderPackage(callerIdentity.packageName); - } - /** * May be overridden by subclasses to provide extra debug information. */ diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index 0067b1a43659..e5cbb7e2893f 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -17,6 +17,7 @@ package com.android.server.location.gnss; import static android.location.LocationManager.GPS_PROVIDER; +import static android.location.util.identity.CallerIdentity.PERMISSION_FINE; import android.Manifest; import android.annotation.Nullable; @@ -32,6 +33,7 @@ import android.location.IGpsGeofenceHardware; import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationManagerInternal; +import android.location.util.identity.CallerIdentity; import android.os.Binder; import android.os.RemoteException; import android.util.Log; @@ -43,7 +45,6 @@ import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.location.AppForegroundHelper; import com.android.server.location.AppOpsHelper; -import com.android.server.location.CallerIdentity; import com.android.server.location.GnssAntennaInfoProvider; import com.android.server.location.GnssBatchingProvider; import com.android.server.location.GnssCapabilitiesProvider; @@ -66,6 +67,8 @@ public class GnssManagerService { public static final String TAG = "GnssManager"; public static final boolean D = Log.isLoggable(TAG, Log.DEBUG); + private static final String FEATURE_ID = "GnssService"; + public static boolean isGnssSupported() { return GnssLocationProvider.isSupported(); } @@ -114,7 +117,7 @@ public class GnssManagerService { GnssLocationProvider gnssLocationProvider) { Preconditions.checkState(isGnssSupported()); - mContext = context; + mContext = context.createFeatureContext(FEATURE_ID); mSettingsHelper = settingsHelper; mAppOpsHelper = appOpsHelper; mAppForegroundHelper = appForegroundHelper; @@ -185,7 +188,6 @@ public class GnssManagerService { */ public int getGnssBatchSize(String packageName) { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); synchronized (mGnssBatchingLock) { return mGnssBatchingProvider.getBatchSize(); @@ -199,7 +201,6 @@ public class GnssManagerService { public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName, String featureId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); if (!mAppOpsHelper.checkLocationAccess(identity)) { @@ -224,9 +225,9 @@ public class GnssManagerService { public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName, @Nullable String featureId) { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); + identity.enforceLocationPermission(PERMISSION_FINE); synchronized (mGnssBatchingLock) { Binder.DeathRecipient deathRecipient = () -> { @@ -255,7 +256,6 @@ public class GnssManagerService { */ public void flushGnssBatch(String packageName) { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); synchronized (mGnssBatchingLock) { mGnssBatchingProvider.flush(); @@ -297,9 +297,9 @@ public class GnssManagerService { */ public void registerGnssStatusCallback(IGnssStatusListener listener, String packageName, @Nullable String featureId) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); + identity.enforceLocationPermission(PERMISSION_FINE); + mGnssStatusProvider.addListener(identity, listener); } @@ -315,12 +315,13 @@ public class GnssManagerService { */ public void addGnssMeasurementsListener(GnssRequest request, IGnssMeasurementsListener listener, String packageName, @Nullable String featureId) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); + CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); + identity.enforceLocationPermission(PERMISSION_FINE); + if (request.isFullTracking()) { mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null); } - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); mGnssMeasurementsProvider.addListener(request, identity, listener); } @@ -351,9 +352,9 @@ public class GnssManagerService { */ public void addGnssAntennaInfoListener(IGnssAntennaInfoListener listener, String packageName, @Nullable String featureId) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); + identity.enforceLocationPermission(PERMISSION_FINE); + mGnssAntennaInfoProvider.addListener(identity, listener); } @@ -371,9 +372,9 @@ public class GnssManagerService { */ public void addGnssNavigationMessageListener(IGnssNavigationMessageListener listener, String packageName, @Nullable String featureId) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null); - CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId); + identity.enforceLocationPermission(PERMISSION_FINE); + mGnssNavigationMessageProvider.addListener(identity, listener); } diff --git a/services/core/java/com/android/server/location/util/listeners/IdentifiedRegistration.java b/services/core/java/com/android/server/location/util/listeners/IdentifiedRegistration.java index 79577c93595b..132be232470f 100644 --- a/services/core/java/com/android/server/location/util/listeners/IdentifiedRegistration.java +++ b/services/core/java/com/android/server/location/util/listeners/IdentifiedRegistration.java @@ -19,11 +19,11 @@ package com.android.server.location.util.listeners; import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.annotation.Nullable; +import android.location.util.identity.CallerIdentity; import android.location.util.listeners.AbstractListenerManager; import android.os.Process; import com.android.server.FgThread; -import com.android.server.location.CallerIdentity; import java.util.Objects; import java.util.concurrent.Executor; diff --git a/services/tests/mockingservicestests/src/com/android/server/location/AppOpsHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/AppOpsHelperTest.java index 7fc10b14209b..3bbcf2135a94 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/AppOpsHelperTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/AppOpsHelperTest.java @@ -22,9 +22,8 @@ import static android.app.AppOpsManager.OP_FINE_LOCATION; import static android.app.AppOpsManager.OP_MOCK_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION; import static android.app.AppOpsManager.OP_MONITOR_LOCATION; - -import static com.android.server.location.CallerIdentity.PERMISSION_COARSE; -import static com.android.server.location.CallerIdentity.PERMISSION_FINE; +import static android.location.util.identity.CallerIdentity.PERMISSION_COARSE; +import static android.location.util.identity.CallerIdentity.PERMISSION_FINE; import static com.google.common.truth.Truth.assertThat; @@ -41,6 +40,7 @@ import static org.mockito.MockitoAnnotations.initMocks; import android.app.AppOpsManager; import android.content.Context; +import android.location.util.identity.CallerIdentity; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; @@ -105,7 +105,7 @@ public class AppOpsHelperTest { @Test public void testCheckLocationAccess() { - CallerIdentity identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + CallerIdentity identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_FINE); doReturn(MODE_ALLOWED).when( @@ -116,7 +116,7 @@ public class AppOpsHelperTest { mAppOps).checkOpNoThrow(eq(OP_FINE_LOCATION), eq(1000), eq("mypackage")); assertThat(mHelper.checkLocationAccess(identity)).isFalse(); - identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_COARSE); doReturn(MODE_ALLOWED).when( @@ -130,7 +130,7 @@ public class AppOpsHelperTest { @Test public void testNoteLocationAccess() { - CallerIdentity identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + CallerIdentity identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_FINE); doReturn(MODE_ALLOWED).when( @@ -144,7 +144,7 @@ public class AppOpsHelperTest { assertThat(mHelper.noteLocationAccess(identity)).isFalse(); - identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_COARSE); doReturn(MODE_ALLOWED).when( @@ -160,7 +160,7 @@ public class AppOpsHelperTest { @Test public void testStartLocationMonitoring() { - CallerIdentity identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + CallerIdentity identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_FINE); doReturn(MODE_ALLOWED).when( @@ -176,7 +176,7 @@ public class AppOpsHelperTest { @Test public void testStartHighPowerLocationMonitoring() { - CallerIdentity identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + CallerIdentity identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_FINE); doReturn(MODE_ALLOWED).when( @@ -194,7 +194,7 @@ public class AppOpsHelperTest { @Test public void testStopLocationMonitoring() { - CallerIdentity identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + CallerIdentity identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_FINE); mHelper.stopLocationMonitoring(identity); @@ -203,7 +203,7 @@ public class AppOpsHelperTest { @Test public void testStopHighPowerLocationMonitoring() { - CallerIdentity identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + CallerIdentity identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_FINE); mHelper.stopHighPowerLocationMonitoring(identity); @@ -212,7 +212,7 @@ public class AppOpsHelperTest { @Test public void testNoteMockLocationAccess() { - CallerIdentity identity = new CallerIdentity(1000, 1000, 1000, "mypackage", "myfeature", + CallerIdentity identity = CallerIdentity.forTest(1000, 1000, "mypackage", "myfeature", PERMISSION_FINE); doReturn(MODE_ALLOWED).when( diff --git a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java index 9b076e8edb52..6bfe566197af 100644 --- a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java @@ -35,21 +35,18 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.server.location.test.FakeProvider; +import com.android.server.location.test.ProviderListenerCapture; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.LinkedList; -import java.util.List; - @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) public class MockableLocationProviderTest { - private Object mLock; - private ListenerCapture mListener; + private ProviderListenerCapture mListener; private AbstractLocationProvider mRealProvider; private MockProvider mMockProvider; @@ -58,8 +55,8 @@ public class MockableLocationProviderTest { @Before public void setUp() { - mLock = new Object(); - mListener = new ListenerCapture(); + Object lock = new Object(); + mListener = new ProviderListenerCapture(lock); mRealProvider = spy(new FakeProvider()); mMockProvider = spy(new MockProvider(new ProviderProperties( @@ -71,9 +68,10 @@ public class MockableLocationProviderTest { true, true, Criteria.POWER_LOW, - Criteria.ACCURACY_FINE))); + Criteria.ACCURACY_FINE) + )); - mProvider = new MockableLocationProvider(mLock, mListener); + mProvider = new MockableLocationProvider(lock, mListener); mProvider.setRealProvider(mRealProvider); } @@ -170,34 +168,4 @@ public class MockableLocationProviderTest { mMockProvider.reportLocation(mockLocation); assertThat(mListener.getNextLocation()).isEqualTo(mockLocation); } - - private class ListenerCapture implements AbstractLocationProvider.Listener { - - private final LinkedList<AbstractLocationProvider.State> mNewStates = new LinkedList<>(); - private final LinkedList<Location> mLocations = new LinkedList<>(); - - @Override - public void onStateChanged(AbstractLocationProvider.State oldState, - AbstractLocationProvider.State newState) { - assertThat(Thread.holdsLock(mLock)).isTrue(); - mNewStates.add(newState); - } - - private AbstractLocationProvider.State getNextNewState() { - return mNewStates.poll(); - } - - @Override - public void onReportLocation(Location location) { - assertThat(Thread.holdsLock(mLock)).isTrue(); - mLocations.add(location); - } - - private Location getNextLocation() { - return mLocations.poll(); - } - - @Override - public void onReportLocation(List<Location> locations) {} - } } diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java index dd196312f763..a8635d85f62c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java @@ -55,6 +55,7 @@ import android.location.IGnssStatusListener; import android.location.INetInitiatedListener; import android.location.Location; import android.location.LocationManagerInternal; +import android.location.util.identity.CallerIdentity; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; @@ -64,7 +65,6 @@ import android.os.RemoteException; import com.android.server.LocalServices; import com.android.server.location.AppForegroundHelper; import com.android.server.location.AppOpsHelper; -import com.android.server.location.CallerIdentity; import com.android.server.location.GnssAntennaInfoProvider; import com.android.server.location.GnssAntennaInfoProvider.GnssAntennaInfoProviderNative; import com.android.server.location.GnssBatchingProvider; @@ -148,6 +148,7 @@ public class GnssManagerServiceTest { MockitoAnnotations.initMocks(this); GnssLocationProvider.setIsSupportedForTest(true); + when(mMockContext.createFeatureContext(anyString())).thenReturn(mMockContext); when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn( Context.APP_OPS_SERVICE); when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn( @@ -158,6 +159,7 @@ public class GnssManagerServiceTest { enableLocationPermissions(); when(mUserInfoHelper.isCurrentUserId(anyInt())).thenReturn(true); + when(mSettingsHelper.isLocationEnabled(anyInt())).thenReturn(true); when(mAppOpsHelper.checkLocationAccess(any(CallerIdentity.class))).thenReturn(true); when(mAppOpsHelper.noteLocationAccess(any(CallerIdentity.class))).thenReturn(true); when(mAppForegroundHelper.isAppForeground(anyInt())).thenReturn(true); @@ -297,7 +299,7 @@ public class GnssManagerServiceTest { private void enableLocationPermissions() { Mockito.doThrow(new SecurityException()).when( - mMockContext).enforceCallingPermission( + mMockContext).enforceCallingOrSelfPermission( AdditionalMatchers.and( AdditionalMatchers.not(eq(Manifest.permission.LOCATION_HARDWARE)), AdditionalMatchers.not(eq(Manifest.permission.ACCESS_FINE_LOCATION))), @@ -305,6 +307,12 @@ public class GnssManagerServiceTest { when(mMockContext.checkPermission( eq(android.Manifest.permission.LOCATION_HARDWARE), anyInt(), anyInt())).thenReturn( PackageManager.PERMISSION_GRANTED); + when(mMockContext.checkPermission( + eq(Manifest.permission.ACCESS_FINE_LOCATION), anyInt(), anyInt())).thenReturn( + PackageManager.PERMISSION_GRANTED); + when(mMockContext.checkPermission( + eq(Manifest.permission.ACCESS_COARSE_LOCATION), anyInt(), anyInt())).thenReturn( + PackageManager.PERMISSION_GRANTED); // AppOpsManager will return true if OP_FINE_LOCATION is checked when(mAppOpsManager.checkOpNoThrow(anyInt(), anyInt(), anyString())).thenAnswer( @@ -324,6 +332,10 @@ public class GnssManagerServiceTest { Mockito.doThrow(new SecurityException()).when( mMockContext).enforceCallingOrSelfPermission(anyString(), nullable(String.class)); + when(mMockContext.checkPermission( + anyString(), anyInt(), anyInt())).thenReturn( + PackageManager.PERMISSION_DENIED); + when(mAppOpsManager.checkOpNoThrow(anyInt(), anyInt(), anyString())).thenReturn(AppOpsManager.MODE_ERRORED); diff --git a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java index 5943f67494f8..2f1a20b2cbb1 100644 --- a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java @@ -23,12 +23,11 @@ import com.android.server.location.AbstractLocationProvider; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Collections; public class FakeProvider extends AbstractLocationProvider { public FakeProvider() { - super(Runnable::run, Collections.emptySet()); + super(Runnable::run); } @Override diff --git a/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java b/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java new file mode 100644 index 000000000000..5e5ed11bd0e7 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 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.test; + +import static com.google.common.truth.Truth.assertThat; + +import android.location.Location; + +import com.android.server.location.AbstractLocationProvider; + +import java.util.LinkedList; +import java.util.List; + +public class ProviderListenerCapture implements AbstractLocationProvider.Listener { + + private final Object mLock; + private final LinkedList<AbstractLocationProvider.State> mNewStates = new LinkedList<>(); + private final LinkedList<Location> mLocations = new LinkedList<>(); + + public ProviderListenerCapture(Object lock) { + mLock = lock; + } + + @Override + public void onStateChanged(AbstractLocationProvider.State oldState, + AbstractLocationProvider.State newState) { + assertThat(Thread.holdsLock(mLock)).isTrue(); + mNewStates.add(newState); + } + + public AbstractLocationProvider.State getNextNewState() { + return mNewStates.poll(); + } + + @Override + public void onReportLocation(Location location) { + assertThat(Thread.holdsLock(mLock)).isTrue(); + mLocations.add(location); + } + + public Location getNextLocation() { + return mLocations.poll(); + } + + @Override + public void onReportLocation(List<Location> locations) {} +} |