diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java index 886add3a3c8e6..012dd9b2995ea 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java @@ -102,6 +102,8 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface final SparseArray> mUserPackageModes = new SparseArray<>(); private final LegacyAppOpStateParser mAppOpsStateParser = new LegacyAppOpStateParser(); + @GuardedBy("mLock") + private List mModeChangedListeners = new ArrayList<>(); final AtomicFile mFile; final Runnable mWriteRunner = new Runnable() { @@ -183,31 +185,39 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface @Override public boolean setUidMode(int uid, int op, int mode) { final int defaultMode = AppOpsManager.opToDefaultMode(op); + List listenersCopy; synchronized (mLock) { SparseIntArray opModes = mUidModes.get(uid, null); - if (opModes == null) { - if (mode != defaultMode) { - opModes = new SparseIntArray(); - mUidModes.put(uid, opModes); - opModes.put(op, mode); - scheduleWriteLocked(); + + int previousMode = defaultMode; + if (opModes != null) { + previousMode = opModes.get(op, defaultMode); + } + if (mode == previousMode) { + return false; + } + + if (mode == defaultMode) { + opModes.delete(op); + if (opModes.size() == 0) { + mUidModes.remove(uid); } } else { - if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) { - return false; + if (opModes == null) { + opModes = new SparseIntArray(); + mUidModes.put(uid, opModes); } - if (mode == defaultMode) { - opModes.delete(op); - if (opModes.size() <= 0) { - opModes = null; - mUidModes.delete(uid); - } - } else { - opModes.put(op, mode); - } - scheduleWriteLocked(); + opModes.put(op, mode); } + + scheduleWriteLocked(); + listenersCopy = new ArrayList<>(mModeChangedListeners); } + + for (int i = 0; i < listenersCopy.size(); i++) { + listenersCopy.get(i).onUidModeChanged(uid, op, mode); + } + return true; } @@ -229,35 +239,52 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface @Override public void setPackageMode(String packageName, int op, @Mode int mode, @UserIdInt int userId) { final int defaultMode = AppOpsManager.opToDefaultMode(op); + List listenersCopy; synchronized (mLock) { ArrayMap packageModes = mUserPackageModes.get(userId, null); - if (packageModes == null) { + if (packageModes == null && mode != defaultMode) { packageModes = new ArrayMap<>(); mUserPackageModes.put(userId, packageModes); } - SparseIntArray opModes = packageModes.get(packageName); - if (opModes == null) { - if (mode != defaultMode) { - opModes = new SparseIntArray(); - packageModes.put(packageName, opModes); - opModes.put(op, mode); - scheduleWriteLocked(); + SparseIntArray opModes = null; + int previousMode = defaultMode; + if (packageModes != null) { + opModes = packageModes.get(packageName); + if (opModes != null) { + previousMode = opModes.get(op, defaultMode); + } + } + + if (mode == previousMode) { + return; + } + + if (mode == defaultMode) { + opModes.delete(op); + if (opModes.size() == 0) { + packageModes.remove(packageName); + if (packageModes.size() == 0) { + mUserPackageModes.remove(userId); + } } } else { - if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) { - return; + if (packageModes == null) { + packageModes = new ArrayMap<>(); + mUserPackageModes.put(userId, packageModes); } - if (mode == defaultMode) { - opModes.delete(op); - if (opModes.size() <= 0) { - opModes = null; - packageModes.remove(packageName); - } - } else { - opModes.put(op, mode); + if (opModes == null) { + opModes = new SparseIntArray(); + packageModes.put(packageName, opModes); } - scheduleWriteLocked(); + opModes.put(op, mode); } + + scheduleFastWriteLocked(); + listenersCopy = new ArrayList<>(mModeChangedListeners); + } + + for (int i = 0; i < listenersCopy.size(); i++) { + listenersCopy.get(i).onPackageModeChanged(packageName, userId, op, mode); } } @@ -633,4 +660,18 @@ public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface return result; } -} \ No newline at end of file + + @Override + public boolean addAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + synchronized (mLock) { + return mModeChangedListeners.add(listener); + } + } + + @Override + public boolean removeAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + synchronized (mLock) { + return mModeChangedListeners.remove(listener); + } + } +} diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java index 76f1f8ada8304..60d17cd388f6f 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java @@ -158,4 +158,46 @@ public interface AppOpsCheckingServiceInterface { * MODE_FOREGROUND for the passed package name and user ID. */ SparseBooleanArray getForegroundOps(String packageName, int userId); + + /** + * Adds a listener for changes in appop modes. These callbacks should be dispatched + * synchronously. + * + * @param listener The listener to be added. + * @return true if the listener was added. + */ + boolean addAppOpsModeChangedListener(@NonNull AppOpsModeChangedListener listener); + + /** + * Removes a listener for changes in appop modes. + * + * @param listener The listener to be removed. + * @return true if the listener was removed. + */ + boolean removeAppOpsModeChangedListener(@NonNull AppOpsModeChangedListener listener); + + /** + * A listener for changes to the AppOps mode. + */ + interface AppOpsModeChangedListener { + + /** + * Invoked when a UID's appop mode is changed. + * + * @param uid The UID whose appop mode was changed. + * @param code The op code that was changed. + * @param mode The new mode. + */ + void onUidModeChanged(int uid, int code, int mode); + + /** + * Invoked when a package's appop mode is changed. + * + * @param packageName The package name whose appop mode was changed. + * @param userId The user ID for the package. + * @param code The op code that was changed. + * @param mode The new mode. + */ + void onPackageModeChanged(@NonNull String packageName, int userId, int code, int mode); + } } diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java index 32dcb5aff8ea6..3fee59bd1c2f1 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceLoggingDecorator.java @@ -141,4 +141,16 @@ public class AppOpsCheckingServiceLoggingDecorator implements AppOpsCheckingServ + ")"); return mService.getForegroundOps(packageName, userId); } + + @Override + public boolean addAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + Log.i(LOG_TAG, "addAppOpsModeChangedListener(listener = " + listener + ")"); + return mService.addAppOpsModeChangedListener(listener); + } + + @Override + public boolean removeAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + Log.i(LOG_TAG, "removeAppOpsModeChangedListener(listener = " + listener + ")"); + return mService.removeAppOpsModeChangedListener(listener); + } } diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java index 91dbc23246ed8..c0cc8b1766134 100644 --- a/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java +++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceTracingDecorator.java @@ -221,4 +221,26 @@ public class AppOpsCheckingServiceTracingDecorator implements AppOpsCheckingServ Trace.traceEnd(TRACE_TAG); } } + + @Override + public boolean addAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + Trace.traceBegin(TRACE_TAG, + "TaggedTracingAppOpsCheckingServiceInterfaceImpl#addAppOpsModeChangedListener"); + try { + return mService.addAppOpsModeChangedListener(listener); + } finally { + Trace.traceEnd(TRACE_TAG); + } + } + + @Override + public boolean removeAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + Trace.traceBegin(TRACE_TAG, + "TaggedTracingAppOpsCheckingServiceInterfaceImpl#removeAppOpsModeChangedListener"); + try { + return mService.removeAppOpsModeChangedListener(listener); + } finally { + Trace.traceEnd(TRACE_TAG); + } + } } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 903c2ba773ff6..111cbfdf7467d 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -399,6 +399,10 @@ public class AppOpsService extends IAppOpsService.Stub { private AppOpsUidStateTracker mUidStateTracker; + /** Callback to skip on next appop update.*/ + @GuardedBy("this") + private IAppOpsCallback mIgnoredCallback = null; + /** Hands the definition of foreground and uid states */ @GuardedBy("this") public AppOpsUidStateTracker getUidStateTracker() { @@ -923,6 +927,59 @@ public class AppOpsService extends IAppOpsService.Stub { mAppOpsCheckingService = new AppOpsCheckingServiceTracingDecorator( new AppOpsCheckingServiceImpl( storageFile, this, handler, context, mSwitchedOps)); + mAppOpsCheckingService.addAppOpsModeChangedListener( + new AppOpsCheckingServiceInterface.AppOpsModeChangedListener() { + @Override + public void onUidModeChanged(int uid, int code, int mode) { + notifyOpChangedForAllPkgsInUid(code, uid, false); + } + + @Override + public void onPackageModeChanged(String packageName, int userId, int code, + int mode) { + ArraySet repCbs = null; + int uid = -1; + synchronized (AppOpsService.this) { + ArraySet cbs = + mOpModeWatchers.get(code); + if (cbs != null) { + if (repCbs == null) { + repCbs = new ArraySet<>(); + } + repCbs.addAll(cbs); + } + cbs = mPackageModeWatchers.get(packageName); + if (cbs != null) { + if (repCbs == null) { + repCbs = new ArraySet<>(); + } + repCbs.addAll(cbs); + } + if (repCbs != null && mIgnoredCallback != null) { + repCbs.remove(mModeWatchers.get(mIgnoredCallback.asBinder())); + } + uid = getPackageManagerInternal().getPackageUid(packageName, + PackageManager.MATCH_KNOWN_PACKAGES, userId); + Op op = getOpLocked(code, uid, packageName, null, false, null, + /* edit */ false); + if (op != null && mode == AppOpsManager.opToDefaultMode(op.op)) { + // If going into the default mode, prune this op + // if there is nothing else interesting in it. + pruneOpLocked(op, uid, packageName); + } + scheduleFastWriteLocked(); + if (mode != MODE_ERRORED) { + updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid); + } + } + + if (repCbs != null && uid != -1) { + mHandler.sendMessage(PooledLambda.obtainMessage( + AppOpsService::notifyOpChanged, + AppOpsService.this, repCbs, code, uid, packageName)); + } + } + }); //mAppOpsCheckingService = new AppOpsCheckingServiceLoggingDecorator( // LocalServices.getService(AppOpsCheckingServiceInterface.class)); mAppOpsRestrictions = new AppOpsRestrictionsImpl(context, handler, @@ -1363,7 +1420,7 @@ public class AppOpsService extends IAppOpsService.Stub { && uidState.getUidMode(code) == AppOpsManager.MODE_FOREGROUND) { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpChangedForAllPkgsInUid, - this, code, uidState.uid, true, null)); + this, code, uidState.uid, true)); } else if (!uidState.pkgOps.isEmpty()) { final ArraySet listenerSet = mOpModeWatchers.get(code); @@ -1830,6 +1887,7 @@ public class AppOpsService extends IAppOpsService.Stub { previousMode = MODE_DEFAULT; } + mIgnoredCallback = permissionPolicyCallback; if (!uidState.setUidMode(code, mode)) { return; } @@ -1838,8 +1896,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } - notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback); - notifyOpChangedSync(code, uid, null, mode, previousMode); + notifyStorageManagerOpModeChangedSync(code, uid, null, mode, previousMode); } /** @@ -1849,8 +1906,7 @@ public class AppOpsService extends IAppOpsService.Stub { * @param uid The uid the op was changed for * @param onlyForeground Only notify watchers that watch for foreground changes */ - private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground, - @Nullable IAppOpsCallback callbackToIgnore) { + private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground) { String[] uidPackageNames = getPackagesForUid(uid); ArrayMap> callbackSpecs = null; synchronized (this) { @@ -1903,8 +1959,8 @@ public class AppOpsService extends IAppOpsService.Stub { } } - if (callbackSpecs != null && callbackToIgnore != null) { - callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder())); + if (callbackSpecs != null && mIgnoredCallback != null) { + callbackSpecs.remove(mModeWatchers.get(mIgnoredCallback.asBinder())); } } @@ -2023,8 +2079,8 @@ public class AppOpsService extends IAppOpsService.Stub { } } - private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode, - int previousMode) { + private void notifyStorageManagerOpModeChangedSync(int code, int uid, + @NonNull String packageName, int mode, int previousMode) { final StorageManagerInternal storageManagerInternal = LocalServices.getService(StorageManagerInternal.class); if (storageManagerInternal != null) { @@ -2053,7 +2109,6 @@ public class AppOpsService extends IAppOpsService.Stub { return; } - ArraySet repCbs = null; code = AppOpsManager.opToSwitch(code); PackageVerificationResult pvr; @@ -2070,49 +2125,17 @@ public class AppOpsService extends IAppOpsService.Stub { int previousMode = MODE_DEFAULT; synchronized (this) { - UidState uidState = getUidStateLocked(uid, false); Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ true); if (op != null) { if (op.getMode() != mode) { previousMode = op.getMode(); + mIgnoredCallback = permissionPolicyCallback; op.setMode(mode); - ArraySet cbs = - mOpModeWatchers.get(code); - if (cbs != null) { - if (repCbs == null) { - repCbs = new ArraySet<>(); - } - repCbs.addAll(cbs); - } - cbs = mPackageModeWatchers.get(packageName); - if (cbs != null) { - if (repCbs == null) { - repCbs = new ArraySet<>(); - } - repCbs.addAll(cbs); - } - if (repCbs != null && permissionPolicyCallback != null) { - repCbs.remove(mModeWatchers.get(permissionPolicyCallback.asBinder())); - } - if (mode == AppOpsManager.opToDefaultMode(op.op)) { - // If going into the default mode, prune this op - // if there is nothing else interesting in it. - pruneOpLocked(op, uid, packageName); - } - scheduleFastWriteLocked(); - if (mode != MODE_ERRORED) { - updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid); - } } } } - if (repCbs != null) { - mHandler.sendMessage(PooledLambda.obtainMessage( - AppOpsService::notifyOpChanged, - this, repCbs, code, uid, packageName)); - } - notifyOpChangedSync(code, uid, packageName, mode, previousMode); + notifyStorageManagerOpModeChangedSync(code, uid, packageName, mode, previousMode); } private void notifyOpChanged(ArraySet callbacks, int code, @@ -2349,7 +2372,7 @@ public class AppOpsService extends IAppOpsService.Stub { int numChanges = allChanges.size(); for (int i = 0; i < numChanges; i++) { ChangeRec change = allChanges.get(i); - notifyOpChangedSync(change.op, change.uid, change.pkg, + notifyStorageManagerOpModeChangedSync(change.op, change.uid, change.pkg, AppOpsManager.opToDefaultMode(change.op), change.previous_mode); } } diff --git a/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java b/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java index c605375e1d3f5..de73a5514792e 100644 --- a/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java +++ b/services/core/java/com/android/server/appop/AppOpsServiceTestingShim.java @@ -201,4 +201,28 @@ public class AppOpsServiceTestingShim implements AppOpsCheckingServiceInterface return newVal; } + + @Override + public boolean addAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + boolean oldVal = mOldImplementation.addAppOpsModeChangedListener(listener); + boolean newVal = mNewImplementation.addAppOpsModeChangedListener(listener); + + if (oldVal != newVal) { + signalImplDifference("addAppOpsModeChangedListener"); + } + + return newVal; + } + + @Override + public boolean removeAppOpsModeChangedListener(AppOpsModeChangedListener listener) { + boolean oldVal = mOldImplementation.removeAppOpsModeChangedListener(listener); + boolean newVal = mNewImplementation.removeAppOpsModeChangedListener(listener); + + if (oldVal != newVal) { + signalImplDifference("removeAppOpsModeChangedListener"); + } + + 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 2c290a3bef27d..5b91ad9834df5 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 @@ -20,43 +20,40 @@ import android.app.AppOpsManager import android.os.Handler import android.os.UserHandle import android.util.ArrayMap -import android.util.SparseArray +import android.util.ArraySet import android.util.SparseBooleanArray import android.util.SparseIntArray import com.android.internal.annotations.VisibleForTesting -import com.android.internal.util.ArrayUtils import com.android.server.appop.AppOpsCheckingServiceInterface +import com.android.server.appop.AppOpsCheckingServiceInterface.AppOpsModeChangedListener 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.collection.forEachIndexed +import com.android.server.permission.access.collection.set class AppOpService( private val service: AccessCheckingService ) : AppOpsCheckingServiceInterface { private val packagePolicy = service.getSchemePolicy(PackageUri.SCHEME, AppOpUri.SCHEME) as PackageAppOpPolicy - private val uidPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) + private val appIdPolicy = service.getSchemePolicy(UidUri.SCHEME, AppOpUri.SCHEME) as AppIdAppOpPolicy private val context = service.context private lateinit var handler: Handler - private lateinit var lock: Any - private lateinit var switchedOps: SparseArray + + @Volatile + private var listeners = ArraySet() + private val listenersLock = Any() fun initialize() { // TODO(b/252883039): Wrong handler. Inject main thread handler here. handler = Handler(context.mainLooper) - // TODO(b/252883039): Wrong lock object. Inject AppOpsService here. - lock = Any() - switchedOps = SparseArray() - for (switchedCode in 0 until AppOpsManager._NUM_OP) { - val switchCode = AppOpsManager.opToSwitch(switchedCode) - switchedOps.put(switchCode, - ArrayUtils.appendInt(switchedOps.get(switchCode), switchedCode)) - } + appIdPolicy.addOnAppOpModeChangedListener(OnAppIdAppOpModeChangedListener()) + packagePolicy.addOnAppOpModeChangedListener(OnPackageAppOpModeChangedListener()) } @VisibleForTesting @@ -90,16 +87,14 @@ class AppOpService( val userId = UserHandle.getUserId(uid) val opName = AppOpsManager.opToPublicName(op) return service.getState { - with(uidPolicy) { getAppOpMode(appId, userId, opName) } + with(appIdPolicy) { getAppOpMode(appId, userId, opName) } } } private fun getUidModes(uid: Int): ArrayMap? { val appId = UserHandle.getAppId(uid) val userId = UserHandle.getUserId(uid) - return service.getState { - with(uidPolicy) { getAppOpModes(appId, userId) } - }?.map + return service.getState { with(appIdPolicy) { getAppOpModes(appId, userId) } }?.map } override fun setUidMode(uid: Int, op: Int, mode: Int): Boolean { @@ -108,7 +103,7 @@ class AppOpService( val opName = AppOpsManager.opToPublicName(op) var wasChanged = false service.mutateState { - wasChanged = with(uidPolicy) { setAppOpMode(appId, userId, opName, mode) } + wasChanged = with(appIdPolicy) { setAppOpMode(appId, userId, opName, mode) } } return wasChanged } @@ -137,7 +132,7 @@ class AppOpService( val appId = UserHandle.getAppId(uid) val userId = UserHandle.getUserId(uid) service.mutateState { - with(uidPolicy) { removeAppOpModes(appId, userId) } + with(appIdPolicy) { removeAppOpModes(appId, userId) } } } @@ -194,4 +189,89 @@ class AppOpService( } } } + + override fun addAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean { + synchronized(listenersLock) { + val newListeners = ArraySet(listeners) + val result = newListeners.add(listener) + listeners = newListeners + return result + } + } + + override fun removeAppOpsModeChangedListener(listener: AppOpsModeChangedListener): Boolean { + synchronized(listenersLock) { + val newListeners = ArraySet(listeners) + val result = newListeners.remove(listener) + listeners = newListeners + return result + } + } + + inner class OnAppIdAppOpModeChangedListener : AppIdAppOpPolicy.OnAppOpModeChangedListener() { + // (uid, appOpCode) -> newMode + val pendingChanges = ArrayMap, Int>() + + override fun onAppOpModeChanged( + appId: Int, + userId: Int, + appOpName: String, + oldMode: Int, + newMode: Int + ) { + val uid = UserHandle.getUid(userId, appId) + val appOpCode = AppOpsManager.strOpToOp(appOpName) + val key = Pair(uid, appOpCode) + + pendingChanges[key] = newMode + } + + override fun onStateMutated() { + val listenersLocal = listeners + pendingChanges.forEachIndexed { _, key, mode -> + listenersLocal.forEachIndexed { _, listener -> + val uid = key.first + val appOpCode = key.second + + listener.onUidModeChanged(uid, appOpCode, mode) + } + } + + pendingChanges.clear() + } + } + + private inner class OnPackageAppOpModeChangedListener : + PackageAppOpPolicy.OnAppOpModeChangedListener() { + // (packageName, userId, appOpCode) -> newMode + val pendingChanges = ArrayMap, Int>() + + override fun onAppOpModeChanged( + packageName: String, + userId: Int, + appOpName: String, + oldMode: Int, + newMode: Int + ) { + val appOpCode = AppOpsManager.strOpToOp(appOpName) + val key = Triple(packageName, userId, appOpCode) + + pendingChanges[key] = newMode + } + + override fun onStateMutated() { + val listenersLocal = listeners + pendingChanges.forEachIndexed { _, key, mode -> + listenersLocal.forEachIndexed { _, listener -> + val packageName = key.first + val userId = key.second + val appOpCode = key.third + + listener.onPackageModeChanged(packageName, userId, appOpCode, mode) + } + } + + pendingChanges.clear() + } + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 12853cd8a750d..24bc57e5bbac0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -40,6 +40,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; @@ -163,6 +164,8 @@ public class AppOpsServiceTest { when(mockPackageManagerInternal.getPackageStateInternal(sMyPackageName)) .thenReturn(mockMyPSInternal); when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg); + when(mockPackageManagerInternal.getPackageUid(eq(sMyPackageName), anyLong(), + eq(getUserId(mMyUid)))).thenReturn(mMyUid); doReturn(mockPackageManagerInternal).when( () -> LocalServices.getService(PackageManagerInternal.class));