From 58c02458cdb815632c42953578ebab7cb0bd2c8e Mon Sep 17 00:00:00 2001 From: Evan Severson Date: Thu, 23 Mar 2023 14:43:16 -0700 Subject: [PATCH] Move appop watcher logic into AppOpsService The interface is intended to be for queries about the raw data state. We also remove the foregroundOps cache that is used for dispatching foreground mode changes; since we now have to do more computation on foreground changes to dispatch callbacks the performance impact has been briefly analyzed to show that onUidStateChanged is not a highly frequently called method and went from .05ms to 0.07ms to execute. This was calculated by running CtsAppOpsTestCAses and tracing. Test: atest CtsAppOpsTestCases Fixes: 268696066 Change-Id: I96700653496984aa3333b174abf2ceb3c1790b10 --- .../appop/AppOpsCheckingServiceImpl.java | 380 ++---------------- .../appop/AppOpsCheckingServiceInterface.java | 105 +---- ...AppOpsCheckingServiceLoggingDecorator.java | 84 +--- ...AppOpsCheckingServiceTracingDecorator.java | 122 +----- .../server/appop/AppOpsRestrictions.java | 7 + .../server/appop/AppOpsRestrictionsImpl.java | 13 +- .../android/server/appop/AppOpsService.java | 339 +++++++++++----- .../appop/AppOpsServiceTestingShim.java | 103 +---- .../permission/access/appop/AppOpService.kt | 324 +-------------- .../appop/AppOpsLegacyRestrictionsTest.java | 9 +- 10 files changed, 325 insertions(+), 1161 deletions(-) diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java index f520f6a9ef492..cb2c54349c6d0 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java @@ -17,32 +17,21 @@ package com.android.server.appop; import static android.app.AppOpsManager.MODE_ALLOWED; -import static android.app.AppOpsManager.OP_NONE; +import static android.app.AppOpsManager.MODE_FOREGROUND; import static android.app.AppOpsManager.OP_SCHEDULE_EXACT_ALARM; -import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; -import static android.app.AppOpsManager.opRestrictsRead; import static android.app.AppOpsManager.opToDefaultMode; -import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; - -import android.Manifest; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManager.Mode; import android.content.Context; -import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.UserPackage; import android.os.AsyncTask; -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.AtomicFile; import android.util.Slog; import android.util.SparseArray; @@ -53,15 +42,12 @@ import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; -import com.android.internal.util.function.pooled.PooledLambda; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.LocalServices; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.PermissionManagerServiceInternal; -import libcore.util.EmptyArray; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -70,11 +56,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Objects; /** @@ -128,10 +111,6 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface @GuardedBy("mLock") final SparseArray> mUserPackageModes = new SparseArray<>(); - final SparseArray> mOpModeWatchers = new SparseArray<>(); - final ArrayMap> mPackageModeWatchers = - new ArrayMap<>(); - final AtomicFile mFile; final Runnable mWriteRunner = new Runnable() { public void run() { @@ -153,10 +132,6 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface boolean mWriteScheduled; boolean mFastWriteScheduled; - - // Constant meaning that any UID should be matched when dispatching callbacks - private static final int UID_ANY = -2; - AppOpsCheckingServiceImpl(File storageFile, @NonNull Object lock, Handler handler, Context context, SparseArray switchedOps) { @@ -351,348 +326,43 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface } @Override - public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, - int op) { - Objects.requireNonNull(changedListener); + public SparseBooleanArray getForegroundOps(int uid) { + SparseBooleanArray result = new SparseBooleanArray(); synchronized (mLock) { - ArraySet modeWatcherSet = mOpModeWatchers.get(op); - if (modeWatcherSet == null) { - modeWatcherSet = new ArraySet<>(); - mOpModeWatchers.put(op, modeWatcherSet); + SparseIntArray modes = mUidModes.get(uid); + if (modes == null) { + return result; + } + for (int i = 0; i < modes.size(); i++) { + if (modes.valueAt(i) == MODE_FOREGROUND) { + result.put(modes.keyAt(i), true); + } } - modeWatcherSet.add(changedListener); } + + return result; } @Override - public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener, - @NonNull String packageName) { - Objects.requireNonNull(changedListener); - Objects.requireNonNull(packageName); + public SparseBooleanArray getForegroundOps(String packageName, int userId) { + SparseBooleanArray result = new SparseBooleanArray(); synchronized (mLock) { - ArraySet modeWatcherSet = - mPackageModeWatchers.get(packageName); - if (modeWatcherSet == null) { - modeWatcherSet = new ArraySet<>(); - mPackageModeWatchers.put(packageName, modeWatcherSet); + ArrayMap packageModes = mUserPackageModes.get(userId); + if (packageModes == null) { + return result; } - 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 cbs = mOpModeWatchers.valueAt(i); - cbs.remove(changedListener); - if (cbs.size() <= 0) { - mOpModeWatchers.removeAt(i); - } + SparseIntArray modes = packageModes.get(packageName); + if (modes == null) { + return result; } - - for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) { - ArraySet cbs = mPackageModeWatchers.valueAt(i); - cbs.remove(changedListener); - if (cbs.size() <= 0) { - mPackageModeWatchers.removeAt(i); - } - } - } - } - - @Override - public ArraySet getOpModeChangedListeners(int op) { - synchronized (mLock) { - ArraySet modeChangedListenersSet = mOpModeWatchers.get(op); - if (modeChangedListenersSet == null) { - return new ArraySet<>(); - } - return new ArraySet<>(modeChangedListenersSet); - } - } - - @Override - public ArraySet getPackageModeChangedListeners( - @NonNull String packageName) { - Objects.requireNonNull(packageName); - - synchronized (mLock) { - ArraySet modeChangedListenersSet = - mPackageModeWatchers.get(packageName); - if (modeChangedListenersSet == null) { - return new ArraySet<>(); - } - return new ArraySet<>(modeChangedListenersSet); - } - } - - @Override - public void notifyWatchersOfChange(int code, int uid) { - ArraySet listenerSet = getOpModeChangedListeners(code); - if (listenerSet == null) { - return; - } - for (int i = 0; i < listenerSet.size(); i++) { - final OnOpModeChangedListener listener = listenerSet.valueAt(i); - notifyOpChanged(listener, code, uid, null); - } - } - - @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> callbackSpecs = null; - - synchronized (mLock) { - ArraySet 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 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 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 reportedPackageNames = callbackSpecs.valueAt(i); - if (reportedPackageNames == null) { - mHandler.sendMessage(PooledLambda.obtainMessage( - AppOpsCheckingServiceImpl::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( - AppOpsCheckingServiceImpl::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, @UserIdInt int userId) { - synchronized (mLock) { - ArrayMap packageModes = mUserPackageModes.get(userId, null); - return evalForegroundOps(packageModes == null ? null : packageModes.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 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 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()); + for (int i = 0; i < modes.size(); i++) { + if (modes.valueAt(i) == MODE_FOREGROUND) { + result.put(modes.keyAt(i), true); } } } - 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 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; + return result; } private void scheduleWriteLocked() { diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java index 90968983d4d7f..76f1f8ada8304 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java @@ -16,17 +16,13 @@ package com.android.server.appop; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager.Mode; -import android.util.ArraySet; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; -import java.io.PrintWriter; - /** * Interface for accessing and modifying modes for app-ops i.e. package and uid modes. * This interface also includes functions for added and removing op mode watchers. @@ -148,99 +144,18 @@ public interface AppOpsCheckingServiceInterface { 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. + * @param uid UID to query foreground ops for. + * @return SparseBooleanArray where the keys are the op codes for which their modes are + * MODE_FOREGROUND for the passed UID. */ - void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, int op); + SparseBooleanArray getForegroundOps(int uid); /** - * 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. + * + * @param packageName Package name to check for. + * @param userId User ID to check for. + * @return SparseBooleanArray where the keys are the op codes for which their modes are + * MODE_FOREGROUND for the passed package name and user ID. */ - 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 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 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 op App-op whose mode has changed - * @param uid user id associated with the app-op (or, if UID_ANY, notifies all users) - */ - void notifyWatchersOfChange(int op, int uid); - - /** - * 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. - * @param userId user id associated with the package. - * @return foregroundOps. - */ - SparseBooleanArray evalForegroundPackageOps(String packageName, - SparseBooleanArray foregroundOps, @UserIdInt int userId); - - /** - * 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); + SparseBooleanArray getForegroundOps(String packageName, int userId); } diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java index 0094b86975bbe..32dcb5aff8ea6 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java @@ -17,14 +17,10 @@ package com.android.server.appop; import android.annotation.NonNull; -import android.annotation.Nullable; -import android.util.ArraySet; import android.util.Log; import android.util.SparseBooleanArray; import android.util.SparseIntArray; -import java.io.PrintWriter; - /** * Logging decorator for {@link AppOpsCheckingServiceInterface}. */ @@ -134,83 +130,15 @@ public class AppOpsCheckingServiceLoggingDecorator implements AppOpsCheckingServ } @Override - public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, - int op) { - Log.i(LOG_TAG, "startWatchingOpModeChanged(changedListener = " + changedListener + ", op = " - + op + ")"); - mService.startWatchingOpModeChanged(changedListener, op); + public SparseBooleanArray getForegroundOps(int uid) { + Log.i(LOG_TAG, "getForegroundOps(uid = " + uid + ")"); + return mService.getForegroundOps(uid); } @Override - public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener, - @NonNull String packageName) { - Log.i(LOG_TAG, "startWatchingPackageModeChanged(changedListener = " + changedListener - + ", packageName = " + packageName + ")"); - mService.startWatchingPackageModeChanged(changedListener, packageName); - } - - @Override - public void removeListener(@NonNull OnOpModeChangedListener changedListener) { - Log.i(LOG_TAG, "removeListener(changedListener = " + changedListener + ")"); - mService.removeListener(changedListener); - } - - @Override - public ArraySet getOpModeChangedListeners(int op) { - Log.i(LOG_TAG, "getOpModeChangedListeners(op = " + op + ")"); - return mService.getOpModeChangedListeners(op); - } - - @Override - public ArraySet getPackageModeChangedListeners( - @NonNull String packageName) { - Log.i(LOG_TAG, "getPackageModeChangedListeners(packageName = " + packageName + ")"); - return mService.getPackageModeChangedListeners(packageName); - } - - @Override - public void notifyWatchersOfChange(int op, int uid) { - Log.i(LOG_TAG, "notifyWatchersOfChange(op = " + op + ", uid = " + uid + ")"); - mService.notifyWatchersOfChange(op, uid); - } - - @Override - public void notifyOpChanged(@NonNull OnOpModeChangedListener changedListener, int op, int uid, - @Nullable String packageName) { - Log.i(LOG_TAG, "notifyOpChanged(changedListener = " + changedListener + ", op = " + op - + ", uid = " + uid + ", packageName = " + packageName + ")"); - mService.notifyOpChanged(changedListener, op, uid, packageName); - } - - @Override - public void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground, - @Nullable OnOpModeChangedListener callbackToIgnore) { - Log.i(LOG_TAG, "notifyOpChangedForAllPkgsInUid(op = " + op + ", uid = " + uid - + ", onlyForeground = " + onlyForeground + ", callbackToIgnore = " - + callbackToIgnore + ")"); - mService.notifyOpChangedForAllPkgsInUid(op, uid, onlyForeground, callbackToIgnore); - } - - @Override - public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) { - Log.i(LOG_TAG, "evalForegroundUidOps(uid = " + uid + ", foregroundOps = " + foregroundOps + public SparseBooleanArray getForegroundOps(String packageName, int userId) { + Log.i(LOG_TAG, "getForegroundOps(packageName = " + packageName + ", userId = " + userId + ")"); - return mService.evalForegroundUidOps(uid, foregroundOps); - } - - @Override - public SparseBooleanArray evalForegroundPackageOps(String packageName, - SparseBooleanArray foregroundOps, int userId) { - Log.i(LOG_TAG, "evalForegroundPackageOps(packageName = " + packageName - + ", foregroundOps = " + foregroundOps + ", userId = " + userId + ")"); - return mService.evalForegroundPackageOps(packageName, foregroundOps, userId); - } - - @Override - public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, - PrintWriter printWriter) { - Log.i(LOG_TAG, "dumpListeners(dumpOp = " + dumpOp + ", dumpUid = " + dumpUid - + ", dumpPackage = " + dumpPackage + ", printWriter = " + printWriter + ")"); - return mService.dumpListeners(dumpOp, dumpUid, dumpPackage, printWriter); + return mService.getForegroundOps(packageName, userId); } } diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java index a028ae16da2f3..91dbc23246ed8 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java @@ -17,16 +17,12 @@ package com.android.server.appop; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.os.Trace; -import android.util.ArraySet; import android.util.SparseBooleanArray; import android.util.SparseIntArray; -import java.io.PrintWriter; - /** * Surrounds all AppOpsCheckingServiceInterface method calls with Trace.traceBegin and * Trace.traceEnd. These traces are used for performance testing. @@ -205,128 +201,22 @@ public class AppOpsCheckingServiceTracingDecorator implements AppOpsCheckingServ } @Override - public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, - int op) { + public SparseBooleanArray getForegroundOps(int uid) { Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#startWatchingOpModeChanged"); + "TaggedTracingAppOpsCheckingServiceInterfaceImpl#getForegroundOps"); try { - mService.startWatchingOpModeChanged(changedListener, op); + return mService.getForegroundOps(uid); } finally { Trace.traceEnd(TRACE_TAG); } } @Override - public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener, - @NonNull String packageName) { + public SparseBooleanArray getForegroundOps(String packageName, int userId) { Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#startWatchingPackageModeChanged"); + "TaggedTracingAppOpsCheckingServiceInterfaceImpl#getForegroundOps"); try { - mService.startWatchingPackageModeChanged(changedListener, packageName); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public void removeListener(@NonNull OnOpModeChangedListener changedListener) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#removeListener"); - try { - mService.removeListener(changedListener); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public ArraySet getOpModeChangedListeners(int op) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#getOpModeChangedListeners"); - try { - return mService.getOpModeChangedListeners(op); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public ArraySet getPackageModeChangedListeners( - @NonNull String packageName) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#getPackageModeChangedListeners"); - try { - return mService.getPackageModeChangedListeners(packageName); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public void notifyWatchersOfChange(int op, int uid) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#notifyWatchersOfChange"); - try { - mService.notifyWatchersOfChange(op, uid); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public void notifyOpChanged(@NonNull OnOpModeChangedListener changedListener, int op, int uid, - @Nullable String packageName) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#notifyOpChanged"); - try { - mService.notifyOpChanged(changedListener, op, uid, packageName); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground, - @Nullable OnOpModeChangedListener callbackToIgnore) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#notifyOpChangedForAllPkgsInUid"); - try { - mService.notifyOpChangedForAllPkgsInUid(op, uid, onlyForeground, callbackToIgnore); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#evalForegroundUidOps"); - try { - return mService.evalForegroundUidOps(uid, foregroundOps); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public SparseBooleanArray evalForegroundPackageOps(String packageName, - SparseBooleanArray foregroundOps, @UserIdInt int userId) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#evalForegroundPackageOps"); - try { - return mService.evalForegroundPackageOps(packageName, foregroundOps, userId); - } finally { - Trace.traceEnd(TRACE_TAG); - } - } - - @Override - public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, - PrintWriter printWriter) { - Trace.traceBegin(TRACE_TAG, - "TaggedTracingAppOpsCheckingServiceInterfaceImpl#dumpListeners"); - try { - return mService.dumpListeners(dumpOp, dumpUid, dumpPackage, printWriter); + return mService.getForegroundOps(packageName, userId); } finally { Trace.traceEnd(TRACE_TAG); } diff --git a/services/core/java/com/android/server/appop/AppOpsRestrictions.java b/services/core/java/com/android/server/appop/AppOpsRestrictions.java index f7ccd3429f114..0241d02f364bd 100644 --- a/services/core/java/com/android/server/appop/AppOpsRestrictions.java +++ b/services/core/java/com/android/server/appop/AppOpsRestrictions.java @@ -144,4 +144,11 @@ public interface AppOpsRestrictions { */ void dumpRestrictions(PrintWriter printWriter, int dumpOp, String dumpPackage, boolean showUserRestrictions); + + /** + * Listener for when an appop restriction is removed. + */ + interface AppOpsRestrictionRemovedListener { + void onAppOpsRestrictionRemoved(int code); + } } diff --git a/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java b/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java index f51200f2bf0c3..ae93991d3945a 100644 --- a/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java +++ b/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java @@ -42,7 +42,8 @@ public class AppOpsRestrictionsImpl implements AppOpsRestrictions { private Context mContext; private Handler mHandler; - private AppOpsCheckingServiceInterface mAppOpsCheckingServiceInterface; + + private AppOpsRestrictionRemovedListener mAppOpsRestrictionRemovedListener; // Map from (Object token) to (int code) to (boolean restricted) private final ArrayMap mGlobalRestrictions = new ArrayMap<>(); @@ -56,10 +57,10 @@ public class AppOpsRestrictionsImpl implements AppOpsRestrictions { mUserRestrictionExcludedPackageTags = new ArrayMap<>(); public AppOpsRestrictionsImpl(Context context, Handler handler, - AppOpsCheckingServiceInterface appOpsCheckingServiceInterface) { + AppOpsRestrictionRemovedListener appOpsRestrictionRemovedListener) { mContext = context; mHandler = handler; - mAppOpsCheckingServiceInterface = appOpsCheckingServiceInterface; + mAppOpsRestrictionRemovedListener = appOpsRestrictionRemovedListener; } @Override @@ -211,15 +212,11 @@ public class AppOpsRestrictionsImpl implements AppOpsRestrictions { return allRestrictedCodes; } - // TODO: For clearUserRestrictions, we are calling notifyOpChanged from within the - // LegacyAppOpsServiceInterfaceImpl class. But, for all other changes to restrictions, we're - // calling it from within AppOpsService. This is awkward, and we should probably do it one - // way or the other. private void notifyAllUserRestrictions(SparseBooleanArray allUserRestrictedCodes) { int restrictedCodesSize = allUserRestrictedCodes.size(); for (int j = 0; j < restrictedCodesSize; j++) { int code = allUserRestrictedCodes.keyAt(j); - mHandler.post(() -> mAppOpsCheckingServiceInterface.notifyWatchersOfChange(code, UID_ANY)); + mHandler.post(() -> mAppOpsRestrictionRemovedListener.onAppOpsRestrictionRemoved(code)); } } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a46dd47ad3d83..719bb64fad981 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -52,6 +52,7 @@ import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED; import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM; import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS; import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE; +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; @@ -292,6 +293,11 @@ public class AppOpsService extends IAppOpsService.Stub { private final ArrayMap, ArrayList> mUnforwardedAsyncNotedOps = new ArrayMap<>(); + private final SparseArray> mOpModeWatchers = + new SparseArray<>(); + private final ArrayMap> mPackageModeWatchers = + new ArrayMap<>(); + boolean mWriteNoteOpsScheduled; boolean mWriteScheduled; @@ -315,6 +321,8 @@ public class AppOpsService extends IAppOpsService.Stub { @GuardedBy("this") @VisibleForTesting final SparseArray mUidStates = new SparseArray<>(); + @GuardedBy("this") + private boolean mUidStatesInitialized; volatile @NonNull HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this); @@ -341,8 +349,6 @@ public class AppOpsService extends IAppOpsService.Stub { */ private final SparseArray mSwitchedOps = new SparseArray<>(); - private ActivityManagerInternal mActivityManagerInternal; - /** Package sampled for message collection in the current session */ @GuardedBy("this") private String mSampledPackage = null; @@ -505,11 +511,6 @@ public class AppOpsService extends IAppOpsService.Stub { @NonNull public final ArrayMap pkgOps = new ArrayMap<>(); - // 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; - public UidState(int uid) { this.uid = uid; } @@ -540,25 +541,6 @@ public class AppOpsService extends IAppOpsService.Stub { return getUidStateTracker().evalMode(uid, op, mode); } - public void evalForegroundOps() { - foregroundOps = null; - foregroundOps = mAppOpsCheckingService.evalForegroundUidOps(uid, foregroundOps); - for (int i = pkgOps.size() - 1; i >= 0; i--) { - foregroundOps = mAppOpsCheckingService - .evalForegroundPackageOps(pkgOps.valueAt(i).packageName, foregroundOps, - UserHandle.getUserId(uid)); - } - hasForegroundWatchers = false; - if (foregroundOps != null) { - for (int i = 0; i < foregroundOps.size(); i++) { - if (foregroundOps.valueAt(i)) { - hasForegroundWatchers = true; - break; - } - } - } - } - @SuppressWarnings("GuardedBy") public int getState() { return getUidStateTracker().getUidState(uid); @@ -940,7 +922,8 @@ public class AppOpsService extends IAppOpsService.Stub { storageFile, this, handler, context, mSwitchedOps)); //mAppOpsCheckingService = new AppOpsCheckingServiceLoggingDecorator( // LocalServices.getService(AppOpsCheckingServiceInterface.class)); - mAppOpsRestrictions = new AppOpsRestrictionsImpl(context, handler, mAppOpsCheckingService); + mAppOpsRestrictions = new AppOpsRestrictionsImpl(context, handler, + code -> notifyWatchersOfChange(code, UID_ANY)); LockGuard.installLock(this, LockGuard.INDEX_APP_OPS); mStorageFile = new AtomicFile(storageFile, "appops_legacy"); @@ -1108,8 +1091,7 @@ public class AppOpsService extends IAppOpsService.Stub { for (int code : OPS_RESTRICTED_ON_SUSPEND) { ArraySet onModeChangedListeners; synchronized (AppOpsService.this) { - onModeChangedListeners = - mAppOpsCheckingService.getOpModeChangedListeners(code); + onModeChangedListeners = mOpModeWatchers.get(code); if (onModeChangedListeners == null) { continue; } @@ -1149,8 +1131,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } }); - - mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); } @VisibleForTesting @@ -1222,6 +1202,7 @@ public class AppOpsService extends IAppOpsService.Stub { for (int uid : NON_PACKAGE_UIDS) { mUidStates.put(uid, new UidState(uid)); } + mUidStatesInitialized = true; } } @@ -1265,8 +1246,6 @@ public class AppOpsService extends IAppOpsService.Stub { ops.put(code, new Op(uidState, packageName, code, uid)); } } - - uidState.evalForegroundOps(); } /** @@ -1342,12 +1321,40 @@ public class AppOpsService extends IAppOpsService.Stub { synchronized (this) { UidState uidState = getUidStateLocked(uid, false); - if (uidState != null && foregroundModeMayChange && uidState.hasForegroundWatchers) { - for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) { - if (!uidState.foregroundOps.valueAt(fgi)) { + boolean hasForegroundWatchers = false; + + for (int i = 0; i < mModeWatchers.size(); i++) { + ModeCallback cb = mModeWatchers.valueAt(i); + if (cb.isWatchingUid(uid) && (cb.getFlags() & WATCH_FOREGROUND_CHANGES) != 0) { + hasForegroundWatchers = true; + break; + } + } + + if (uidState != null && foregroundModeMayChange && hasForegroundWatchers) { + + SparseBooleanArray foregroundOps = new SparseBooleanArray(); + + SparseBooleanArray uidForegroundOps = mAppOpsCheckingService.getForegroundOps(uid); + for (int i = 0; i < uidForegroundOps.size(); i++) { + foregroundOps.put(uidForegroundOps.keyAt(i), true); + } + String[] uidPackageNames = getPackagesForUid(uid); + + int userId = UserHandle.getUserId(uid); + for (String packageName : uidPackageNames) { + SparseBooleanArray packageForegroundOps = + mAppOpsCheckingService.getForegroundOps(packageName, userId); + for (int i = 0; i < packageForegroundOps.size(); i++) { + foregroundOps.put(packageForegroundOps.keyAt(i), true); + } + } + + for (int fgi = foregroundOps.size() - 1; fgi >= 0; fgi--) { + if (!foregroundOps.valueAt(fgi)) { continue; } - final int code = uidState.foregroundOps.keyAt(fgi); + final int code = foregroundOps.keyAt(fgi); if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code) && uidState.getUidMode(code) == AppOpsManager.MODE_FOREGROUND) { @@ -1356,7 +1363,7 @@ public class AppOpsService extends IAppOpsService.Stub { this, code, uidState.uid, true, null)); } else if (!uidState.pkgOps.isEmpty()) { final ArraySet listenerSet = - mAppOpsCheckingService.getOpModeChangedListeners(code); + mOpModeWatchers.get(code); if (listenerSet != null) { for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) { final OnOpModeChangedListener listener = listenerSet.valueAt(cbi); @@ -1822,7 +1829,6 @@ public class AppOpsService extends IAppOpsService.Stub { if (!uidState.setUidMode(code, mode)) { return; } - uidState.evalForegroundOps(); if (mode != MODE_ERRORED && mode != previousMode) { updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid); } @@ -1841,10 +1847,81 @@ public class AppOpsService extends IAppOpsService.Stub { */ private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, @Nullable IAppOpsCallback callbackToIgnore) { - ModeCallback listenerToIgnore = callbackToIgnore != null - ? mModeWatchers.get(callbackToIgnore.asBinder()) : null; - mAppOpsCheckingService.notifyOpChangedForAllPkgsInUid(code, uid, onlyForeground, - listenerToIgnore); + String[] uidPackageNames = getPackagesForUid(uid); + ArrayMap> callbackSpecs = null; + synchronized (this) { + ArraySet 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 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 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 OnOpModeChangedListener callback = callbackSpecs.keyAt(i); + final ArraySet 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)); + } + } + } } private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) { @@ -1991,19 +2068,15 @@ public class AppOpsService extends IAppOpsService.Stub { if (op.getMode() != mode) { previousMode = op.getMode(); op.setMode(mode); - - if (uidState != null) { - uidState.evalForegroundOps(); - } ArraySet cbs = - mAppOpsCheckingService.getOpModeChangedListeners(code); + mOpModeWatchers.get(code); if (cbs != null) { if (repCbs == null) { repCbs = new ArraySet<>(); } repCbs.addAll(cbs); } - cbs = mAppOpsCheckingService.getPackageModeChangedListeners(packageName); + cbs = mPackageModeWatchers.get(packageName); if (cbs != null) { if (repCbs == null) { repCbs = new ArraySet<>(); @@ -2042,9 +2115,42 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private void notifyOpChanged(OnOpModeChangedListener callback, int code, + private void notifyOpChanged(OnOpModeChangedListener onModeChangedListener, int code, int uid, String packageName) { - mAppOpsCheckingService.notifyOpChanged(callback, code, uid, 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 static ArrayList addChange(ArrayList reports, @@ -2143,11 +2249,9 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.setUidMode(code, newMode); for (String packageName : getPackagesForUid(uidState.uid)) { callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, - previousMode, - mAppOpsCheckingService.getOpModeChangedListeners(code)); + previousMode, mOpModeWatchers.get(code)); callbacks = addCallbacks(callbacks, code, uidState.uid, packageName, - previousMode, mAppOpsCheckingService - .getPackageModeChangedListeners(packageName)); + previousMode, mPackageModeWatchers.get(packageName)); allChanges = addChange(allChanges, code, uidState.uid, packageName, previousMode); @@ -2196,11 +2300,9 @@ public class AppOpsService extends IAppOpsService.Stub { uidChanged = true; final int uid = curOp.uidState.uid; callbacks = addCallbacks(callbacks, curOp.op, uid, packageName, - previousMode, - mAppOpsCheckingService.getOpModeChangedListeners(curOp.op)); + previousMode, mOpModeWatchers.get(curOp.op)); callbacks = addCallbacks(callbacks, curOp.op, uid, packageName, - previousMode, mAppOpsCheckingService - .getPackageModeChangedListeners(packageName)); + previousMode, mPackageModeWatchers.get(packageName)); allChanges = addChange(allChanges, curOp.op, uid, packageName, previousMode); @@ -2216,9 +2318,6 @@ public class AppOpsService extends IAppOpsService.Stub { UserHandle.getUserId(uidState.uid)); } } - if (uidChanged) { - uidState.evalForegroundOps(); - } } if (changed) { @@ -2295,15 +2394,6 @@ public class AppOpsService extends IAppOpsService.Stub { dpmi.resetOp(op, packageName, userId); } - private void evalAllForegroundOpsLocked() { - for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) { - final UidState uidState = mUidStates.valueAt(uidi); - if (uidState.foregroundOps != null) { - uidState.evalForegroundOps(); - } - } - } - @Override public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) { startWatchingModeWithFlags(op, packageName, 0, callback); @@ -2347,12 +2437,21 @@ public class AppOpsService extends IAppOpsService.Stub { mModeWatchers.put(callback.asBinder(), cb); } if (switchOp != AppOpsManager.OP_NONE) { - mAppOpsCheckingService.startWatchingOpModeChanged(cb, switchOp); + ArraySet cbs = mOpModeWatchers.get(switchOp); + if (cbs == null) { + cbs = new ArraySet<>(); + mOpModeWatchers.put(switchOp, cbs); + } + cbs.add(cb); } if (mayWatchPackageName) { - mAppOpsCheckingService.startWatchingPackageModeChanged(cb, packageName); + ArraySet cbs = mPackageModeWatchers.get(packageName); + if (cbs == null) { + cbs = new ArraySet<>(); + mPackageModeWatchers.put(packageName, cbs); + } + cbs.add(cb); } - evalAllForegroundOpsLocked(); } } @@ -2365,10 +2464,21 @@ public class AppOpsService extends IAppOpsService.Stub { ModeCallback cb = mModeWatchers.remove(callback.asBinder()); if (cb != null) { cb.unlinkToDeath(); - mAppOpsCheckingService.removeListener(cb); + for (int i = mOpModeWatchers.size() - 1; i >= 0; i--) { + ArraySet cbs = mOpModeWatchers.valueAt(i); + cbs.remove(cb); + if (cbs.size() <= 0) { + mOpModeWatchers.removeAt(i); + } + } + for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) { + ArraySet cbs = mPackageModeWatchers.valueAt(i); + cbs.remove(cb); + if (cbs.size() <= 0) { + mPackageModeWatchers.removeAt(i); + } + } } - - evalAllForegroundOpsLocked(); } } @@ -3721,7 +3831,7 @@ public class AppOpsService extends IAppOpsService.Stub { /** * Create a restriction description matching the properties of the package. * - * @param pkg The package to create the restriction description for + * @param packageState The package to create the restriction description for * * @return The restriction matching the package */ @@ -5151,8 +5261,55 @@ public class AppOpsService extends IAppOpsService.Stub { pw.println(); } - if (!dumpHistory) { - needSep |= mAppOpsCheckingService.dumpListeners(dumpOp, dumpUid, dumpPackage, pw); + 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 callbacks = mOpModeWatchers.valueAt(i); + for (int j = 0; j < callbacks.size(); j++) { + final OnOpModeChangedListener cb = callbacks.valueAt(j); + if (dumpPackage != null + && dumpUid != UserHandle.getAppId(cb.getWatchingUid())) { + 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 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 (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) { @@ -5352,11 +5509,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - if (uidState.foregroundOps != null && !hasOp) { - if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) { - hasOp = true; - } - } if (!hasOp || !hasPackage || !hasMode) { continue; } @@ -5364,21 +5516,6 @@ public class AppOpsService extends IAppOpsService.Stub { pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":"); uidState.dump(pw, nowElapsed); - if (uidState.foregroundOps != null && (dumpMode < 0 - || dumpMode == AppOpsManager.MODE_FOREGROUND)) { - pw.println(" foregroundOps:"); - for (int j = 0; j < uidState.foregroundOps.size(); j++) { - if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) { - continue; - } - pw.print(" "); - pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j))); - pw.print(": "); - pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT"); - } - pw.print(" hasForegroundWatchers="); - pw.println(uidState.hasForegroundWatchers); - } needSep = true; if (opModes != null) { @@ -5580,7 +5717,7 @@ public class AppOpsService extends IAppOpsService.Stub { private void notifyWatchersOfChange(int code, int uid) { final ArraySet modeChangedListenerSet; synchronized (this) { - modeChangedListenerSet = mAppOpsCheckingService.getOpModeChangedListeners(code); + modeChangedListenerSet = mOpModeWatchers.get(code); if (modeChangedListenerSet == null) { return; } diff --git a/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java b/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java index 6aaf19049f005..c605375e1d3f5 100644 --- a/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java +++ b/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java @@ -16,11 +16,9 @@ package com.android.server.appop; -import android.util.ArraySet; import android.util.SparseBooleanArray; import android.util.SparseIntArray; -import java.io.PrintWriter; import java.util.Objects; /** @@ -181,109 +179,24 @@ public class AppOpsServiceTestingShim implements AppOpsCheckingServiceInterface } @Override - public void startWatchingOpModeChanged(OnOpModeChangedListener changedListener, int op) { - mOldImplementation.startWatchingOpModeChanged(changedListener, op); - mNewImplementation.startWatchingOpModeChanged(changedListener, op); - } - - @Override - public void startWatchingPackageModeChanged(OnOpModeChangedListener changedListener, - String packageName) { - mOldImplementation.startWatchingPackageModeChanged(changedListener, packageName); - mNewImplementation.startWatchingPackageModeChanged(changedListener, packageName); - } - - @Override - public void removeListener(OnOpModeChangedListener changedListener) { - mOldImplementation.removeListener(changedListener); - mNewImplementation.removeListener(changedListener); - } - - @Override - public ArraySet getOpModeChangedListeners(int op) { - ArraySet oldVal = mOldImplementation.getOpModeChangedListeners(op); - ArraySet newVal = mNewImplementation.getOpModeChangedListeners(op); + public SparseBooleanArray getForegroundOps(int uid) { + SparseBooleanArray oldVal = mOldImplementation.getForegroundOps(uid); + SparseBooleanArray newVal = mNewImplementation.getForegroundOps(uid); if (!Objects.equals(oldVal, newVal)) { - signalImplDifference("getOpModeChangedListeners"); + signalImplDifference("getForegroundOps"); } return newVal; } @Override - public ArraySet getPackageModeChangedListeners(String packageName) { - ArraySet oldVal = mOldImplementation - .getPackageModeChangedListeners(packageName); - ArraySet newVal = mNewImplementation - .getPackageModeChangedListeners(packageName); + public SparseBooleanArray getForegroundOps(String packageName, int userId) { + SparseBooleanArray oldVal = mOldImplementation.getForegroundOps(packageName, userId); + SparseBooleanArray newVal = mNewImplementation.getForegroundOps(packageName, userId); if (!Objects.equals(oldVal, newVal)) { - signalImplDifference("getPackageModeChangedListeners"); - } - - return newVal; - } - - @Override - public void notifyWatchersOfChange(int op, int uid) { - mOldImplementation.notifyWatchersOfChange(op, uid); - mNewImplementation.notifyWatchersOfChange(op, uid); - } - - @Override - public void notifyOpChanged(OnOpModeChangedListener changedListener, int op, int uid, - String packageName) { - mOldImplementation.notifyOpChanged(changedListener, op, uid, packageName); - mNewImplementation.notifyOpChanged(changedListener, op, uid, packageName); - } - - @Override - public void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground, - OnOpModeChangedListener callbackToIgnore) { - mOldImplementation - .notifyOpChangedForAllPkgsInUid(op, uid, onlyForeground, callbackToIgnore); - mNewImplementation - .notifyOpChangedForAllPkgsInUid(op, uid, onlyForeground, callbackToIgnore); - } - - @Override - public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) { - SparseBooleanArray oldVal = mOldImplementation.evalForegroundUidOps(uid, foregroundOps); - SparseBooleanArray newVal = mNewImplementation.evalForegroundUidOps(uid, foregroundOps); - - if (!Objects.equals(oldVal, newVal)) { - signalImplDifference("evalForegroundUidOps"); - } - - return newVal; - } - - @Override - public SparseBooleanArray evalForegroundPackageOps(String packageName, - SparseBooleanArray foregroundOps, int userId) { - SparseBooleanArray oldVal = mOldImplementation - .evalForegroundPackageOps(packageName, foregroundOps, userId); - SparseBooleanArray newVal = mNewImplementation - .evalForegroundPackageOps(packageName, foregroundOps, userId); - - if (!Objects.equals(oldVal, newVal)) { - signalImplDifference("evalForegroundPackageOps"); - } - - return newVal; - } - - @Override - public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, - PrintWriter printWriter) { - boolean oldVal = mOldImplementation - .dumpListeners(dumpOp, dumpUid, dumpPackage, printWriter); - boolean newVal = mNewImplementation - .dumpListeners(dumpOp, dumpUid, dumpPackage, printWriter); - - if (oldVal != newVal) { - signalImplDifference("dumpListeners"); + signalImplDifference("getForegroundOps"); } return newVal; diff --git a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt index 4caf6cc257b50..17c92acd84a27 100644 --- a/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt +++ b/services/permission/java/com/android/server/permission/access/appop/AppOpService.kt @@ -16,30 +16,21 @@ package com.android.server.permission.access.appop -import android.Manifest -import android.annotation.UserIdInt -import android.app.AppGlobals import android.app.AppOpsManager -import android.content.pm.PackageManager -import android.os.Binder import android.os.Handler -import android.os.RemoteException import android.os.UserHandle -import android.util.SparseBooleanArray import android.util.SparseIntArray import com.android.internal.annotations.VisibleForTesting import com.android.internal.util.ArrayUtils -import com.android.internal.util.function.pooled.PooledLambda import com.android.server.appop.AppOpsCheckingServiceInterface -import com.android.server.appop.OnOpModeChangedListener import com.android.server.permission.access.AccessCheckingService import com.android.server.permission.access.AppOpUri import com.android.server.permission.access.PackageUri import com.android.server.permission.access.UidUri -import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports -import com.android.server.permission.access.util.hasBits -import libcore.util.EmptyArray -import java.io.PrintWriter +import com.android.server.permission.access.collection.IndexedMap +import com.android.server.permission.access.collection.IntBooleanMap +import com.android.server.permission.access.collection.IntMap +import com.android.server.permission.access.collection.forEachIndexed class AppOpService( private val service: AccessCheckingService @@ -184,308 +175,23 @@ class AppOpService( // and we have our own persistence. } - // code -> listeners - private val opModeWatchers = IntMap>() - - // packageName -> listeners - private val packageModeWatchers = IndexedMap>() - - override fun startWatchingOpModeChanged(changedListener: OnOpModeChangedListener, op: Int) { - synchronized(lock) { - opModeWatchers.getOrPut(op) { IndexedSet() } += changedListener - } - } - - override fun startWatchingPackageModeChanged( - changedListener: OnOpModeChangedListener, - packageName: String - ) { - synchronized(lock) { - packageModeWatchers.getOrPut(packageName) { IndexedSet() } += changedListener - } - } - - override fun removeListener(changedListener: OnOpModeChangedListener) { - synchronized(lock) { - opModeWatchers.removeAllIndexed { _, _, listeners -> - listeners -= changedListener - listeners.isEmpty() - } - packageModeWatchers.removeAllIndexed { _, _, listeners -> - listeners -= changedListener - listeners.isEmpty() - } - } - } - - override fun getOpModeChangedListeners(op: Int): IndexedSet { - synchronized(lock) { - val listeners = opModeWatchers[op] - return if (listeners == null) { - IndexedSet() - } else { - IndexedSet(listeners) - } - } - } - - override fun getPackageModeChangedListeners( - packageName: String - ): IndexedSet { - synchronized(lock) { - val listeners = packageModeWatchers[packageName] - return if (listeners == null) { - IndexedSet() - } else { - IndexedSet(listeners) - } - } - } - - override fun notifyWatchersOfChange(op: Int, uid: Int) { - val listeners = getOpModeChangedListeners(op) - listeners.forEachIndexed { _, listener -> - notifyOpChanged(listener, op, uid, null) - } - } - - override fun notifyOpChanged( - changedListener: OnOpModeChangedListener, - op: Int, - uid: Int, - packageName: String? - ) { - if (uid != UID_ANY && - changedListener.watchingUid >= 0 && - changedListener.watchingUid != uid - ) { - return - } - - // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE - val switchedCodes = when (changedListener.watchedOpCode) { - ALL_OPS -> switchedOps.get(op) - AppOpsManager.OP_NONE -> intArrayOf(op) - else -> intArrayOf(changedListener.watchedOpCode) - } - - for (switchedCode in 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. - val identity = Binder.clearCallingIdentity() - try { - if (!shouldIgnoreCallback(switchedCode, changedListener)) { - changedListener.onOpModeChanged(switchedCode, uid, packageName) - } - } catch (e: RemoteException) { - /* ignore */ - } finally { - Binder.restoreCallingIdentity(identity) - } - } - } - - private fun shouldIgnoreCallback(op: Int, listener: OnOpModeChangedListener): Boolean { - // 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 AppOpsManager.opRestrictsRead(op) && context.checkPermission( - Manifest.permission.MANAGE_APPOPS, - listener.callingPid, - listener.callingUid - ) != PackageManager.PERMISSION_GRANTED - } - - /** - * Construct a map from each listener (listening to the given op, uid) to all of its associated - * packageNames (by reverse-indexing opModeWatchers and packageModeWatchers), then invoke - * notifyOpChanged for each listener. - */ - override fun notifyOpChangedForAllPkgsInUid( - op: Int, - uid: Int, - onlyForeground: Boolean, - callbackToIgnore: OnOpModeChangedListener? - ) { - val uidPackageNames = getPackagesForUid(uid) - val callbackSpecs = IndexedMap>() - - fun associateListenerWithPackageNames( - listener: OnOpModeChangedListener, - packageNames: Array - ) { - val listenerIsForeground = - listener.flags.hasBits(AppOpsManager.WATCH_FOREGROUND_CHANGES) - if (onlyForeground && !listenerIsForeground) { - return - } - val changedPackages = callbackSpecs.getOrPut(listener) { IndexedSet() } - changedPackages.addAll(packageNames) - } - - synchronized(lock) { - // Collect all listeners from opModeWatchers and pckageModeWatchers - val listeners = opModeWatchers[op] - listeners?.forEachIndexed { _, listener -> - associateListenerWithPackageNames(listener, uidPackageNames) - } - uidPackageNames.forEachIndexed { _, uidPackageName -> - val packageListeners = packageModeWatchers[uidPackageName] - packageListeners?.forEachIndexed { _, listener -> - associateListenerWithPackageNames(listener, arrayOf(uidPackageName)) - } - } - // Remove ignored listeners - if (callbackToIgnore != null) { - callbackSpecs.remove(callbackToIgnore) - } - } - - // For each (listener, packageName) pair, invoke notifyOpChanged - callbackSpecs.forEachIndexed { _, listener, reportedPackageNames -> - reportedPackageNames.forEachIndexed { _, reportedPackageName -> - handler.sendMessage( - PooledLambda.obtainMessage( - AppOpService::notifyOpChanged, this, listener, - op, uid, reportedPackageName - ) - ) - } - } - } - - private fun getPackagesForUid(uid: Int): Array { - // Very early during boot the package manager is not yet or not yet fully started. At this - // time there are no packages yet. - return try { - AppGlobals.getPackageManager()?.getPackagesForUid(uid) ?: EmptyArray.STRING - } catch (e: RemoteException) { - EmptyArray.STRING - } - } - - override fun evalForegroundUidOps( - uid: Int, - foregroundOps: SparseBooleanArray? - ): SparseBooleanArray? { - synchronized(lock) { - val uidModes = getUidModes(uid) - return evalForegroundOps(uidModes, foregroundOps) - } - } - - override fun evalForegroundPackageOps( - packageName: String, - foregroundOps: SparseBooleanArray?, - @UserIdInt userId: Int - ): SparseBooleanArray? { - synchronized(lock) { - val ops = service.getState { getPackageModes(packageName, userId) } - return evalForegroundOps(ops, foregroundOps) - } - } - - private fun evalForegroundOps( - ops: IndexedMap?, - foregroundOps: SparseBooleanArray? - ): SparseBooleanArray? { - var foregroundOps = foregroundOps - ops?.forEachIndexed { _, opName, opMode -> - if (opMode == AppOpsManager.MODE_FOREGROUND) { - if (foregroundOps == null) { - foregroundOps = SparseBooleanArray() - } - evalForegroundWatchers(opName, foregroundOps!!) - } - } - return foregroundOps - } - - private fun evalForegroundWatchers(opName: String, foregroundOps: SparseBooleanArray) { - val opCode = AppOpsManager.strOpToOp(opName) - val listeners = opModeWatchers[opCode] - val hasForegroundListeners = foregroundOps[opCode] || listeners?.anyIndexed { _, listener -> - listener.flags.hasBits(AppOpsManager.WATCH_FOREGROUND_CHANGES) - } ?: false - foregroundOps.put(opCode, hasForegroundListeners) - } - - override fun dumpListeners( - dumpOp: Int, - dumpUid: Int, - dumpPackage: String?, - printWriter: PrintWriter - ): Boolean { - var needSep = false - if (opModeWatchers.size() > 0) { - var printedHeader = false - opModeWatchers.forEachIndexed { _, op, modeChangedListenerSet -> - if (dumpOp >= 0 && dumpOp != op) { - return@forEachIndexed // continue - } - val opName = AppOpsManager.opToName(op) - var printedOpHeader = false - modeChangedListenerSet.forEachIndexed listenerLoop@ { listenerIndex, listener -> - with(printWriter) { - if (dumpPackage != null && - dumpUid != UserHandle.getAppId(listener.watchingUid)) { - return@listenerLoop // continue - } - needSep = true - if (!printedHeader) { - println(" Op mode watchers:") - printedHeader = true - } - if (!printedOpHeader) { - print(" Op ") - print(opName) - println(":") - printedOpHeader = true - } - print(" #") - print(listenerIndex) - print(opName) - print(": ") - println(listener.toString()) - } + override fun getForegroundOps(uid: Int): IntBooleanMap { + return IntBooleanMap().apply { + getUidModes(uid)?.forEachIndexed { _, code, mode -> + if (mode == AppOpsManager.MODE_FOREGROUND) { + put(AppOpsManager.strOpToOp(code), true) } } } + } - if (packageModeWatchers.size > 0 && dumpOp < 0) { - var printedHeader = false - packageModeWatchers.forEachIndexed { _, packageName, listeners -> - with(printWriter) { - if (dumpPackage != null && dumpPackage != packageName) { - return@forEachIndexed // continue - } - needSep = true - if (!printedHeader) { - println(" Package mode watchers:") - printedHeader = true - } - print(" Pkg ") - print(packageName) - println(":") - listeners.forEachIndexed { listenerIndex, listener -> - print(" #") - print(listenerIndex) - print(": ") - println(listener.toString()) - } + override fun getForegroundOps(packageName: String, userId: Int): IntBooleanMap { + return IntBooleanMap().apply { + getPackageModes(packageName, userId)?.forEachIndexed { _, code, mode -> + if (mode == AppOpsManager.MODE_FOREGROUND) { + put(AppOpsManager.strOpToOp(code), true) } } } - return needSep - } - - companion object { - private val LOG_TAG = AppOpService::class.java.simpleName - - // Constant meaning that any UID should be matched when dispatching callbacks - private const val UID_ANY = -2 - - // If watchedOpCode==ALL_OPS, notify for ops affected by the switch-op - private const val ALL_OPS = -2 } } diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java index 021d01cca381c..197342874b2aa 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java @@ -57,7 +57,7 @@ public class AppOpsLegacyRestrictionsTest { Handler mHandler; @Mock - AppOpsCheckingServiceInterface mLegacyAppOpsService; + AppOpsRestrictions.AppOpsRestrictionRemovedListener mRestrictionRemovedListener; AppOpsRestrictions mAppOpsRestrictions; @@ -75,7 +75,8 @@ public class AppOpsLegacyRestrictionsTest { r.run(); return true; }); - mAppOpsRestrictions = new AppOpsRestrictionsImpl(mContext, mHandler, mLegacyAppOpsService); + mAppOpsRestrictions = new AppOpsRestrictionsImpl(mContext, mHandler, + mRestrictionRemovedListener); } @After @@ -271,7 +272,7 @@ public class AppOpsLegacyRestrictionsTest { public void testNotify() { mAppOpsRestrictions.setUserRestriction(mClientToken, mUserId1, mOpCode1, true, null); mAppOpsRestrictions.clearUserRestrictions(mClientToken); - Mockito.verify(mLegacyAppOpsService, Mockito.times(1)) - .notifyWatchersOfChange(mOpCode1, UID_ANY); + Mockito.verify(mRestrictionRemovedListener, Mockito.times(1)) + .onAppOpsRestrictionRemoved(mOpCode1); } }