diff options
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(); + +} |