Merge "Give location providers a known identity"

This commit is contained in:
Soonil Nagarkar
2020-03-04 23:05:49 +00:00
committed by Android (Google) Code Review
38 changed files with 601 additions and 436 deletions

View File

@@ -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);

View File

@@ -1387,7 +1387,7 @@ package android.location {
method @NonNull public String[] getBackgroundThrottlingWhitelist();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void getCurrentLocation(@NonNull android.location.LocationRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.location.Location>);
method @NonNull public String[] getIgnoreSettingsWhitelist();
method @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
method @Deprecated @Nullable @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public java.util.List<java.lang.String> getProviderPackages(@NonNull String);
method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);

View File

@@ -4987,9 +4987,10 @@
<feature android:featureId="CountryDetector" android:label="@string/country_detector"/>
<!-- Feature Id for Location service. -->
<feature android:featureId="LocationService" android:label="@string/location_service"/>
<!-- Feature Id for Gnss service. -->
<feature android:featureId="GnssService" android:label="@string/gnss_service"/>
<!-- Feature Id for Sensor Notification service. -->
<feature android:featureId="SensorNotificationService"
android:label="@string/sensor_notification_service"/>
<feature android:featureId="SensorNotificationService" android:label="@string/sensor_notification_service"/>
<!-- Feature Id for Twilight service. -->
<feature android:featureId="TwilightService" android:label="@string/twilight_service"/>

View File

@@ -425,6 +425,8 @@
<string name="country_detector">Country Detector</string>
<!-- Feature Id for Location service. [CHAR LIMIT=NONE]-->
<string name="location_service">Location Service</string>
<!-- Feature Id for Gnss service. [CHAR LIMIT=NONE]-->
<string name="gnss_service">GNSS Service</string>
<!-- Feature Id for Sensor Notification service. [CHAR LIMIT=NONE]-->
<string name="sensor_notification_service">Sensor Notification Service</string>
<!-- Feature Id for Twilight service. [CHAR LIMIT=NONE]-->

View File

@@ -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);

View File

@@ -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));

View File

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

View File

@@ -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

View File

@@ -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();
}
}
/**
@@ -315,11 +326,27 @@ 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() {}

View File

@@ -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);

View File

@@ -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";
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -52,7 +52,6 @@ import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -200,7 +199,7 @@ public class FusedLocationServiceTest {
}
@Override
public void onSetAdditionalProviderPackages(List<String> packageNames) {
public void onSetFeatureId(String featureId) {
}

View File

@@ -24,11 +24,10 @@ import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.location.util.identity.CallerIdentity.PERMISSION_COARSE;
import static android.location.util.identity.CallerIdentity.PERMISSION_FINE;
import static android.os.PowerManager.locationPowerSaveModeToString;
import static com.android.server.location.CallerIdentity.PERMISSION_COARSE;
import static com.android.server.location.CallerIdentity.PERMISSION_FINE;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.Manifest;
@@ -62,6 +61,8 @@ import android.location.LocationManagerInternal;
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
import android.location.util.identity.CallerIdentity;
import android.location.util.identity.CallerIdentity.PermissionLevel;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -95,8 +96,6 @@ import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.AppForegroundHelper;
import com.android.server.location.AppOpsHelper;
import com.android.server.location.CallerIdentity;
import com.android.server.location.CallerIdentity.PermissionLevel;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GeofenceProxy;
@@ -128,7 +127,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -229,7 +227,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// @GuardedBy("mLock")
// hold lock for write or to prevent write, no lock for read
private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
new CopyOnWriteArrayList<>();
@GuardedBy("mLock")
@@ -243,7 +241,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@PowerManager.LocationPowerSaveMode
private int mBatterySaverMode;
private LocationManagerService(Context context) {
LocationManagerService(Context context) {
mContext = context.createFeatureContext(FEATURE_ID);
mHandler = FgThread.getHandler();
mLocalService = new LocalService();
@@ -278,7 +276,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// most startup is deferred until systemReady()
}
private void onSystemReady() {
void onSystemReady() {
mAppOpsHelper.onSystemReady();
mUserInfoHelper.onSystemReady();
mSettingsHelper.onSystemReady();
@@ -358,7 +356,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
private void onSystemThirdPartyAppsCanStart() {
void onSystemThirdPartyAppsCanStart() {
synchronized (mLock) {
// prepare providers
initializeProvidersLocked();
@@ -666,7 +664,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
protected final MockableLocationProvider mProvider;
private LocationProviderManager(String name) {
LocationProviderManager(String name) {
mName = name;
mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
mEnabled = new SparseArray<>(2);
@@ -716,8 +714,9 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
public Set<String> getPackages() {
return mProvider.getState().providerPackageNames;
@Nullable
public CallerIdentity getProviderIdentity() {
return mProvider.getState().identity;
}
@Nullable
@@ -1395,7 +1394,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Nullable
private LocationProviderManager getLocationProviderManager(String providerName) {
LocationProviderManager getLocationProviderManager(String providerName) {
for (LocationProviderManager manager : mProviderManagers) {
if (providerName.equals(manager.getName())) {
return manager;
@@ -1419,7 +1418,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
if (!CallerIdentity.checkCallingOrSelfLocationPermission(mContext)) {
if (!CallerIdentity.checkCallingOrSelfLocationPermission(mContext, PERMISSION_COARSE)) {
return Collections.emptyList();
}
@@ -1653,7 +1652,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return true;
}
return mLocalService.isProviderPackage(callerIdentity.packageName);
return mLocalService.isProvider(null, callerIdentity);
}
@@ -1667,8 +1666,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return true;
}
return mLocalService.isProviderPackage(record.mReceiver.mCallerIdentity.packageName);
return mLocalService.isProvider(null, record.mReceiver.mCallerIdentity);
}
private class UpdateRecord {
@@ -1850,7 +1848,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId);
identity.enforceLocationPermission();
identity.enforceLocationPermission(PERMISSION_COARSE);
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
@@ -2002,7 +2000,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// unsafe is ok because app ops will verify the package name
CallerIdentity identity = CallerIdentity.fromBinderUnsafe(mContext, packageName, featureId);
identity.enforceLocationPermission();
identity.enforceLocationPermission(PERMISSION_COARSE);
if (mSettingsHelper.isLocationPackageBlacklisted(identity.userId, identity.packageName)) {
return null;
@@ -2114,7 +2112,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId);
identity.enforceLocationPermission();
identity.enforceLocationPermission(PERMISSION_COARSE);
Objects.requireNonNull(intent);
@@ -2254,7 +2252,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
CallerIdentity.enforceCallingOrSelfLocationPermission(mContext);
CallerIdentity.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_COARSE);
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null);
@@ -2288,16 +2286,40 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
public boolean isProviderPackage(String packageName) {
public boolean isProviderPackage(String provider, String packageName) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null);
return mLocalService.isProviderPackage(packageName);
for (LocationProviderManager manager : mProviderManagers) {
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
CallerIdentity identity = manager.getProviderIdentity();
if (identity == null) {
continue;
}
if (identity.packageName.equals(packageName)) {
return true;
}
}
return false;
}
@Override
public List<String> getProviderPackages(String providerName) {
public List<String> getProviderPackages(String provider) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_DEVICE_CONFIG, null);
LocationProviderManager manager = getLocationProviderManager(providerName);
return manager == null ? Collections.emptyList() : new ArrayList<>(manager.getPackages());
LocationProviderManager manager = getLocationProviderManager(provider);
if (manager == null) {
return Collections.emptyList();
}
CallerIdentity identity = manager.getProviderIdentity();
if (identity == null) {
return Collections.emptyList();
}
return Collections.singletonList(identity.packageName);
}
@Override
@@ -2426,7 +2448,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
if (!mUserInfoHelper.isCurrentUserId(identity.userId)
&& !isProviderPackage(identity.packageName)) {
&& !mLocalService.isProvider(null, identity)) {
continue;
}
@@ -2725,6 +2747,8 @@ public class LocationManagerService extends ILocationManager.Stub {
private class LocalService extends LocationManagerInternal {
LocalService() {}
@Override
public boolean isProviderEnabledForUser(@NonNull String provider, int userId) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
@@ -2739,12 +2763,16 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
public boolean isProviderPackage(String packageName) {
public boolean isProvider(String provider, CallerIdentity identity) {
for (LocationProviderManager manager : mProviderManagers) {
if (manager.getPackages().contains(packageName)) {
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
if (identity.equals(manager.getProviderIdentity())) {
return true;
}
}
return false;
}

View File

@@ -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;
/**

View File

@@ -19,21 +19,18 @@ package com.android.server.location;
import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
import android.annotation.Nullable;
import android.content.Context;
import android.location.Location;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
import android.os.Bundle;
import android.util.ArraySet;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
@@ -78,8 +75,7 @@ public abstract class AbstractLocationProvider {
* Default state value for a location provider that is disabled with no properties and an
* empty provider package list.
*/
public static final State EMPTY_STATE = new State(false, null,
Collections.emptySet());
public static final State EMPTY_STATE = new State(false, null, null);
/**
* The provider's allowed state.
@@ -92,39 +88,37 @@ public abstract class AbstractLocationProvider {
@Nullable public final ProviderProperties properties;
/**
* The provider's package name list - provider packages may be afforded special privileges.
* The provider's identity - providers may be afforded special privileges.
*/
public final Set<String> providerPackageNames;
@Nullable public final CallerIdentity identity;
private State(boolean allowed, ProviderProperties properties,
Set<String> providerPackageNames) {
private State(boolean allowed, ProviderProperties properties, CallerIdentity identity) {
this.allowed = allowed;
this.properties = properties;
this.providerPackageNames = Objects.requireNonNull(providerPackageNames);
this.identity = identity;
}
private State withAllowed(boolean allowed) {
State withAllowed(boolean allowed) {
if (allowed == this.allowed) {
return this;
} else {
return new State(allowed, properties, providerPackageNames);
return new State(allowed, properties, identity);
}
}
private State withProperties(ProviderProperties properties) {
if (properties.equals(this.properties)) {
State withProperties(@Nullable ProviderProperties properties) {
if (Objects.equals(properties, this.properties)) {
return this;
} else {
return new State(allowed, properties, providerPackageNames);
return new State(allowed, properties, identity);
}
}
private State withProviderPackageNames(Set<String> providerPackageNames) {
if (providerPackageNames.equals(this.providerPackageNames)) {
State withIdentity(@Nullable CallerIdentity identity) {
if (Objects.equals(identity, this.identity)) {
return this;
} else {
return new State(allowed, properties,
Collections.unmodifiableSet(new ArraySet<>(providerPackageNames)));
return new State(allowed, properties, identity);
}
}
@@ -138,12 +132,12 @@ public abstract class AbstractLocationProvider {
}
State state = (State) o;
return allowed == state.allowed && properties == state.properties
&& providerPackageNames.equals(state.providerPackageNames);
&& Objects.equals(identity, state.identity);
}
@Override
public int hashCode() {
return Objects.hash(allowed, properties, providerPackageNames);
return Objects.hash(allowed, properties, identity);
}
}
@@ -153,12 +147,12 @@ public abstract class AbstractLocationProvider {
@Nullable public final Listener listener;
public final State state;
private InternalState(@Nullable Listener listener, State state) {
InternalState(@Nullable Listener listener, State state) {
this.listener = listener;
this.state = state;
}
private InternalState withListener(Listener listener) {
InternalState withListener(Listener listener) {
if (listener == this.listener) {
return this;
} else {
@@ -166,7 +160,7 @@ public abstract class AbstractLocationProvider {
}
}
private InternalState withState(State state) {
InternalState withState(State state) {
if (state.equals(this.state)) {
return this;
} else {
@@ -174,7 +168,7 @@ public abstract class AbstractLocationProvider {
}
}
private InternalState withState(UnaryOperator<State> operator) {
InternalState withState(UnaryOperator<State> operator) {
return withState(operator.apply(state));
}
}
@@ -187,14 +181,17 @@ public abstract class AbstractLocationProvider {
// before it was set, and should not miss any updates that occur after it was set).
private final AtomicReference<InternalState> mInternalState;
protected AbstractLocationProvider(Executor executor, Context context) {
this(executor, Collections.singleton(context.getPackageName()));
}
protected AbstractLocationProvider(Executor executor, Set<String> 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<String> getProviderPackages() {
return mInternalState.get().state.providerPackageNames;
@Nullable
protected CallerIdentity getIdentity() {
return mInternalState.get().state.identity;
}
/**
@@ -298,8 +296,8 @@ public abstract class AbstractLocationProvider {
/**
* Call this method to report a change in provider packages.
*/
protected void setPackageNames(Set<String> packageNames) {
setState(state -> state.withProviderPackageNames(packageNames));
protected void setIdentity(CallerIdentity identity) {
setState(state -> state.withIdentity(identity));
}
/**

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

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

View File

@@ -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}.

View File

@@ -1,62 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.location;
import android.content.Context;
import android.content.pm.PackageManager;
/**
* Encapsulates utility functions and classes related to location permission checking.
*/
public final class LocationPermissionUtil {
/**
* Returns true if the calling process identified by {@code callerIdentity} is enabled to
* report location to AppOps service before providing device location identifiable information
* to its clients. Packages with these permissions must report any reporting of location
* information to apps, via AppOps.
*
* <p>The calling package represented by {@code callerIdentity} is considered a part of the
* extended Location Manager Service if it has all of the permissions below.
* <ul>
* <li>{@link android.Manifest.permission#LOCATION_HARDWARE}
* <li>{@link android.Manifest.permission#UPDATE_APP_OPS_STATS}
* </ul>
*
* <p>Any package with these permissions, that passes along location information from Android
* framework to apps, must report to AppOps, similarly to Location Manager Service - i.e.
* whenever it reports device location or location identifiable information such as
* GNSS status, GNSS measurements, etc. to its clients.
*/
public static boolean doesCallerReportToAppOps(Context context, CallerIdentity callerIdentity) {
return hasPermissionLocationHardware(context, callerIdentity)
&& hasPermissionUpdateAppOpsStats(context, callerIdentity);
}
private static boolean hasPermissionLocationHardware(Context context,
CallerIdentity callerIdentity) {
return context.checkPermission(android.Manifest.permission.LOCATION_HARDWARE,
callerIdentity.pid, callerIdentity.uid) == PackageManager.PERMISSION_GRANTED;
}
private static boolean hasPermissionUpdateAppOpsStats(Context context,
CallerIdentity callerIdentity) {
return context.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
callerIdentity.pid, callerIdentity.uid) == PackageManager.PERMISSION_GRANTED;
}
private LocationPermissionUtil() {}
}

View File

@@ -16,20 +16,16 @@
package com.android.server.location;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.util.identity.CallerIdentity;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.location.ILocationProvider;
@@ -41,18 +37,12 @@ import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
/**
* Proxy for ILocationProvider implementations.
*/
public class LocationProviderProxy extends AbstractLocationProvider {
private static final String TAG = "LocationProviderProxy";
private static final int MAX_ADDITIONAL_PACKAGES = 2;
/**
* Creates and registers this proxy. If no suitable service is available for the proxy, returns
* null.
@@ -69,76 +59,13 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
}
private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() {
// executed on binder thread
@Override
public void onSetAdditionalProviderPackages(List<String> packageNames) {
int maxCount = Math.min(MAX_ADDITIONAL_PACKAGES, packageNames.size());
ArraySet<String> allPackages = new ArraySet<>(maxCount + 1);
for (String packageName : packageNames) {
if (packageNames.size() >= maxCount) {
return;
}
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);
}
}
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -14,11 +14,11 @@
* limitations under the License.
*/
package com.android.server.location.util.listeners;
package com.android.server.location.gnss;
import android.annotation.Nullable;
import android.location.LocationManager;
import android.location.LocationManagerInternal;
import android.location.util.identity.CallerIdentity;
import android.location.util.listeners.AbstractListenerManager;
import android.os.Binder;
import android.os.IBinder;
@@ -31,9 +31,9 @@ import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import com.android.server.location.AppForegroundHelper;
import com.android.server.location.AppOpsHelper;
import com.android.server.location.CallerIdentity;
import com.android.server.location.SettingsHelper;
import com.android.server.location.UserInfoHelper;
import com.android.server.location.util.listeners.IdentifiedRegistration;
import java.util.Objects;
@@ -115,6 +115,18 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
return getIdentity().userId == userId;
}
boolean onLocationEnabledChanged(int userId) {
if (userId == getIdentity().userId) {
return onActiveChanged();
}
return false;
}
boolean onBackgroundThrottlePackageWhitelistChanged() {
return onActiveChanged();
}
boolean onAppOpsChanged(String packageName) {
if (getIdentity().packageName.equals(packageName)) {
boolean appOpsAllowed = mAppOpsHelper.checkLocationAccess(getIdentity());
@@ -144,9 +156,11 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
private boolean onActiveChanged() {
synchronized (this) {
// TODO: we should be checking if the gps provider is enabled, not location
boolean active = mAppOpsAllowed
&& (mForeground || isBackgroundRestrictionExempt(getIdentity()))
&& mUserInfoHelper.isCurrentUserId(getIdentity().userId);
&& mUserInfoHelper.isCurrentUserId(getIdentity().userId)
&& mSettingsHelper.isLocationEnabled(getIdentity().userId);
if (active != mActive) {
mActive = active;
return true;
@@ -156,6 +170,19 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
return false;
}
private boolean isBackgroundRestrictionExempt(CallerIdentity identity) {
if (identity.uid == Process.SYSTEM_UID) {
return true;
}
if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
identity.packageName)) {
return true;
}
return mLocationManagerInternal.isProvider(null, identity);
}
@Override
public void binderDied() {
IBinder key = mKey;
@@ -193,6 +220,16 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
protected final AppForegroundHelper mAppForegroundHelper;
protected final LocationManagerInternal mLocationManagerInternal;
private final UserInfoHelper.UserListener mUserChangedListener = this::onUserChanged;
private final SettingsHelper.UserSettingChangedListener mLocationEnabledChangedListener =
this::onLocationEnabledChanged;
private final SettingsHelper.GlobalSettingChangedListener
mBackgroundThrottlePackageWhitelistChangedListener =
this::onBackgroundThrottlePackageWhitelistChanged;
private final AppOpsHelper.LocationAppOpListener mAppOpsChangedListener = this::onAppOpsChanged;
private final AppForegroundHelper.AppForegroundListener mAppForegroundChangedListener =
this::onAppForegroundChanged;
protected GnssListenerManager(UserInfoHelper userInfoHelper, SettingsHelper settingsHelper,
AppOpsHelper appOpsHelper, AppForegroundHelper appForegroundHelper) {
mUserInfoHelper = userInfoHelper;
@@ -201,10 +238,6 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
mAppForegroundHelper = appForegroundHelper;
mLocationManagerInternal = Objects.requireNonNull(
LocalServices.getService(LocationManagerInternal.class));
mUserInfoHelper.addListener(this::onUserChanged);
mAppOpsHelper.addListener(this::onAppOpsChanged);
mAppForegroundHelper.addListener(this::onAppForegroundChanged);
}
/**
@@ -236,8 +269,27 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
protected boolean isActive(GnssRegistration registration) {
// we don't have an easy listener for provider enabled status changes available, so we
// check it every time, which should be pretty cheap
return registration.isActive() && mLocationManagerInternal.isProviderEnabledForUser(
LocationManager.GPS_PROVIDER, registration.getIdentity().userId);
return registration.isActive();
}
@Override
protected void onRegister() {
mUserInfoHelper.addListener(mUserChangedListener);
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
mBackgroundThrottlePackageWhitelistChangedListener);
mAppOpsHelper.addListener(mAppOpsChangedListener);
mAppForegroundHelper.addListener(mAppForegroundChangedListener);
}
@Override
protected void onUnregister() {
mUserInfoHelper.removeListener(mUserChangedListener);
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
mBackgroundThrottlePackageWhitelistChangedListener);
mAppOpsHelper.removeListener(mAppOpsChangedListener);
mAppForegroundHelper.removeListener(mAppForegroundChangedListener);
}
private void onUserChanged(int userId, int change) {
@@ -246,6 +298,14 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
}
}
private void onLocationEnabledChanged(int userId) {
updateRegistrations(registration -> registration.onLocationEnabledChanged(userId));
}
private void onBackgroundThrottlePackageWhitelistChanged() {
updateRegistrations(GnssRegistration::onBackgroundThrottlePackageWhitelistChanged);
}
private void onAppOpsChanged(String packageName) {
updateRegistrations(registration -> registration.onAppOpsChanged(packageName));
}
@@ -254,19 +314,6 @@ public abstract class GnssListenerManager<TRequest, TListener extends IInterface
updateRegistrations(registration -> registration.onForegroundChanged(uid, foreground));
}
boolean isBackgroundRestrictionExempt(CallerIdentity callerIdentity) {
if (callerIdentity.uid == Process.SYSTEM_UID) {
return true;
}
if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
callerIdentity.packageName)) {
return true;
}
return mLocationManagerInternal.isProviderPackage(callerIdentity.packageName);
}
/**
* May be overridden by subclasses to provide extra debug information.
*/

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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(

View File

@@ -35,21 +35,18 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.server.location.test.FakeProvider;
import com.android.server.location.test.ProviderListenerCapture;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.LinkedList;
import java.util.List;
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class MockableLocationProviderTest {
private Object mLock;
private ListenerCapture mListener;
private ProviderListenerCapture mListener;
private AbstractLocationProvider mRealProvider;
private MockProvider mMockProvider;
@@ -58,8 +55,8 @@ public class MockableLocationProviderTest {
@Before
public void setUp() {
mLock = new Object();
mListener = new ListenerCapture();
Object lock = new Object();
mListener = new ProviderListenerCapture(lock);
mRealProvider = spy(new FakeProvider());
mMockProvider = spy(new MockProvider(new ProviderProperties(
@@ -71,9 +68,10 @@ public class MockableLocationProviderTest {
true,
true,
Criteria.POWER_LOW,
Criteria.ACCURACY_FINE)));
Criteria.ACCURACY_FINE)
));
mProvider = new MockableLocationProvider(mLock, mListener);
mProvider = new MockableLocationProvider(lock, mListener);
mProvider.setRealProvider(mRealProvider);
}
@@ -170,34 +168,4 @@ public class MockableLocationProviderTest {
mMockProvider.reportLocation(mockLocation);
assertThat(mListener.getNextLocation()).isEqualTo(mockLocation);
}
private class ListenerCapture implements AbstractLocationProvider.Listener {
private final LinkedList<AbstractLocationProvider.State> mNewStates = new LinkedList<>();
private final LinkedList<Location> mLocations = new LinkedList<>();
@Override
public void onStateChanged(AbstractLocationProvider.State oldState,
AbstractLocationProvider.State newState) {
assertThat(Thread.holdsLock(mLock)).isTrue();
mNewStates.add(newState);
}
private AbstractLocationProvider.State getNextNewState() {
return mNewStates.poll();
}
@Override
public void onReportLocation(Location location) {
assertThat(Thread.holdsLock(mLock)).isTrue();
mLocations.add(location);
}
private Location getNextLocation() {
return mLocations.poll();
}
@Override
public void onReportLocation(List<Location> locations) {}
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.location.test;
import static com.google.common.truth.Truth.assertThat;
import android.location.Location;
import com.android.server.location.AbstractLocationProvider;
import java.util.LinkedList;
import java.util.List;
public class ProviderListenerCapture implements AbstractLocationProvider.Listener {
private final Object mLock;
private final LinkedList<AbstractLocationProvider.State> mNewStates = new LinkedList<>();
private final LinkedList<Location> mLocations = new LinkedList<>();
public ProviderListenerCapture(Object lock) {
mLock = lock;
}
@Override
public void onStateChanged(AbstractLocationProvider.State oldState,
AbstractLocationProvider.State newState) {
assertThat(Thread.holdsLock(mLock)).isTrue();
mNewStates.add(newState);
}
public AbstractLocationProvider.State getNextNewState() {
return mNewStates.poll();
}
@Override
public void onReportLocation(Location location) {
assertThat(Thread.holdsLock(mLock)).isTrue();
mLocations.add(location);
}
public Location getNextLocation() {
return mLocations.poll();
}
@Override
public void onReportLocation(List<Location> locations) {}
}