From 470c8f6a3f5a8f6d2c877019d1c22fc619eccad6 Mon Sep 17 00:00:00 2001 From: Soonil Nagarkar Date: Wed, 4 Mar 2020 12:18:57 -0800 Subject: [PATCH] Give location providers a known identity Providers no longer need the ability to specify additional packages, this can be replaced with tracking the provider identity. In addition, move CallerIdentity into the client space, and fix some minor GNSS bugs. Bug: 149839935 Test: atest LocationProviderTest Change-Id: Ide107abc61531946b20d2ac50cd9555fc215ef03 --- api/system-current.txt | 3 +- api/test-current.txt | 2 +- core/res/AndroidManifest.xml | 5 +- core/res/res/values/strings.xml | 2 + .../android/location/ILocationManager.aidl | 2 +- .../android/location/LocationManager.java | 80 ++++++-- .../location/LocationManagerInternal.java | 13 +- .../util/identity}/CallerIdentity.java | 81 ++++++--- .../listeners/AbstractListenerManager.java | 31 +++- .../location/ILocationProviderManager.aidl | 2 +- location/lib/api/current.txt | 7 +- .../provider/LocationProviderBase.java | 61 ++++--- .../location/fused/FusedLocationProvider.java | 34 +--- .../fused/tests/FusedLocationServiceTest.java | 3 +- .../server/LocationManagerService.java | 88 ++++++--- .../server/LocationManagerServiceUtils.java | 3 +- .../location/AbstractLocationProvider.java | 70 ++++--- .../android/server/location/AppOpsHelper.java | 3 +- .../server/location/GeofenceManager.java | 1 + .../server/location/GeofenceState.java | 1 + .../location/GnssAntennaInfoProvider.java | 3 +- .../server/location/GnssLocationProvider.java | 3 +- .../location/GnssMeasurementsProvider.java | 3 +- .../GnssNavigationMessageProvider.java | 3 +- .../server/location/GnssStatusProvider.java | 3 +- .../location/LocationPermissionUtil.java | 62 ------- .../location/LocationProviderProxy.java | 171 +++++++++--------- .../android/server/location/MockProvider.java | 3 +- .../location/MockableLocationProvider.java | 17 +- .../server/location/PassiveProvider.java | 3 +- .../GnssListenerManager.java | 93 +++++++--- .../location/gnss/GnssManagerService.java | 29 +-- .../listeners/IdentifiedRegistration.java | 2 +- .../server/location/AppOpsHelperTest.java | 24 +-- .../MockableLocationProviderTest.java | 46 +---- .../location/gnss/GnssManagerServiceTest.java | 16 +- .../server/location/test/FakeProvider.java | 3 +- .../test/ProviderListenerCapture.java | 61 +++++++ 38 files changed, 601 insertions(+), 436 deletions(-) rename {services/core/java/com/android/server/location => location/java/android/location/util/identity}/CallerIdentity.java (70%) delete mode 100644 services/core/java/com/android/server/location/LocationPermissionUtil.java rename services/core/java/com/android/server/location/{util/listeners => gnss}/GnssListenerManager.java (74%) rename services/tests/{servicestests => mockingservicestests}/src/com/android/server/location/MockableLocationProviderTest.java (81%) rename services/tests/{servicestests => mockingservicestests}/src/com/android/server/location/test/FakeProvider.java (93%) create mode 100644 services/tests/mockingservicestests/src/com/android/server/location/test/ProviderListenerCapture.java diff --git a/api/system-current.txt b/api/system-current.txt index 05fb00abc1bab..d1dbb7476773f 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 b0666aeaa4c77..6678e2ac6726e 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); method @NonNull public String[] getIgnoreSettingsWhitelist(); - method @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List getProviderPackages(@NonNull String); + method @Deprecated @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List getProviderPackages(@NonNull String); method @NonNull public java.util.List 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 885117018c50f..c2dbf4711ee0f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4987,9 +4987,10 @@ + + - + diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index ce5b8afa4ee06..7a5d7c7c73aef 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -425,6 +425,8 @@ Country Detector Location Service + + GNSS Service Sensor Notification Service diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 6be770ea2c7b0..5a7c91caaf760 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -95,7 +95,7 @@ interface ILocationManager List 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 getProviderPackages(String provider); void setExtraLocationControllerPackage(String packageName); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 7523f07674ea4..0bf7add422cfe 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 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 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 consumer) { + GetCurrentLocationTransport(Executor executor, Consumer 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 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 locations) { deliverToListeners((listener) -> listener.onLocationBatch(locations)); diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java index 6006d5079b07e..542737b479e2f 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 similarity index 70% rename from services/core/java/com/android/server/location/CallerIdentity.java rename to location/java/android/location/util/identity/CallerIdentity.java index b84fd13415fc0..15641eb3bb6f5 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 { @@ -76,6 +79,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 @@ -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 facb74766f2c6..09c1eb2ae1539 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 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 9cc30d0d751e3..4d0acea15263e 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); + method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List); 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 d3fb58fe257e2..624e8d1b702b2 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 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 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 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 fb7dbc8aca5c6..781efc1184293 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 d1a379afa25eb..38f3bcdb62fe1 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 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 55ccc8a2ad4b0..9d63a6cfe16d3 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 mProviderManagers = + final CopyOnWriteArrayList 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 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 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 getProviderPackages(String providerName) { + public List 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; } @@ -2715,6 +2737,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(), @@ -2729,12 +2753,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 f50a885dd20c1..7ffbc31bc9491 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 e9d94a5430fe9..d45ab561f3c6f 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 providerPackageNames; + @Nullable public final CallerIdentity identity; - private State(boolean allowed, ProviderProperties properties, - Set 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 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 operator) { + InternalState withState(UnaryOperator 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 mInternalState; - protected AbstractLocationProvider(Executor executor, Context context) { - this(executor, Collections.singleton(context.getPackageName())); - } - protected AbstractLocationProvider(Executor executor, Set packageNames) { + protected AbstractLocationProvider(Executor executor) { mExecutor = executor; mInternalState = new AtomicReference<>( - new InternalState(null, State.EMPTY_STATE.withProviderPackageNames(packageNames))); + new InternalState(null, State.EMPTY_STATE)); + } + + protected AbstractLocationProvider(Executor executor, CallerIdentity identity) { + mExecutor = executor; + mInternalState = new AtomicReference<>( + 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 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 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 9c279166ac8a7..1df40f2e9ffcb 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 195b059b7374d..1607283de33bd 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 13318bfa6492c..7d0a90b0f589d 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 4926a1c7f6e05..1dc34556402a0 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 8984ba8e034b7..010e86960a142 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 c3e055d2efb2c..52391d3e55a81 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 10f7c4cb34eb2..85d3b66d42137 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 7d9ff2c55907d..ab2c40e0478c6 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 80b93b5e8ef65..0000000000000 --- 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. - * - *

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. - *

    - *
  • {@link android.Manifest.permission#LOCATION_HARDWARE} - *
  • {@link android.Manifest.permission#UPDATE_APP_OPS_STATS} - *
- * - *

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 87208a7f36f53..696b571f419ac 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 packageNames) { - int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size()); - ArraySet allPackages = new ArraySet<>(maxCount + 1); - for (String packageName : packageNames) { - if (packageNames.size() >= maxCount) { - return; - } + final Object mLock = new Object(); - 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); - } - }; - - // 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 5ec06ca255810..160e641aee9ea 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 0f358e97bc98a..54af1c84d36b4 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 1ba38cc4d999d..f37992a456acf 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 similarity index 74% rename from services/core/java/com/android/server/location/util/listeners/GnssListenerManager.java rename to services/core/java/com/android/server/location/gnss/GnssListenerManager.java index 5da3542fe6513..e4c8315a3f5c2 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 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 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 0067b1a436599..e5cbb7e2893f5 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 79577c93595b2..132be232470f0 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 7fc10b14209b7..3bbcf2135a945 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 similarity index 81% rename from services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java rename to services/tests/mockingservicestests/src/com/android/server/location/MockableLocationProviderTest.java index 9b076e8edb52a..6bfe566197af2 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 mNewStates = new LinkedList<>(); - private final LinkedList 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 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 dd196312f7631..a8635d85f62c1 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 similarity index 93% rename from services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java rename to services/tests/mockingservicestests/src/com/android/server/location/test/FakeProvider.java index 5943f67494f81..2f1a20b2cbb16 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 0000000000000..5e5ed11bd0e75 --- /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 mNewStates = new LinkedList<>(); + private final LinkedList 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 locations) {} +}