Merge "Give location providers a known identity"
This commit is contained in:
committed by
Android (Google) Code Review
commit
1eb8014bd2
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
|
||||
@@ -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]-->
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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}.
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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) {}
|
||||
}
|
||||
Reference in New Issue
Block a user