diff options
author | 2020-03-04 23:05:49 +0000 | |
---|---|---|
committer | 2020-03-04 23:05:49 +0000 | |
commit | 1eb8014bd2d07ad03de3ee17243bb48b1e513297 (patch) | |
tree | 2e059301b8790e349581425a9bd46bff6cacd107 /location | |
parent | e445b758067f0fbe0796fab069a04aed2e1d1d06 (diff) | |
parent | 470c8f6a3f5a8f6d2c877019d1c22fc619eccad6 (diff) |
Merge "Give location providers a known identity"
Diffstat (limited to 'location')
8 files changed, 405 insertions, 52 deletions
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index b7346308042f..6f543c31d9a3 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -96,7 +96,7 @@ interface ILocationManager List<String> getProviders(in Criteria criteria, boolean enabledOnly); String getBestProvider(in Criteria criteria, boolean enabledOnly); ProviderProperties getProviderProperties(String provider); - boolean isProviderPackage(String packageName); + boolean isProviderPackage(String provider, String packageName); List<String> getProviderPackages(String provider); void setExtraLocationControllerPackage(String packageName); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 7523f07674ea..0bf7add422cf 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -64,7 +64,6 @@ import com.android.internal.location.ProviderProperties; import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledRunnable; -import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; @@ -313,10 +312,9 @@ public class LocationManager { private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000; - private final Context mContext; - + final Context mContext; @UnsupportedAppUsage - private final ILocationManager mService; + final ILocationManager mService; @GuardedBy("mListeners") private final ArrayMap<LocationListener, LocationListenerTransport> mListeners = @@ -1403,15 +1401,36 @@ public class LocationManager { * otherwise. * * @hide + * @deprecated Prefer {@link #isProviderPackage(String, String)} instead. */ + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String packageName) { try { - return mService.isProviderPackage(packageName); + return mService.isProviderPackage(null, packageName); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return false; + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns true if the given provider corresponds to the given package name. If the given + * provider is null, this will return true if any provider corresponds to the given package + * name. + * + * @param provider a provider listed by {@link #getAllProviders()} or null + * @param packageName the package name to test if it is a provider + * @return true if the given arguments correspond to a provider + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) + public boolean isProviderPackage(@Nullable String provider, @NonNull String packageName) { + try { + return mService.isProviderPackage(provider, packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -1420,16 +1439,17 @@ public class LocationManager { * and an empty list if no package is associated with the provider. * * @hide + * @deprecated Prefer {@link #isProviderPackage(String, String)} instead. */ @TestApi + @Deprecated @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) @Nullable public List<String> getProviderPackages(@NonNull String provider) { try { return mService.getProviderPackages(provider); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return Collections.emptyList(); + throw e.rethrowFromSystemServer(); } } @@ -2470,7 +2490,7 @@ public class LocationManager { @Nullable private ICancellationSignal mRemoteCancellationSignal; - private GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer) { + GetCurrentLocationTransport(Executor executor, Consumer<Location> consumer) { Preconditions.checkArgument(executor != null, "illegal null executor"); Preconditions.checkArgument(consumer != null, "illegal null consumer"); mExecutor = executor; @@ -2595,7 +2615,7 @@ public class LocationManager { private final LocationListener mListener; @Nullable private volatile Executor mExecutor = null; - private LocationListenerTransport(@NonNull LocationListener listener) { + LocationListenerTransport(@NonNull LocationListener listener) { Preconditions.checkArgument(listener != null, "invalid null listener"); mListener = listener; } @@ -2769,7 +2789,7 @@ public class LocationManager { private final OnNmeaMessageListener mListener; - private NmeaAdapter(OnNmeaMessageListener listener) { + NmeaAdapter(OnNmeaMessageListener listener) { mListener = listener; } @@ -2783,7 +2803,7 @@ public class LocationManager { private final GpsStatus.Listener mGpsListener; - private GpsAdapter(GpsStatus.Listener gpsListener) { + GpsAdapter(GpsStatus.Listener gpsListener) { mGpsListener = gpsListener; } @@ -2813,8 +2833,11 @@ public class LocationManager { private @Nullable IGnssStatusListener mListenerTransport; - private volatile @Nullable GnssStatus mGnssStatus; - private volatile int mTtff; + volatile @Nullable GnssStatus mGnssStatus; + volatile int mTtff; + + GnssStatusListenerManager() { + } public GnssStatus getGnssStatus() { return mGnssStatus; @@ -2862,6 +2885,9 @@ public class LocationManager { } private class GnssStatusListener extends IGnssStatusListener.Stub { + GnssStatusListener() { + } + @Override public void onGnssStarted() { deliverToListeners(GnssStatus.Callback::onStarted); @@ -2905,6 +2931,9 @@ public class LocationManager { @Nullable private IGnssMeasurementsListener mListenerTransport; + GnssMeasurementsListenerManager() { + } + @Override protected boolean registerService(GnssRequest request) { Preconditions.checkState(mListenerTransport == null); @@ -2947,6 +2976,9 @@ public class LocationManager { } private class GnssMeasurementsListener extends IGnssMeasurementsListener.Stub { + GnssMeasurementsListener() { + } + @Override public void onGnssMeasurementsReceived(final GnssMeasurementsEvent event) { deliverToListeners((callback) -> callback.onGnssMeasurementsReceived(event)); @@ -2965,6 +2997,9 @@ public class LocationManager { @Nullable private IGnssNavigationMessageListener mListenerTransport; + GnssNavigationMessageListenerManager() { + } + @Override protected boolean registerService(Void ignored) { Preconditions.checkState(mListenerTransport == null); @@ -2994,6 +3029,9 @@ public class LocationManager { } private class GnssNavigationMessageListener extends IGnssNavigationMessageListener.Stub { + GnssNavigationMessageListener() { + } + @Override public void onGnssNavigationMessageReceived(GnssNavigationMessage event) { deliverToListeners((listener) -> listener.onGnssNavigationMessageReceived(event)); @@ -3012,6 +3050,9 @@ public class LocationManager { @Nullable private IGnssAntennaInfoListener mListenerTransport; + GnssAntennaInfoListenerManager() { + } + @Override protected boolean registerService(Void ignored) { Preconditions.checkState(mListenerTransport == null); @@ -3041,6 +3082,9 @@ public class LocationManager { } private class GnssAntennaInfoListener extends IGnssAntennaInfoListener.Stub { + GnssAntennaInfoListener() { + } + @Override public void onGnssAntennaInfoReceived(List<GnssAntennaInfo> infos) { deliverToListeners(callback -> callback.onGnssAntennaInfoReceived(infos)); @@ -3055,6 +3099,9 @@ public class LocationManager { @Nullable private IBatchedLocationCallback mListenerTransport; + BatchedLocationCallbackManager() { + } + @Override protected boolean registerService(Void ignored) { Preconditions.checkState(mListenerTransport == null); @@ -3083,6 +3130,9 @@ public class LocationManager { } private class BatchedLocationCallback extends IBatchedLocationCallback.Stub { + BatchedLocationCallback() { + } + @Override public void onLocationBatch(List<Location> locations) { deliverToListeners((listener) -> listener.onLocationBatch(locations)); diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java index 6006d5079b07..542737b479e2 100644 --- a/location/java/android/location/LocationManagerInternal.java +++ b/location/java/android/location/LocationManagerInternal.java @@ -18,6 +18,8 @@ package android.location; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.location.util.identity.CallerIdentity; /** * Location manager local system service interface. @@ -36,13 +38,14 @@ public abstract class LocationManagerInternal { public abstract boolean isProviderEnabledForUser(@NonNull String provider, int userId); /** - * Returns true if the given package belongs to a location provider, and so should be afforded - * some special privileges. + * Returns true if the given identity is a location provider. * - * @param packageName The package name to check - * @return True is the given package belongs to a location provider, false otherwise + * @param provider The provider to check, or null to check every provider + * @param identity The identity to match + * @return True if the given identity matches either the given location provider or any + * provider, and false otherwise */ - public abstract boolean isProviderPackage(@NonNull String packageName); + public abstract boolean isProvider(@Nullable String provider, @NonNull CallerIdentity identity); /** * Should only be used by GNSS code. diff --git a/location/java/android/location/util/identity/CallerIdentity.java b/location/java/android/location/util/identity/CallerIdentity.java new file mode 100644 index 000000000000..15641eb3bb6f --- /dev/null +++ b/location/java/android/location/util/identity/CallerIdentity.java @@ -0,0 +1,261 @@ +/* + * 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 android.location.util.identity; + +import static android.Manifest.permission.ACCESS_COARSE_LOCATION; +import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + +import android.annotation.IntDef; +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; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Identifying information on a caller. + * + * @hide + */ +public final class CallerIdentity { + + public static final int PERMISSION_NONE = 0; + public static final int PERMISSION_COARSE = 1; + public static final int PERMISSION_FINE = 2; + + @IntDef({PERMISSION_NONE, PERMISSION_COARSE, PERMISSION_FINE}) + @Retention(RetentionPolicy.SOURCE) + public @interface PermissionLevel {} + + /** + * Converts the given permission level to the corresponding permission. + */ + public static String asPermission(@PermissionLevel int permissionLevel) { + switch (permissionLevel) { + case PERMISSION_COARSE: + return ACCESS_COARSE_LOCATION; + case PERMISSION_FINE: + return ACCESS_FINE_LOCATION; + default: + throw new IllegalArgumentException(); + } + } + + /** + * Converts the given permission level to the corresponding appop. + */ + public static int asAppOp(@PermissionLevel int permissionLevel) { + switch (permissionLevel) { + case PERMISSION_COARSE: + return AppOpsManager.OP_COARSE_LOCATION; + case PERMISSION_FINE: + return AppOpsManager.OP_FINE_LOCATION; + default: + throw new IllegalArgumentException(); + } + } + + /** + * Construct a CallerIdentity for test purposes. + */ + @VisibleForTesting + public static CallerIdentity forTest(int uid, int pid, String packageName, + @Nullable String featureId, @PermissionLevel int permissionLevel) { + + return new CallerIdentity(uid, pid, packageName, featureId, + permissionLevel); + } + + /** + * Creates a CallerIdentity for the current process and context. + */ + public static CallerIdentity fromContext(Context context) { + return new CallerIdentity(Process.myUid(), Process.myPid(), + context.getPackageName(), context.getFeatureId(), + getPermissionLevel(context, Binder.getCallingPid(), Binder.getCallingUid())); + } + + /** + * Creates a CallerIdentity from the current binder identity, using the given package and + * feature id. The package will be checked to enforce it belongs to the calling uid, and a + * security exception will be thrown if it is invalid. + */ + public static CallerIdentity fromBinder(Context context, String packageName, + @Nullable String featureId) { + int uid = Binder.getCallingUid(); + if (!ArrayUtils.contains(context.getPackageManager().getPackagesForUid(uid), packageName)) { + throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid); + } + + return fromBinderUnsafe(context, packageName, featureId); + } + + /** + * Creates a CallerIdentity from the current binder identity, using the given package and + * feature id. The package will not be checked to enforce that it belongs to the calling uid - + * this method should only be used if the package will be validated by some other means, such as + * an appops call. + */ + public static CallerIdentity fromBinderUnsafe(Context context, String packageName, + @Nullable String featureId) { + return new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), + 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, + @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, + @PermissionLevel int desiredPermissionLevel) { + return checkLocationPermission( + getPermissionLevel(context, Binder.getCallingPid(), Binder.getCallingUid()), + desiredPermissionLevel); + } + + private static void enforceLocationPermission(int uid, @PermissionLevel int permissionLevel, + @PermissionLevel int desiredPermissionLevel) { + if (checkLocationPermission(permissionLevel, desiredPermissionLevel)) { + return; + } + + 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, + @PermissionLevel int desiredPermissionLevel) { + return permissionLevel >= desiredPermissionLevel; + } + + 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.checkPermission(ACCESS_COARSE_LOCATION, pid, uid) == PERMISSION_GRANTED) { + return PERMISSION_COARSE; + } + + return PERMISSION_NONE; + } + + /** The calling UID. */ + public final int uid; + + /** The calling PID. */ + public final int pid; + + /** The calling user. */ + public final int userId; + + /** The calling package name. */ + public final String packageName; + + /** The calling feature id. */ + public final @Nullable String featureId; + + /** + * The calling location permission level. This field should only be used for validating + * permissions for API access. It should not be used for validating permissions for location + * access - that must be done through appops. + */ + public final @PermissionLevel int permissionLevel; + + private CallerIdentity(int uid, int pid, String packageName, + @Nullable String featureId, @PermissionLevel int permissionLevel) { + this.uid = uid; + this.pid = pid; + this.userId = UserHandle.getUserId(uid); + this.packageName = Objects.requireNonNull(packageName); + this.featureId = featureId; + this.permissionLevel = Preconditions.checkArgumentInRange(permissionLevel, PERMISSION_NONE, + PERMISSION_FINE, "permissionLevel"); + } + + /** + * Throws a security exception if the CallerIdentity does not hold a location permission. + */ + public void enforceLocationPermission(@PermissionLevel int desiredPermissionLevel) { + enforceLocationPermission(uid, permissionLevel, desiredPermissionLevel); + } + + @Override + public String toString() { + int length = 10 + packageName.length(); + if (featureId != null) { + length += featureId.length(); + } + + StringBuilder builder = new StringBuilder(length); + builder.append(pid).append("/").append(packageName); + if (featureId != null) { + builder.append("["); + if (featureId.startsWith(packageName)) { + builder.append(featureId.substring(packageName.length())); + } else { + builder.append(featureId); + } + builder.append("]"); + } + return builder.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof CallerIdentity)) { + return false; + } + CallerIdentity that = (CallerIdentity) o; + return uid == that.uid + && pid == that.pid + && packageName.equals(that.packageName) + && Objects.equals(featureId, that.featureId); + } + + @Override + public int hashCode() { + return Objects.hash(uid, pid, packageName, featureId); + } +} diff --git a/location/java/android/location/util/listeners/AbstractListenerManager.java b/location/java/android/location/util/listeners/AbstractListenerManager.java index facb74766f2c..09c1eb2ae153 100644 --- a/location/java/android/location/util/listeners/AbstractListenerManager.java +++ b/location/java/android/location/util/listeners/AbstractListenerManager.java @@ -156,8 +156,15 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, // this class does not support adding listeners reentrantly Preconditions.checkState(!mReentrancyGuard.isReentrant()); + if (mRegistrations.isEmpty()) { + onRegister(); + } + if (!registration.register()) { registration.unregister(); + if (mRegistrations.isEmpty()) { + onUnregister(); + } return; } @@ -210,6 +217,10 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, onRegistrationRemoved(key, registration); registration.unregister(); updateService(); + + if (mRegistrations.isEmpty()) { + onUnregister(); + } } /** @@ -316,10 +327,26 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, protected abstract void unregisterService(); /** + * Invoked before the first registration occurs. This is a convenient entry point for + * registering listeners, etc, which only need to be present while there are any registrations. + * This method will always be invoked before a corresponding call to + * {@link Registration#onRegister()} and {@link #onActive()}. + */ + protected void onRegister() {} + + /** + * Invoked after the last unregistration occurs. This is a convenient entry point for + * unregistering listeners, etc, which only need to be present while there are any + * registrations. This method will always be after a corresponding call to + * {@link Registration#onUnregister()} and {@link #onInactive()}. + */ + protected void onUnregister() {} + + /** * Invoked when the listener goes from having no active registrations to having some active * registrations. This is a convenient entry point for registering listeners, etc, which only * need to be present while there are active registrations. This method will always be invoked - * before a corrosponding call to {@link #registerService(Object)}. + * before a corresponding call to {@link #registerService(Object)}. */ protected void onActive() {} @@ -327,7 +354,7 @@ public abstract class AbstractListenerManager<TKey, TRequest, TListener, * Invoked when the listener goes from having some active registrations to having no active * registrations. This is a convenient entry point for unregistering listeners, etc, which only * need to be present while there are active registrations. This method will always be invoked - * after a corrosponding call to {@link #unregisterService()}. + * after a corresponding call to {@link #unregisterService()}. */ protected void onInactive() {} diff --git a/location/java/com/android/internal/location/ILocationProviderManager.aidl b/location/java/com/android/internal/location/ILocationProviderManager.aidl index 439039148773..1bdedd57f321 100644 --- a/location/java/com/android/internal/location/ILocationProviderManager.aidl +++ b/location/java/com/android/internal/location/ILocationProviderManager.aidl @@ -26,7 +26,7 @@ import com.android.internal.location.ProviderProperties; */ interface ILocationProviderManager { - void onSetAdditionalProviderPackages(in List<String> packageNames); + void onSetFeatureId(String featureId); @UnsupportedAppUsage void onSetAllowed(boolean allowed); diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt index 9cc30d0d751e..4d0acea15263 100644 --- a/location/lib/api/current.txt +++ b/location/lib/api/current.txt @@ -7,7 +7,8 @@ package com.android.location.provider { } public abstract class LocationProviderBase { - ctor public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled); + ctor @Deprecated public LocationProviderBase(String, com.android.location.provider.ProviderPropertiesUnbundled); + ctor @RequiresApi(android.os.Build.VERSION_CODES.R) public LocationProviderBase(android.content.Context, String, com.android.location.provider.ProviderPropertiesUnbundled); method public android.os.IBinder getBinder(); method @RequiresApi(android.os.Build.VERSION_CODES.R) public boolean isAllowed(); method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public boolean isEnabled(); @@ -20,11 +21,11 @@ package com.android.location.provider { method protected boolean onSendExtraCommand(@Nullable String, @Nullable android.os.Bundle); method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource); method public void reportLocation(android.location.Location); - method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>); + method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setAdditionalProviderPackages(java.util.List<java.lang.String>); method @RequiresApi(android.os.Build.VERSION_CODES.R) public void setAllowed(boolean); method @Deprecated @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setEnabled(boolean); method @RequiresApi(android.os.Build.VERSION_CODES.Q) public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled); - field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; + field @Deprecated public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation"; field public static final String FUSED_PROVIDER = "fused"; } diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java index d3fb58fe257e..624e8d1b702b 100644 --- a/location/lib/java/com/android/location/provider/LocationProviderBase.java +++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java @@ -39,7 +39,6 @@ import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.List; /** @@ -65,7 +64,10 @@ public abstract class LocationProviderBase { * Bundle key for a version of the location containing no GPS data. * Allows location providers to flag locations as being safe to * feed to LocationFudger. + * + * @deprecated Do not use from Android R onwards. */ + @Deprecated public static final String EXTRA_NO_GPS_LOCATION = Location.EXTRA_NO_GPS_LOCATION; /** @@ -76,8 +78,9 @@ public abstract class LocationProviderBase { */ public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER; - private final String mTag; - private final IBinder mBinder; + final String mTag; + final String mFeatureId; + final IBinder mBinder; /** * This field may be removed in the future, do not rely on it. @@ -90,13 +93,30 @@ public abstract class LocationProviderBase { protected final ILocationManager mLocationManager; // write locked on mBinder, read lock is optional depending on atomicity requirements - @Nullable private volatile ILocationProviderManager mManager; - private volatile ProviderProperties mProperties; - private volatile boolean mAllowed; - private final ArrayList<String> mAdditionalProviderPackages; + @Nullable + volatile ILocationProviderManager mManager; + volatile ProviderProperties mProperties; + volatile boolean mAllowed; + /** + * @deprecated Prefer + * {@link #LocationProviderBase(Context, String, ProviderPropertiesUnbundled)}. + */ + @Deprecated public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) { + this(null, tag, properties); + } + + /** + * This constructor associates the feature id of the given context with this location provider. + * The location service may afford special privileges to incoming calls identified as belonging + * to this location provider. + */ + @RequiresApi(VERSION_CODES.R) + public LocationProviderBase(Context context, String tag, + ProviderPropertiesUnbundled properties) { mTag = tag; + mFeatureId = context != null ? context.getFeatureId() : null; mBinder = new Service(); mLocationManager = ILocationManager.Stub.asInterface( @@ -105,7 +125,6 @@ public abstract class LocationProviderBase { mManager = null; mProperties = properties.getProviderProperties(); mAllowed = true; - mAdditionalProviderPackages = new ArrayList<>(0); } public IBinder getBinder() { @@ -183,23 +202,12 @@ public abstract class LocationProviderBase { * another package may issue location requests on behalf of this package in the course of * providing location. This will inform location services to treat the other packages as * location providers as well. + * + * @deprecated On Android R and above this has no effect. */ + @Deprecated @RequiresApi(VERSION_CODES.Q) - public void setAdditionalProviderPackages(List<String> packageNames) { - synchronized (mBinder) { - mAdditionalProviderPackages.clear(); - mAdditionalProviderPackages.addAll(packageNames); - } - - ILocationProviderManager manager = mManager; - if (manager != null) { - try { - manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); - } catch (RemoteException | RuntimeException e) { - Log.w(mTag, e); - } - } - } + public void setAdditionalProviderPackages(List<String> packageNames) {} /** * @deprecated Use {@link #isAllowed()} instead. @@ -317,12 +325,15 @@ public abstract class LocationProviderBase { private final class Service extends ILocationProvider.Stub { + Service() { + } + @Override public void setLocationProviderManager(ILocationProviderManager manager) { synchronized (mBinder) { try { - if (!mAdditionalProviderPackages.isEmpty()) { - manager.onSetAdditionalProviderPackages(mAdditionalProviderPackages); + if (mFeatureId != null) { + manager.onSetFeatureId(mFeatureId); } manager.onSetProperties(mProperties); manager.onSetAllowed(mAllowed); |