summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java392
-rw-r--r--services/core/java/com/android/server/appop/AppOpsServiceInterface.java99
-rw-r--r--services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java379
-rw-r--r--services/core/java/com/android/server/appop/OnOpModeChangedListener.java102
4 files changed, 677 insertions, 295 deletions
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a5bcb0517d25..248e35e6964d 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -63,7 +63,6 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
import static android.app.AppOpsManager.UID_STATE_TOP;
-import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
import static android.app.AppOpsManager._NUM_OP;
import static android.app.AppOpsManager.extractFlagsFromKey;
import static android.app.AppOpsManager.extractUidStateFromKey;
@@ -563,6 +562,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
public ArrayMap<String, Ops> pkgOps;
// true indicates there is an interested observer, false there isn't but it has such an op
+ //TODO: Move foregroundOps and hasForegroundWatchers into the AppOpsServiceInterface.
public SparseBooleanArray foregroundOps;
public boolean hasForegroundWatchers;
@@ -658,48 +658,24 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
return mode;
}
- private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
- SparseBooleanArray which) {
- boolean curValue = which.get(op, false);
- ArraySet<ModeCallback> callbacks = watchers.get(op);
- if (callbacks != null) {
- for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
- if ((callbacks.valueAt(cbi).mFlags
- & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
- hasForegroundWatchers = true;
- curValue = true;
- }
+ public void evalForegroundOps() {
+ foregroundOps = null;
+ foregroundOps = mAppOpsServiceInterface.evalForegroundUidOps(uid, foregroundOps);
+ if (pkgOps != null) {
+ for (int i = pkgOps.size() - 1; i >= 0; i--) {
+ foregroundOps = mAppOpsServiceInterface
+ .evalForegroundPackageOps(pkgOps.valueAt(i).packageName, foregroundOps);
}
}
- which.put(op, curValue);
- }
-
- public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
- SparseBooleanArray which = null;
hasForegroundWatchers = false;
- final SparseIntArray opModes = getNonDefaultUidModes();
- for (int i = opModes.size() - 1; i >= 0; i--) {
- if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
- if (which == null) {
- which = new SparseBooleanArray();
- }
- evalForegroundWatchers(opModes.keyAt(i), watchers, which);
- }
- }
- if (pkgOps != null) {
- for (int i = pkgOps.size() - 1; i >= 0; i--) {
- Ops ops = pkgOps.valueAt(i);
- for (int j = ops.size() - 1; j >= 0; j--) {
- if (ops.valueAt(j).getMode() == AppOpsManager.MODE_FOREGROUND) {
- if (which == null) {
- which = new SparseBooleanArray();
- }
- evalForegroundWatchers(ops.keyAt(j), watchers, which);
- }
+ if (foregroundOps != null) {
+ for (int i = 0; i < foregroundOps.size(); i++) {
+ if (foregroundOps.valueAt(i)) {
+ hasForegroundWatchers = true;
+ break;
}
}
}
- foregroundOps = which;
}
}
@@ -1562,33 +1538,24 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
}
}
- final SparseArray<ArraySet<ModeCallback>> mOpModeWatchers = new SparseArray<>();
- final ArrayMap<String, ArraySet<ModeCallback>> mPackageModeWatchers = new ArrayMap<>();
final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>();
final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
- final class ModeCallback implements DeathRecipient {
+ final class ModeCallback extends OnOpModeChangedListener implements DeathRecipient {
/** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */
public static final int ALL_OPS = -2;
- final IAppOpsCallback mCallback;
- final int mWatchingUid;
- final int mFlags;
- final int mWatchedOpCode;
- final int mCallingUid;
- final int mCallingPid;
+ // Need to keep this only because stopWatchingMode needs an IAppOpsCallback.
+ // Otherwise we can just use the IBinder object.
+ private final IAppOpsCallback mCallback;
- ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp,
+ ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOpCode,
int callingUid, int callingPid) {
- mCallback = callback;
- mWatchingUid = watchingUid;
- mFlags = flags;
- mWatchedOpCode = watchedOp;
- mCallingUid = callingUid;
- mCallingPid = callingPid;
+ super(watchingUid, flags, watchedOpCode, callingUid, callingPid);
+ this.mCallback = callback;
try {
mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -1596,20 +1563,16 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
}
}
- public boolean isWatchingUid(int uid) {
- return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
- }
-
@Override
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("ModeCallback{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" watchinguid=");
- UserHandle.formatUid(sb, mWatchingUid);
+ UserHandle.formatUid(sb, getWatchingUid());
sb.append(" flags=0x");
- sb.append(Integer.toHexString(mFlags));
- switch (mWatchedOpCode) {
+ sb.append(Integer.toHexString(getFlags()));
+ switch (getWatchedOpCode()) {
case OP_NONE:
break;
case ALL_OPS:
@@ -1617,13 +1580,13 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
break;
default:
sb.append(" op=");
- sb.append(opToName(mWatchedOpCode));
+ sb.append(opToName(getWatchedOpCode()));
break;
}
sb.append(" from uid=");
- UserHandle.formatUid(sb, mCallingUid);
+ UserHandle.formatUid(sb, getCallingUid());
sb.append(" pid=");
- sb.append(mCallingPid);
+ sb.append(getCallingPid());
sb.append('}');
return sb.toString();
}
@@ -1636,6 +1599,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
public void binderDied() {
stopWatchingMode(mCallback);
}
+
+ @Override
+ public void onOpModeChanged(int op, int uid, String packageName) throws RemoteException {
+ mCallback.opChanged(op, uid, packageName);
+ }
}
final class ActiveCallback implements DeathRecipient {
@@ -1804,7 +1772,14 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
public AppOpsService(File storagePath, Handler handler, Context context) {
mContext = context;
- mAppOpsServiceInterface = new LegacyAppOpsServiceInterfaceImpl(this, this);
+
+ for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
+ int switchCode = AppOpsManager.opToSwitch(switchedCode);
+ mSwitchedOps.put(switchCode,
+ ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
+ }
+ mAppOpsServiceInterface =
+ new LegacyAppOpsServiceInterfaceImpl(this, this, handler, context, mSwitchedOps);
LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
mFile = new AtomicFile(storagePath, "appops");
@@ -1818,12 +1793,6 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
mHandler = handler;
mConstants = new Constants(mHandler);
readState();
-
- for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
- int switchCode = AppOpsManager.opToSwitch(switchedCode);
- mSwitchedOps.put(switchCode,
- ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
- }
}
public void publish() {
@@ -1982,20 +1951,20 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
final String[] changedPkgs = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_PACKAGE_LIST);
for (int code : OPS_RESTRICTED_ON_SUSPEND) {
- ArraySet<ModeCallback> callbacks;
+ ArraySet<OnOpModeChangedListener> onModeChangedListeners;
synchronized (AppOpsService.this) {
- callbacks = mOpModeWatchers.get(code);
- if (callbacks == null) {
+ onModeChangedListeners =
+ mAppOpsServiceInterface.getOpModeChangedListeners(code);
+ if (onModeChangedListeners == null) {
continue;
}
- callbacks = new ArraySet<>(callbacks);
}
for (int i = 0; i < changedUids.length; i++) {
final int changedUid = changedUids[i];
final String changedPkg = changedPkgs[i];
// We trust packagemanager to insert matching uid and packageNames in the
// extras
- notifyOpChanged(callbacks, code, changedUid, changedPkg);
+ notifyOpChanged(onModeChangedListeners, code, changedUid, changedPkg);
}
}
}
@@ -2596,7 +2565,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
if (!uidState.setUidMode(code, mode)) {
return;
}
- uidState.evalForegroundOps(mOpModeWatchers);
+ uidState.evalForegroundOps();
if (mode != MODE_ERRORED && mode != previousMode) {
updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
}
@@ -2615,78 +2584,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
*/
private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
@Nullable IAppOpsCallback callbackToIgnore) {
- String[] uidPackageNames = getPackagesForUid(uid);
- ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null;
-
- synchronized (this) {
- ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
- if (callbacks != null) {
- final int callbackCount = callbacks.size();
- for (int i = 0; i < callbackCount; i++) {
- ModeCallback callback = callbacks.valueAt(i);
- if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
- continue;
- }
-
- ArraySet<String> changedPackages = new ArraySet<>();
- Collections.addAll(changedPackages, uidPackageNames);
- if (callbackSpecs == null) {
- callbackSpecs = new ArrayMap<>();
- }
- callbackSpecs.put(callback, changedPackages);
- }
- }
-
- for (String uidPackageName : uidPackageNames) {
- callbacks = mPackageModeWatchers.get(uidPackageName);
- if (callbacks != null) {
- if (callbackSpecs == null) {
- callbackSpecs = new ArrayMap<>();
- }
- final int callbackCount = callbacks.size();
- for (int i = 0; i < callbackCount; i++) {
- ModeCallback callback = callbacks.valueAt(i);
- if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) {
- continue;
- }
-
- ArraySet<String> changedPackages = callbackSpecs.get(callback);
- if (changedPackages == null) {
- changedPackages = new ArraySet<>();
- callbackSpecs.put(callback, changedPackages);
- }
- changedPackages.add(uidPackageName);
- }
- }
- }
-
- if (callbackSpecs != null && callbackToIgnore != null) {
- callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder()));
- }
- }
-
- if (callbackSpecs == null) {
- return;
- }
-
- for (int i = 0; i < callbackSpecs.size(); i++) {
- final ModeCallback callback = callbackSpecs.keyAt(i);
- final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
- if (reportedPackageNames == null) {
- mHandler.sendMessage(PooledLambda.obtainMessage(
- AppOpsService::notifyOpChanged,
- this, callback, code, uid, (String) null));
-
- } else {
- final int reportedPackageCount = reportedPackageNames.size();
- for (int j = 0; j < reportedPackageCount; j++) {
- final String reportedPackageName = reportedPackageNames.valueAt(j);
- mHandler.sendMessage(PooledLambda.obtainMessage(
- AppOpsService::notifyOpChanged,
- this, callback, code, uid, reportedPackageName));
- }
- }
- }
+ ModeCallback listenerToIgnore = callbackToIgnore != null
+ ? mModeWatchers.get(callbackToIgnore.asBinder()) : null;
+ mAppOpsServiceInterface.notifyOpChangedForAllPkgsInUid(code, uid, onlyForeground,
+ listenerToIgnore);
}
private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
@@ -2810,7 +2711,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
return;
}
- ArraySet<ModeCallback> repCbs = null;
+ ArraySet<OnOpModeChangedListener> repCbs = null;
code = AppOpsManager.opToSwitch(code);
PackageVerificationResult pvr;
@@ -2831,16 +2732,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
op.setMode(mode);
if (uidState != null) {
- uidState.evalForegroundOps(mOpModeWatchers);
+ uidState.evalForegroundOps();
}
- ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
+ ArraySet<OnOpModeChangedListener> cbs =
+ mAppOpsServiceInterface.getOpModeChangedListeners(code);
if (cbs != null) {
if (repCbs == null) {
repCbs = new ArraySet<>();
}
repCbs.addAll(cbs);
}
- cbs = mPackageModeWatchers.get(packageName);
+ cbs = mAppOpsServiceInterface.getPackageModeChangedListeners(packageName);
if (cbs != null) {
if (repCbs == null) {
repCbs = new ArraySet<>();
@@ -2871,47 +2773,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
notifyOpChangedSync(code, uid, packageName, mode, previousMode);
}
- private void notifyOpChanged(ArraySet<ModeCallback> callbacks, int code,
+ private void notifyOpChanged(ArraySet<OnOpModeChangedListener> callbacks, int code,
int uid, String packageName) {
for (int i = 0; i < callbacks.size(); i++) {
- final ModeCallback callback = callbacks.valueAt(i);
+ final OnOpModeChangedListener callback = callbacks.valueAt(i);
notifyOpChanged(callback, code, uid, packageName);
}
}
- private void notifyOpChanged(ModeCallback callback, int code,
+ private void notifyOpChanged(OnOpModeChangedListener callback, int code,
int uid, String packageName) {
- if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
- return;
- }
-
- // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
- int[] switchedCodes;
- if (callback.mWatchedOpCode == ALL_OPS) {
- switchedCodes = mSwitchedOps.get(code);
- } else if (callback.mWatchedOpCode == OP_NONE) {
- switchedCodes = new int[]{code};
- } else {
- switchedCodes = new int[]{callback.mWatchedOpCode};
- }
-
- for (int switchedCode : switchedCodes) {
- // There are features watching for mode changes such as window manager
- // and location manager which are in our process. The callbacks in these
- // features may require permissions our remote caller does not have.
- final long identity = Binder.clearCallingIdentity();
- try {
- if (shouldIgnoreCallback(switchedCode, callback.mCallingPid,
- callback.mCallingUid)) {
- continue;
- }
- callback.mCallback.opChanged(switchedCode, uid, packageName);
- } catch (RemoteException e) {
- /* ignore */
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ mAppOpsServiceInterface.notifyOpChanged(callback, code, uid, packageName);
}
private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports,
@@ -2936,9 +2808,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
return reports;
}
- private static HashMap<ModeCallback, ArrayList<ChangeRec>> addCallbacks(
- HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks,
- int op, int uid, String packageName, int previousMode, ArraySet<ModeCallback> cbs) {
+ private static HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> addCallbacks(
+ HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks,
+ int op, int uid, String packageName, int previousMode,
+ ArraySet<OnOpModeChangedListener> cbs) {
if (cbs == null) {
return callbacks;
}
@@ -2947,7 +2820,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
}
final int N = cbs.size();
for (int i=0; i<N; i++) {
- ModeCallback cb = cbs.valueAt(i);
+ OnOpModeChangedListener cb = cbs.valueAt(i);
ArrayList<ChangeRec> reports = callbacks.get(cb);
ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName, previousMode);
if (changed != reports) {
@@ -2990,7 +2863,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
enforceManageAppOpsModes(callingPid, callingUid, reqUid);
- HashMap<ModeCallback, ArrayList<ChangeRec>> callbacks = null;
+ HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks = null;
ArrayList<ChangeRec> allChanges = new ArrayList<>();
synchronized (this) {
boolean changed = false;
@@ -3007,9 +2880,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
uidState.setUidMode(code, AppOpsManager.opToDefaultMode(code));
for (String packageName : getPackagesForUid(uidState.uid)) {
callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
- previousMode, mOpModeWatchers.get(code));
+ previousMode,
+ mAppOpsServiceInterface.getOpModeChangedListeners(code));
callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
- previousMode, mPackageModeWatchers.get(packageName));
+ previousMode, mAppOpsServiceInterface
+ .getPackageModeChangedListeners(packageName));
allChanges = addChange(allChanges, code, uidState.uid,
packageName, previousMode);
@@ -3053,9 +2928,11 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
uidChanged = true;
final int uid = curOp.uidState.uid;
callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
- previousMode, mOpModeWatchers.get(curOp.op));
+ previousMode,
+ mAppOpsServiceInterface.getOpModeChangedListeners(curOp.op));
callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
- previousMode, mPackageModeWatchers.get(packageName));
+ previousMode, mAppOpsServiceInterface
+ .getPackageModeChangedListeners(packageName));
allChanges = addChange(allChanges, curOp.op, uid, packageName,
previousMode);
@@ -3075,7 +2952,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
mUidStates.remove(uidState.uid);
}
if (uidChanged) {
- uidState.evalForegroundOps(mOpModeWatchers);
+ uidState.evalForegroundOps();
}
}
@@ -3084,8 +2961,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
}
}
if (callbacks != null) {
- for (Map.Entry<ModeCallback, ArrayList<ChangeRec>> ent : callbacks.entrySet()) {
- ModeCallback cb = ent.getKey();
+ for (Map.Entry<OnOpModeChangedListener, ArrayList<ChangeRec>> ent
+ : callbacks.entrySet()) {
+ OnOpModeChangedListener cb = ent.getKey();
ArrayList<ChangeRec> reports = ent.getValue();
for (int i=0; i<reports.size(); i++) {
ChangeRec rep = reports.get(i);
@@ -3121,7 +2999,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
final UidState uidState = mUidStates.valueAt(uidi);
if (uidState.foregroundOps != null) {
- uidState.evalForegroundOps(mOpModeWatchers);
+ uidState.evalForegroundOps();
}
}
}
@@ -3169,20 +3047,10 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
mModeWatchers.put(callback.asBinder(), cb);
}
if (switchOp != AppOpsManager.OP_NONE) {
- ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp);
- if (cbs == null) {
- cbs = new ArraySet<>();
- mOpModeWatchers.put(switchOp, cbs);
- }
- cbs.add(cb);
+ mAppOpsServiceInterface.startWatchingOpModeChanged(cb, switchOp);
}
if (mayWatchPackageName) {
- ArraySet<ModeCallback> cbs = mPackageModeWatchers.get(packageName);
- if (cbs == null) {
- cbs = new ArraySet<>();
- mPackageModeWatchers.put(packageName, cbs);
- }
- cbs.add(cb);
+ mAppOpsServiceInterface.startWatchingPackageModeChanged(cb, packageName);
}
evalAllForegroundOpsLocked();
}
@@ -3197,21 +3065,9 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
ModeCallback cb = mModeWatchers.remove(callback.asBinder());
if (cb != null) {
cb.unlinkToDeath();
- for (int i=mOpModeWatchers.size()-1; i>=0; i--) {
- ArraySet<ModeCallback> cbs = mOpModeWatchers.valueAt(i);
- cbs.remove(cb);
- if (cbs.size() <= 0) {
- mOpModeWatchers.removeAt(i);
- }
- }
- for (int i=mPackageModeWatchers.size()-1; i>=0; i--) {
- ArraySet<ModeCallback> cbs = mPackageModeWatchers.valueAt(i);
- cbs.remove(cb);
- if (cbs.size() <= 0) {
- mPackageModeWatchers.removeAt(i);
- }
- }
+ mAppOpsServiceInterface.removeListener(cb);
}
+
evalAllForegroundOpsLocked();
}
}
@@ -4542,12 +4398,14 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
AppOpsService::notifyOpChangedForAllPkgsInUid,
this, code, uidState.uid, true, null));
} else if (uidState.pkgOps != null) {
- final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
- if (callbacks != null) {
- for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
- final ModeCallback callback = callbacks.valueAt(cbi);
- if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
- || !callback.isWatchingUid(uidState.uid)) {
+ final ArraySet<OnOpModeChangedListener> listenerSet =
+ mAppOpsServiceInterface.getOpModeChangedListeners(code);
+ if (listenerSet != null) {
+ for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) {
+ final OnOpModeChangedListener listener = listenerSet.valueAt(cbi);
+ if ((listener.getFlags()
+ & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
+ || !listener.isWatchingUid(uidState.uid)) {
continue;
}
for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
@@ -4558,7 +4416,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
if (op.getMode() == AppOpsManager.MODE_FOREGROUND) {
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyOpChanged,
- this, callback, code, uidState.uid,
+ this, listenerSet.valueAt(cbi), code, uidState.uid,
uidState.pkgOps.keyAt(pkgi)));
}
}
@@ -5045,7 +4903,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
}
}
if (changed) {
- uidState.evalForegroundOps(mOpModeWatchers);
+ uidState.evalForegroundOps();
}
}
}
@@ -5131,7 +4989,7 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
XmlUtils.skipCurrentTag(parser);
}
}
- uidState.evalForegroundOps(mOpModeWatchers);
+ uidState.evalForegroundOps();
}
private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
@@ -6122,62 +5980,17 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
}
pw.println();
}
- if (mOpModeWatchers.size() > 0 && !dumpHistory) {
- boolean printedHeader = false;
- for (int i=0; i<mOpModeWatchers.size(); i++) {
- if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
- continue;
- }
- boolean printedOpHeader = false;
- ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
- for (int j=0; j<callbacks.size(); j++) {
- final ModeCallback cb = callbacks.valueAt(j);
- if (dumpPackage != null
- && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
- continue;
- }
- needSep = true;
- if (!printedHeader) {
- pw.println(" Op mode watchers:");
- printedHeader = true;
- }
- if (!printedOpHeader) {
- pw.print(" Op ");
- pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
- pw.println(":");
- printedOpHeader = true;
- }
- pw.print(" #"); pw.print(j); pw.print(": ");
- pw.println(cb);
- }
- }
- }
- if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
- boolean printedHeader = false;
- for (int i=0; i<mPackageModeWatchers.size(); i++) {
- if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
- continue;
- }
- needSep = true;
- if (!printedHeader) {
- pw.println(" Package mode watchers:");
- printedHeader = true;
- }
- pw.print(" Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
- pw.println(":");
- ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
- for (int j=0; j<callbacks.size(); j++) {
- pw.print(" #"); pw.print(j); pw.print(": ");
- pw.println(callbacks.valueAt(j));
- }
- }
+
+ if (!dumpHistory) {
+ needSep |= mAppOpsServiceInterface.dumpListeners(dumpOp, dumpUid, dumpPackage, pw);
}
+
if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
boolean printedHeader = false;
- for (int i=0; i<mModeWatchers.size(); i++) {
+ for (int i = 0; i < mModeWatchers.size(); i++) {
final ModeCallback cb = mModeWatchers.valueAt(i);
if (dumpPackage != null
- && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+ && dumpUid != UserHandle.getAppId(cb.getWatchingUid())) {
continue;
}
needSep = true;
@@ -6729,16 +6542,15 @@ public class AppOpsService extends IAppOpsService.Stub implements PersistenceSch
}
private void notifyWatchersOfChange(int code, int uid) {
- final ArraySet<ModeCallback> clonedCallbacks;
+ final ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
synchronized (this) {
- ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
- if (callbacks == null) {
+ modeChangedListenerSet = mAppOpsServiceInterface.getOpModeChangedListeners(code);
+ if (modeChangedListenerSet == null) {
return;
}
- clonedCallbacks = new ArraySet<>(callbacks);
}
- notifyOpChanged(clonedCallbacks, code, uid, null);
+ notifyOpChanged(modeChangedListenerSet, code, uid, null);
}
@Override
diff --git a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
index cd5ea120f878..c707086fb2fb 100644
--- a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
+++ b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
@@ -14,12 +14,20 @@
* limitations under the License.
*/
package com.android.server.appop;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager.Mode;
+import android.util.ArraySet;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+
+import java.io.PrintWriter;
+
/**
* Interface for accessing and modifying modes for app-ops i.e. package and uid modes.
- * In the future this interface will also include mode callbacks and op restrictions.
+ * This interface also includes functions for added and removing op mode watchers.
+ * In the future this interface will also include op restrictions.
*/
public interface AppOpsServiceInterface {
/**
@@ -95,4 +103,93 @@ public interface AppOpsServiceInterface {
* Stop tracking app-op modes for all uid and packages.
*/
void clearAllModes();
+
+ /**
+ * Registers changedListener to listen to op's mode change.
+ * @param changedListener the listener that must be trigger on the op's mode change.
+ * @param op op representing the app-op whose mode change needs to be listened to.
+ */
+ void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, int op);
+
+ /**
+ * Registers changedListener to listen to package's app-op's mode change.
+ * @param changedListener the listener that must be trigger on the mode change.
+ * @param packageName of the package whose app-op's mode change needs to be listened to.
+ */
+ void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
+ @NonNull String packageName);
+
+ /**
+ * Stop the changedListener from triggering on any mode change.
+ * @param changedListener the listener that needs to be removed.
+ */
+ void removeListener(@NonNull OnOpModeChangedListener changedListener);
+
+ /**
+ * Temporary API which will be removed once we can safely untangle the methods that use this.
+ * Returns a set of OnOpModeChangedListener that are listening for op's mode changes.
+ * @param op app-op whose mode change is being listened to.
+ */
+ ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op);
+
+ /**
+ * Temporary API which will be removed once we can safely untangle the methods that use this.
+ * Returns a set of OnOpModeChangedListener that are listening for package's op's mode changes.
+ * @param packageName of package whose app-op's mode change is being listened to.
+ */
+ ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(@NonNull String packageName);
+
+ /**
+ * Temporary API which will be removed once we can safely untangle the methods that use this.
+ * Notify that the app-op's mode is changed by triggering the change listener.
+ * @param changedListener the change listener.
+ * @param op App-op whose mode has changed
+ * @param uid user id associated with the app-op
+ * @param packageName package name that is associated with the app-op
+ */
+ void notifyOpChanged(@NonNull OnOpModeChangedListener changedListener, int op, int uid,
+ @Nullable String packageName);
+
+ /**
+ * Temporary API which will be removed once we can safely untangle the methods that use this.
+ * Notify that the app-op's mode is changed to all packages associated with the uid by
+ * triggering the appropriate change listener.
+ * @param op App-op whose mode has changed
+ * @param uid user id associated with the app-op
+ * @param onlyForeground true if only watchers that
+ * @param callbackToIgnore callback that should be ignored.
+ */
+ void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground,
+ @Nullable OnOpModeChangedListener callbackToIgnore);
+
+ /**
+ * TODO: Move hasForegroundWatchers and foregroundOps into this.
+ * Go over the list of app-ops for the uid and mark app-ops with MODE_FOREGROUND in
+ * foregroundOps.
+ * @param uid for which the app-op's mode needs to be marked.
+ * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
+ * @return foregroundOps.
+ */
+ SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps);
+
+ /**
+ * Go over the list of app-ops for the package name and mark app-ops with MODE_FOREGROUND in
+ * foregroundOps.
+ * @param packageName for which the app-op's mode needs to be marked.
+ * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
+ * @return foregroundOps.
+ */
+ SparseBooleanArray evalForegroundPackageOps(String packageName,
+ SparseBooleanArray foregroundOps);
+
+ /**
+ * Dump op mode and package mode listeners and their details.
+ * @param dumpOp if -1 then op mode listeners for all app-ops are dumped. If it's set to an
+ * app-op, only the watchers for that app-op are dumped.
+ * @param dumpUid uid for which we want to dump op mode watchers.
+ * @param dumpPackage if not null and if dumpOp is -1, dumps watchers for the package name.
+ * @param printWriter writer to dump to.
+ */
+ boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, PrintWriter printWriter);
+
}
diff --git a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java b/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
index c27c0d3de5d7..2d498ea2117c 100644
--- a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
+++ b/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
@@ -16,15 +16,39 @@
package com.android.server.appop;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
+import static android.app.AppOpsManager.opRestrictsRead;
+
+import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
+
+import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager.Mode;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import libcore.util.EmptyArray;
+
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Objects;
/**
@@ -33,8 +57,13 @@ import com.android.internal.annotations.VisibleForTesting;
*/
public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface {
- // Should be the same object that the AppOpsService is using for locking.
+ static final String TAG = "LegacyAppOpsServiceInterfaceImpl";
+
+ // Must be the same object that the AppOpsService is using for locking.
final Object mLock;
+ final Handler mHandler;
+ final Context mContext;
+ final SparseArray<int[]> mSwitchedOps;
@GuardedBy("mLock")
@VisibleForTesting
@@ -43,13 +72,25 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface
@GuardedBy("mLock")
final ArrayMap<String, SparseIntArray> mPackageModes = new ArrayMap<>();
+ final SparseArray<ArraySet<OnOpModeChangedListener>> mOpModeWatchers = new SparseArray<>();
+ final ArrayMap<String, ArraySet<OnOpModeChangedListener>> mPackageModeWatchers =
+ new ArrayMap<>();
+
final PersistenceScheduler mPersistenceScheduler;
+ // Constant meaning that any UID should be matched when dispatching callbacks
+ private static final int UID_ANY = -2;
+
+
LegacyAppOpsServiceInterfaceImpl(PersistenceScheduler persistenceScheduler,
- @NonNull Object lock) {
+ @NonNull Object lock, Handler handler, Context context,
+ SparseArray<int[]> switchedOps) {
this.mPersistenceScheduler = persistenceScheduler;
this.mLock = lock;
+ this.mHandler = handler;
+ this.mContext = context;
+ this.mSwitchedOps = switchedOps;
}
@Override
@@ -158,7 +199,6 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface
}
}
-
@Override
public boolean areUidModesDefault(int uid) {
synchronized (mLock) {
@@ -195,4 +235,335 @@ public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface
}
}
-}
+ @Override
+ public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener,
+ int op) {
+ Objects.requireNonNull(changedListener);
+ synchronized (mLock) {
+ ArraySet<OnOpModeChangedListener> modeWatcherSet = mOpModeWatchers.get(op);
+ if (modeWatcherSet == null) {
+ modeWatcherSet = new ArraySet<>();
+ mOpModeWatchers.put(op, modeWatcherSet);
+ }
+ modeWatcherSet.add(changedListener);
+ }
+ }
+
+ @Override
+ public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
+ @NonNull String packageName) {
+ Objects.requireNonNull(changedListener);
+ Objects.requireNonNull(packageName);
+ synchronized (mLock) {
+ ArraySet<OnOpModeChangedListener> modeWatcherSet =
+ mPackageModeWatchers.get(packageName);
+ if (modeWatcherSet == null) {
+ modeWatcherSet = new ArraySet<>();
+ mPackageModeWatchers.put(packageName, modeWatcherSet);
+ }
+ modeWatcherSet.add(changedListener);
+ }
+ }
+
+ @Override
+ public void removeListener(@NonNull OnOpModeChangedListener changedListener) {
+ Objects.requireNonNull(changedListener);
+
+ synchronized (mLock) {
+ for (int i = mOpModeWatchers.size() - 1; i >= 0; i--) {
+ ArraySet<OnOpModeChangedListener> cbs = mOpModeWatchers.valueAt(i);
+ cbs.remove(changedListener);
+ if (cbs.size() <= 0) {
+ mOpModeWatchers.removeAt(i);
+ }
+ }
+
+ for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) {
+ ArraySet<OnOpModeChangedListener> cbs = mPackageModeWatchers.valueAt(i);
+ cbs.remove(changedListener);
+ if (cbs.size() <= 0) {
+ mPackageModeWatchers.removeAt(i);
+ }
+ }
+ }
+ }
+
+ @Override
+ public ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op) {
+ synchronized (mLock) {
+ ArraySet<OnOpModeChangedListener> modeChangedListenersSet = mOpModeWatchers.get(op);
+ if (modeChangedListenersSet == null) {
+ return new ArraySet<>();
+ }
+ return new ArraySet<>(modeChangedListenersSet);
+ }
+ }
+
+ @Override
+ public ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(
+ @NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+
+ synchronized (mLock) {
+ ArraySet<OnOpModeChangedListener> modeChangedListenersSet =
+ mPackageModeWatchers.get(packageName);
+ if (modeChangedListenersSet == null) {
+ return new ArraySet<>();
+ }
+ return new ArraySet<>(modeChangedListenersSet);
+ }
+ }
+
+ @Override
+ public void notifyOpChanged(@NonNull OnOpModeChangedListener onModeChangedListener, int code,
+ int uid, @Nullable String packageName) {
+ Objects.requireNonNull(onModeChangedListener);
+
+ if (uid != UID_ANY && onModeChangedListener.getWatchingUid() >= 0
+ && onModeChangedListener.getWatchingUid() != uid) {
+ return;
+ }
+
+ // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
+ int[] switchedCodes;
+ if (onModeChangedListener.getWatchedOpCode() == ALL_OPS) {
+ switchedCodes = mSwitchedOps.get(code);
+ } else if (onModeChangedListener.getWatchedOpCode() == OP_NONE) {
+ switchedCodes = new int[]{code};
+ } else {
+ switchedCodes = new int[]{onModeChangedListener.getWatchedOpCode()};
+ }
+
+ for (int switchedCode : switchedCodes) {
+ // There are features watching for mode changes such as window manager
+ // and location manager which are in our process. The callbacks in these
+ // features may require permissions our remote caller does not have.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (shouldIgnoreCallback(switchedCode, onModeChangedListener.getCallingPid(),
+ onModeChangedListener.getCallingUid())) {
+ continue;
+ }
+ onModeChangedListener.onOpModeChanged(switchedCode, uid, packageName);
+ } catch (RemoteException e) {
+ /* ignore */
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) {
+ // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission,
+ // as watcher should not use this to signal if the value is changed.
+ return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
+ watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
+ public void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
+ @Nullable OnOpModeChangedListener callbackToIgnore) {
+ String[] uidPackageNames = getPackagesForUid(uid);
+ ArrayMap<OnOpModeChangedListener, ArraySet<String>> callbackSpecs = null;
+
+ synchronized (mLock) {
+ ArraySet<OnOpModeChangedListener> callbacks = mOpModeWatchers.get(code);
+ if (callbacks != null) {
+ final int callbackCount = callbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ OnOpModeChangedListener callback = callbacks.valueAt(i);
+
+ if (onlyForeground && (callback.getFlags()
+ & WATCH_FOREGROUND_CHANGES) == 0) {
+ continue;
+ }
+
+ ArraySet<String> changedPackages = new ArraySet<>();
+ Collections.addAll(changedPackages, uidPackageNames);
+ if (callbackSpecs == null) {
+ callbackSpecs = new ArrayMap<>();
+ }
+ callbackSpecs.put(callback, changedPackages);
+ }
+ }
+
+ for (String uidPackageName : uidPackageNames) {
+ callbacks = mPackageModeWatchers.get(uidPackageName);
+ if (callbacks != null) {
+ if (callbackSpecs == null) {
+ callbackSpecs = new ArrayMap<>();
+ }
+ final int callbackCount = callbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ OnOpModeChangedListener callback = callbacks.valueAt(i);
+
+ if (onlyForeground && (callback.getFlags()
+ & WATCH_FOREGROUND_CHANGES) == 0) {
+ continue;
+ }
+
+ ArraySet<String> changedPackages = callbackSpecs.get(callback);
+ if (changedPackages == null) {
+ changedPackages = new ArraySet<>();
+ callbackSpecs.put(callback, changedPackages);
+ }
+ changedPackages.add(uidPackageName);
+ }
+ }
+ }
+
+ if (callbackSpecs != null && callbackToIgnore != null) {
+ callbackSpecs.remove(callbackToIgnore);
+ }
+ }
+
+ if (callbackSpecs == null) {
+ return;
+ }
+
+ for (int i = 0; i < callbackSpecs.size(); i++) {
+ final OnOpModeChangedListener callback = callbackSpecs.keyAt(i);
+ final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
+ if (reportedPackageNames == null) {
+ mHandler.sendMessage(PooledLambda.obtainMessage(
+ LegacyAppOpsServiceInterfaceImpl::notifyOpChanged,
+ this, callback, code, uid, (String) null));
+
+ } else {
+ final int reportedPackageCount = reportedPackageNames.size();
+ for (int j = 0; j < reportedPackageCount; j++) {
+ final String reportedPackageName = reportedPackageNames.valueAt(j);
+ mHandler.sendMessage(PooledLambda.obtainMessage(
+ LegacyAppOpsServiceInterfaceImpl::notifyOpChanged,
+ this, callback, code, uid, reportedPackageName));
+ }
+ }
+ }
+ }
+
+ private static String[] getPackagesForUid(int uid) {
+ String[] packageNames = null;
+
+ // Very early during boot the package manager is not yet or not yet fully started. At this
+ // time there are no packages yet.
+ if (AppGlobals.getPackageManager() != null) {
+ try {
+ packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+ }
+ if (packageNames == null) {
+ return EmptyArray.STRING;
+ }
+ return packageNames;
+ }
+
+ @Override
+ public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) {
+ synchronized (mLock) {
+ return evalForegroundOps(mUidModes.get(uid), foregroundOps);
+ }
+ }
+
+ @Override
+ public SparseBooleanArray evalForegroundPackageOps(String packageName,
+ SparseBooleanArray foregroundOps) {
+ synchronized (mLock) {
+ return evalForegroundOps(mPackageModes.get(packageName), foregroundOps);
+ }
+ }
+
+ private SparseBooleanArray evalForegroundOps(SparseIntArray opModes,
+ SparseBooleanArray foregroundOps) {
+ SparseBooleanArray tempForegroundOps = foregroundOps;
+ if (opModes != null) {
+ for (int i = opModes.size() - 1; i >= 0; i--) {
+ if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
+ if (tempForegroundOps == null) {
+ tempForegroundOps = new SparseBooleanArray();
+ }
+ evalForegroundWatchers(opModes.keyAt(i), tempForegroundOps);
+ }
+ }
+ }
+ return tempForegroundOps;
+ }
+
+ private void evalForegroundWatchers(int op, SparseBooleanArray foregroundOps) {
+ boolean curValue = foregroundOps.get(op, false);
+ ArraySet<OnOpModeChangedListener> listenerSet = mOpModeWatchers.get(op);
+ if (listenerSet != null) {
+ for (int cbi = listenerSet.size() - 1; !curValue && cbi >= 0; cbi--) {
+ if ((listenerSet.valueAt(cbi).getFlags()
+ & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
+ curValue = true;
+ }
+ }
+ }
+ foregroundOps.put(op, curValue);
+ }
+
+ @Override
+ public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage,
+ PrintWriter printWriter) {
+ boolean needSep = false;
+ if (mOpModeWatchers.size() > 0) {
+ boolean printedHeader = false;
+ for (int i = 0; i < mOpModeWatchers.size(); i++) {
+ if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
+ continue;
+ }
+ boolean printedOpHeader = false;
+ ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
+ mOpModeWatchers.valueAt(i);
+ for (int j = 0; j < modeChangedListenerSet.size(); j++) {
+ final OnOpModeChangedListener listener = modeChangedListenerSet.valueAt(j);
+ if (dumpPackage != null
+ && dumpUid != UserHandle.getAppId(listener.getWatchingUid())) {
+ continue;
+ }
+ needSep = true;
+ if (!printedHeader) {
+ printWriter.println(" Op mode watchers:");
+ printedHeader = true;
+ }
+ if (!printedOpHeader) {
+ printWriter.print(" Op ");
+ printWriter.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
+ printWriter.println(":");
+ printedOpHeader = true;
+ }
+ printWriter.print(" #"); printWriter.print(j); printWriter.print(": ");
+ printWriter.println(listener.toString());
+ }
+ }
+ }
+
+ if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
+ boolean printedHeader = false;
+ for (int i = 0; i < mPackageModeWatchers.size(); i++) {
+ if (dumpPackage != null
+ && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
+ continue;
+ }
+ needSep = true;
+ if (!printedHeader) {
+ printWriter.println(" Package mode watchers:");
+ printedHeader = true;
+ }
+ printWriter.print(" Pkg "); printWriter.print(mPackageModeWatchers.keyAt(i));
+ printWriter.println(":");
+ ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
+ mPackageModeWatchers.valueAt(i);
+
+ for (int j = 0; j < modeChangedListenerSet.size(); j++) {
+ printWriter.print(" #"); printWriter.print(j); printWriter.print(": ");
+ printWriter.println(modeChangedListenerSet.valueAt(j).toString());
+ }
+ }
+ }
+ return needSep;
+ }
+
+} \ No newline at end of file
diff --git a/services/core/java/com/android/server/appop/OnOpModeChangedListener.java b/services/core/java/com/android/server/appop/OnOpModeChangedListener.java
new file mode 100644
index 000000000000..5ebe8119f046
--- /dev/null
+++ b/services/core/java/com/android/server/appop/OnOpModeChangedListener.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 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.appop;
+
+import android.os.RemoteException;
+
+/**
+ * Listener for mode changes, encapsulates methods that should be triggered in the event of a mode
+ * change.
+ */
+abstract class OnOpModeChangedListener {
+
+ // Constant meaning that any UID should be matched when dispatching callbacks
+ private static final int UID_ANY = -2;
+
+ private int mWatchingUid;
+ private int mFlags;
+ private int mWatchedOpCode;
+ private int mCallingUid;
+ private int mCallingPid;
+
+ OnOpModeChangedListener(int watchingUid, int flags, int watchedOpCode, int callingUid,
+ int callingPid) {
+ this.mWatchingUid = watchingUid;
+ this.mFlags = flags;
+ this.mWatchedOpCode = watchedOpCode;
+ this.mCallingUid = callingUid;
+ this.mCallingPid = callingPid;
+ }
+
+ /**
+ * Returns the user id that is watching for the mode change.
+ */
+ public int getWatchingUid() {
+ return mWatchingUid;
+ }
+
+ /**
+ * Returns the flags associated with the mode change listener.
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Get the app-op whose mode change should trigger the callback.
+ */
+ public int getWatchedOpCode() {
+ return mWatchedOpCode;
+ }
+
+ /**
+ * Get the user-id that triggered the app-op mode change to be watched.
+ */
+ public int getCallingUid() {
+ return mCallingUid;
+ }
+
+ /**
+ * Get the process-id that triggered the app-op mode change to be watched.
+ */
+ public int getCallingPid() {
+ return mCallingPid;
+ }
+
+ /**
+ * returns true if the user id passed in the param is the one that is watching for op mode
+ * changed.
+ */
+ public boolean isWatchingUid(int uid) {
+ return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
+ }
+
+ /**
+ * Method that should be triggered when the app-op's mode is changed.
+ * @param op app-op whose mode-change is being listened to.
+ * @param uid user-is associated with the app-op.
+ * @param packageName package name associated with the app-op.
+ */
+ public abstract void onOpModeChanged(int op, int uid, String packageName)
+ throws RemoteException;
+
+ /**
+ * Return human readable string representing the listener.
+ */
+ public abstract String toString();
+
+}