DO NOT MERGE Add listener ids for location listening operations
Bug: 153257294
Test: presubmits
Change-Id: I12654a3afac5362383caba3cea1c5e0a2b8ce1d9
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 4150926..75ea0cb 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -47,10 +47,10 @@
Location getLastLocation(in LocationRequest request, String packageName, String featureId);
boolean getCurrentLocation(in LocationRequest request,
in ICancellationSignal cancellationSignal, in ILocationListener listener,
- String packageName, String featureId);
+ String packageName, String featureId, String listenerId);
void requestLocationUpdates(in LocationRequest request, in ILocationListener listener,
- in PendingIntent intent, String packageName, String featureId);
+ in PendingIntent intent, String packageName, String featureId, String listenerId);
void removeUpdates(in ILocationListener listener, in PendingIntent intent);
void requestGeofence(in LocationRequest request, in Geofence geofence,
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index fcbd3e5..d1b41df 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -718,7 +718,7 @@
currentLocationRequest.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
}
- GetCurrentLocationTransport listenerTransport = new GetCurrentLocationTransport(executor,
+ GetCurrentLocationTransport transport = new GetCurrentLocationTransport(executor,
consumer);
if (cancellationSignal != null) {
@@ -729,14 +729,15 @@
try {
if (mService.getCurrentLocation(currentLocationRequest, remoteCancellationSignal,
- listenerTransport, mContext.getPackageName(), mContext.getAttributionTag())) {
- listenerTransport.register(mContext.getSystemService(AlarmManager.class),
+ transport, mContext.getPackageName(), mContext.getAttributionTag(),
+ transport.getListenerId())) {
+ transport.register(mContext.getSystemService(AlarmManager.class),
remoteCancellationSignal);
if (cancellationSignal != null) {
- cancellationSignal.setOnCancelListener(listenerTransport::cancel);
+ cancellationSignal.setOnCancelListener(transport::cancel);
}
} else {
- listenerTransport.fail();
+ transport.fail();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1175,7 +1176,8 @@
boolean registered = false;
try {
mService.requestLocationUpdates(locationRequest, transport, null,
- mContext.getPackageName(), mContext.getAttributionTag());
+ mContext.getPackageName(), mContext.getAttributionTag(),
+ transport.getListenerId());
registered = true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1220,7 +1222,7 @@
try {
mService.requestLocationUpdates(locationRequest, null, pendingIntent,
- mContext.getPackageName(), mContext.getAttributionTag());
+ mContext.getPackageName(), mContext.getAttributionTag(), null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2558,6 +2560,10 @@
mRemoteCancellationSignal = null;
}
+ public String getListenerId() {
+ return mConsumer.getClass().getName() + "@" + System.identityHashCode(mConsumer);
+ }
+
public synchronized void register(AlarmManager alarmManager,
ICancellationSignal remoteCancellationSignal) {
if (mConsumer == null) {
@@ -2683,6 +2689,10 @@
return mListener;
}
+ public String getListenerId() {
+ return mListener.getClass().getName() + "@" + System.identityHashCode(mListener);
+ }
+
public void register(@NonNull Executor executor) {
Preconditions.checkArgument(executor != null, "invalid null executor");
mExecutor = executor;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index a9c3079..7f25de6b 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1836,12 +1836,13 @@
@Override
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
- PendingIntent intent, String packageName, String featureId) {
+ PendingIntent intent, String packageName, String featureId, String listenerId) {
if (request == null) {
request = DEFAULT_LOCATION_REQUEST;
}
- CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId);
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, featureId,
+ listenerId);
identity.enforceLocationPermission();
WorkSource workSource = request.getWorkSource();
@@ -2027,7 +2028,7 @@
@Override
public boolean getCurrentLocation(LocationRequest locationRequest,
ICancellationSignal remoteCancellationSignal, ILocationListener listener,
- String packageName, String featureId) {
+ String packageName, String featureId, String listenerId) {
// side effect of validating locationRequest and packageName
Location lastLocation = getLastLocation(locationRequest, packageName, featureId);
if (lastLocation != null) {
@@ -2052,7 +2053,7 @@
}
}
- requestLocationUpdates(locationRequest, listener, null, packageName, featureId);
+ requestLocationUpdates(locationRequest, listener, null, packageName, featureId, listenerId);
CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
remoteCancellationSignal);
if (cancellationSignal != null) {
diff --git a/services/core/java/com/android/server/location/AppOpsHelper.java b/services/core/java/com/android/server/location/AppOpsHelper.java
index 9c27916..cb64c50 100644
--- a/services/core/java/com/android/server/location/AppOpsHelper.java
+++ b/services/core/java/com/android/server/location/AppOpsHelper.java
@@ -191,7 +191,7 @@
callerIdentity.uid,
callerIdentity.packageName,
callerIdentity.featureId,
- null) == AppOpsManager.MODE_ALLOWED;
+ callerIdentity.listenerId) == AppOpsManager.MODE_ALLOWED;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -210,7 +210,7 @@
callerIdentity.packageName,
false,
callerIdentity.featureId,
- null) == AppOpsManager.MODE_ALLOWED;
+ callerIdentity.listenerId) == AppOpsManager.MODE_ALLOWED;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -245,7 +245,7 @@
callerIdentity.uid,
callerIdentity.packageName,
callerIdentity.featureId,
- null) == AppOpsManager.MODE_ALLOWED;
+ callerIdentity.listenerId) == AppOpsManager.MODE_ALLOWED;
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/location/CallerIdentity.java b/services/core/java/com/android/server/location/CallerIdentity.java
index b84fd13..8d508bb 100644
--- a/services/core/java/com/android/server/location/CallerIdentity.java
+++ b/services/core/java/com/android/server/location/CallerIdentity.java
@@ -83,12 +83,22 @@
*/
public static CallerIdentity fromBinder(Context context, String packageName,
@Nullable String featureId) {
+ return fromBinder(context, packageName, featureId, null);
+ }
+
+ /**
+ * Creates a CallerIdentity from the current binder identity, using the given package, feature
+ * id, and listener id. The package will be checked to enforce it belongs to the calling uid,
+ * and a security exception will be thrown if it is invalid.
+ */
+ public static CallerIdentity fromBinder(Context context, String packageName,
+ @Nullable String featureId, @Nullable String listenerId) {
int uid = Binder.getCallingUid();
if (!ArrayUtils.contains(context.getPackageManager().getPackagesForUid(uid), packageName)) {
throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid);
}
- return fromBinderUnsafe(context, packageName, featureId);
+ return fromBinderUnsafe(context, packageName, featureId, listenerId);
}
/**
@@ -99,8 +109,19 @@
*/
public static CallerIdentity fromBinderUnsafe(Context context, String packageName,
@Nullable String featureId) {
+ return fromBinderUnsafe(context, packageName, featureId, null);
+ }
+
+ /**
+ * Creates a CallerIdentity from the current binder identity, using the given package, feature
+ * id, and listener id. The package will not be checked to enforce that it belongs to the
+ * calling uid - this method should only be used if the package will be validated by some other
+ * means, such as an appops call.
+ */
+ public static CallerIdentity fromBinderUnsafe(Context context, String packageName,
+ @Nullable String featureId, @Nullable String listenerId) {
return new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(),
- UserHandle.getCallingUserId(), packageName, featureId,
+ UserHandle.getCallingUserId(), packageName, featureId, listenerId,
getBinderPermissionLevel(context));
}
@@ -157,6 +178,9 @@
/** The calling feature id. */
public final @Nullable String featureId;
+ /** The calling listener id. */
+ public final @Nullable String listenerId;
+
/**
* The calling location permission level. This field should only be used for validating
* permissions for API access. It should not be used for validating permissions for location
@@ -167,11 +191,18 @@
@VisibleForTesting
public CallerIdentity(int uid, int pid, int userId, String packageName,
@Nullable String featureId, @PermissionLevel int permissionLevel) {
+ this(uid, pid, userId, packageName, featureId, null, permissionLevel);
+ }
+
+ private CallerIdentity(int uid, int pid, int userId, String packageName,
+ @Nullable String featureId, @Nullable String listenerId,
+ @PermissionLevel int permissionLevel) {
this.uid = uid;
this.pid = pid;
this.userId = userId;
this.packageName = Objects.requireNonNull(packageName);
this.featureId = featureId;
+ this.listenerId = listenerId;
this.permissionLevel = Preconditions.checkArgumentInRange(permissionLevel, PERMISSION_NONE,
PERMISSION_FINE, "permissionLevel");
}
@@ -216,7 +247,8 @@
return uid == that.uid
&& pid == that.pid
&& packageName.equals(that.packageName)
- && Objects.equals(featureId, that.featureId);
+ && Objects.equals(featureId, that.featureId)
+ && Objects.equals(listenerId, that.listenerId);
}
@Override