Allow a particular LocationRequest to be excluded from
AppOps monitoring as long as the client as the appropriate
permission (UPDATE_DEVICE_STATS).
Change-Id: I7223a53bc1551e6498302a22eb310c8c5b5684b0
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 7f056c2..cde84dc 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -462,6 +462,7 @@
final ILocationListener mListener;
final PendingIntent mPendingIntent;
final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
+ final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
final Object mKey;
final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
@@ -474,7 +475,7 @@
PowerManager.WakeLock mWakeLock;
Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
- String packageName, WorkSource workSource) {
+ String packageName, WorkSource workSource, boolean hideFromAppOps) {
mListener = listener;
mPendingIntent = intent;
if (listener != null) {
@@ -490,6 +491,7 @@
workSource = null;
}
mWorkSource = workSource;
+ mHideFromAppOps = hideFromAppOps;
updateMonitoring(true);
@@ -532,6 +534,10 @@
}
public void updateMonitoring(boolean allow) {
+ if (mHideFromAppOps) {
+ return;
+ }
+
// First update monitoring of any location request (including high power).
mOpMonitoring = updateMonitoring(allow, mOpMonitoring,
AppOpsManager.OP_MONITOR_LOCATION);
@@ -931,11 +937,16 @@
* Throw SecurityException if WorkSource use is not allowed (i.e. can't blame other packages
* for battery).
*/
- private void checkWorkSourceAllowed() {
+ private void checkDeviceStatsAllowed() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.UPDATE_DEVICE_STATS, null);
}
+ private void checkUpdateAppOpsAllowed() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.UPDATE_APP_OPS_STATS, null);
+ }
+
public static int resolutionLevelToOp(int allowedResolutionLevel) {
if (allowedResolutionLevel != RESOLUTION_LEVEL_NONE) {
if (allowedResolutionLevel == RESOLUTION_LEVEL_COARSE) {
@@ -1260,11 +1271,12 @@
}
private Receiver getReceiverLocked(ILocationListener listener, int pid, int uid,
- String packageName, WorkSource workSource) {
+ String packageName, WorkSource workSource, boolean hideFromAppOps) {
IBinder binder = listener.asBinder();
Receiver receiver = mReceivers.get(binder);
if (receiver == null) {
- receiver = new Receiver(listener, null, pid, uid, packageName, workSource);
+ receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
+ hideFromAppOps);
mReceivers.put(binder, receiver);
try {
@@ -1278,10 +1290,11 @@
}
private Receiver getReceiverLocked(PendingIntent intent, int pid, int uid, String packageName,
- WorkSource workSource) {
+ WorkSource workSource, boolean hideFromAppOps) {
Receiver receiver = mReceivers.get(intent);
if (receiver == null) {
- receiver = new Receiver(null, intent, pid, uid, packageName, workSource);
+ receiver = new Receiver(null, intent, pid, uid, packageName, workSource,
+ hideFromAppOps);
mReceivers.put(intent, receiver);
}
return receiver;
@@ -1343,16 +1356,16 @@
}
private Receiver checkListenerOrIntentLocked(ILocationListener listener, PendingIntent intent,
- int pid, int uid, String packageName, WorkSource workSource) {
+ int pid, int uid, String packageName, WorkSource workSource, boolean hideFromAppOps) {
if (intent == null && listener == null) {
throw new IllegalArgumentException("need either listener or intent");
} else if (intent != null && listener != null) {
throw new IllegalArgumentException("cannot register both listener and intent");
} else if (intent != null) {
checkPendingIntent(intent);
- return getReceiverLocked(intent, pid, uid, packageName, workSource);
+ return getReceiverLocked(intent, pid, uid, packageName, workSource, hideFromAppOps);
} else {
- return getReceiverLocked(listener, pid, uid, packageName, workSource);
+ return getReceiverLocked(listener, pid, uid, packageName, workSource, hideFromAppOps);
}
}
@@ -1366,7 +1379,11 @@
request.getProvider());
WorkSource workSource = request.getWorkSource();
if (workSource != null && workSource.size() > 0) {
- checkWorkSourceAllowed();
+ checkDeviceStatsAllowed();
+ }
+ boolean hideFromAppOps = request.getHideFromAppOps();
+ if (hideFromAppOps) {
+ checkUpdateAppOpsAllowed();
}
LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
@@ -1381,7 +1398,7 @@
synchronized (mLock) {
Receiver recevier = checkListenerOrIntentLocked(listener, intent, pid, uid,
- packageName, workSource);
+ packageName, workSource, hideFromAppOps);
requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
}
} finally {
@@ -1434,8 +1451,9 @@
synchronized (mLock) {
WorkSource workSource = null;
- Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid, packageName,
- workSource);
+ boolean hideFromAppOps = false;
+ Receiver receiver = checkListenerOrIntentLocked(listener, intent, pid, uid,
+ packageName, workSource, hideFromAppOps);
// providers may use public location API's, need to clear identity
long identity = Binder.clearCallingIdentity();