From 29e092bf290bacb980a47da22f722c1542197565 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Sat, 25 Jan 2020 06:54:06 -0800 Subject: [PATCH 1/2] Notify all packages is uid-mode is changed Multiple packages might share a UID, but appOpsService might not have cached the uid->package mapping for those yet. Hence the only way to list all packages for a uid is to ask package manager. setUidMode already handled this correctly, hence factor out the code into notifyOpChangedForAllPkgsInUid and reuse it from commitUidStatePendingLocked. Bug: 148180766 Test: (on master) atest CtsAppOpsTestCases:android.app.appops.cts.ForegroundModeTest Change-Id: I99a8f255a60d3523da7eb36a8f2c9426af1a1fea Merged-In: I2d5d6c7aa38d201707349a137c9c29b7987775be --- .../android/server/appop/AppOpsService.java | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 3e7188c6e8ec3..90d0c3568c13f 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -31,6 +31,7 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION; import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; import static android.app.AppOpsManager.UID_STATE_PERSISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; +import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager.modeToName; import static android.app.AppOpsManager.opToName; import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState; @@ -1288,6 +1289,18 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.evalForegroundOps(mOpModeWatchers); } + notifyOpChangedForAllPkgsInUid(code, uid, false); + notifyOpChangedSync(code, uid, null, mode); + } + + /** + * Notify that an op changed for all packages in an uid. + * + * @param code The op that changed + * @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) { String[] uidPackageNames = getPackagesForUid(uid); ArrayMap> callbackSpecs = null; @@ -1297,6 +1310,10 @@ public class AppOpsService extends IAppOpsService.Stub { final int callbackCount = callbacks.size(); for (int i = 0; i < callbackCount; i++) { ModeCallback callback = callbacks.valueAt(i); + if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + ArraySet changedPackages = new ArraySet<>(); Collections.addAll(changedPackages, uidPackageNames); if (callbackSpecs == null) { @@ -1315,6 +1332,10 @@ public class AppOpsService extends IAppOpsService.Stub { final int callbackCount = callbacks.size(); for (int i = 0; i < callbackCount; i++) { ModeCallback callback = callbacks.valueAt(i); + if (onlyForeground && (callback.mFlags & WATCH_FOREGROUND_CHANGES) == 0) { + continue; + } + ArraySet changedPackages = callbackSpecs.get(callback); if (changedPackages == null) { changedPackages = new ArraySet<>(); @@ -1327,7 +1348,6 @@ public class AppOpsService extends IAppOpsService.Stub { } if (callbackSpecs == null) { - notifyOpChangedSync(code, uid, null, mode); return; } @@ -1349,8 +1369,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - - notifyOpChangedSync(code, uid, null, mode); } private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) { @@ -2496,24 +2514,28 @@ public class AppOpsService extends IAppOpsService.Stub { if (resolvedLastFg == resolvedNowFg) { continue; } - final ArraySet callbacks = mOpModeWatchers.get(code); - if (callbacks != null) { - for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { - final ModeCallback callback = callbacks.valueAt(cbi); - if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 - || !callback.isWatchingUid(uidState.uid)) { - continue; - } - boolean doAllPackages = uidState.opModes != null - && uidState.opModes.indexOfKey(code) >= 0 - && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND; - if (uidState.pkgOps != null) { + + if (uidState.opModes != null + && uidState.opModes.indexOfKey(code) >= 0 + && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND) { + mHandler.sendMessage(PooledLambda.obtainMessage( + AppOpsService::notifyOpChangedForAllPkgsInUid, + this, code, uidState.uid, true)); + } else { + final ArraySet callbacks = mOpModeWatchers.get(code); + if (callbacks != null) { + for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { + final ModeCallback callback = callbacks.valueAt(cbi); + if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 + || !callback.isWatchingUid(uidState.uid)) { + continue; + } for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) { final Op op = uidState.pkgOps.valueAt(pkgi).get(code); if (op == null) { continue; } - if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) { + if (op.mode == AppOpsManager.MODE_FOREGROUND) { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpChanged, this, callback, code, uidState.uid, From ab9be4fdb63bf30831fd2e05be1315e6c7f067ae Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Sat, 25 Jan 2020 06:57:04 -0800 Subject: [PATCH 2/2] Force update uid state when pending uid state is applied Before the state was update lazily when someone interacted with appopsmanager. Since Q the the uid state might change depending on the procState and hence we might need to trigger the opChanged callbacks when the procState is applied. Bug: 148180766 Test: (on master) atest CtsAppOpsTestCases:android.app.appops.cts.ForegroundModeTest Change-Id: I99720a372db6e79eaba30e4563c09e009cffe86f Merged-In: Id974769a4e9d89c01890b7557dd93f8444a3908f --- .../android/server/appop/AppOpsService.java | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 90d0c3568c13f..a5ad42f17912c 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -36,6 +36,8 @@ import static android.app.AppOpsManager.modeToName; import static android.app.AppOpsManager.opToName; import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState; +import static java.lang.Long.max; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -934,6 +936,19 @@ public class AppOpsService extends IAppOpsService.Stub { } } + /** + * Update the pending state for the uid + * + * @param currentTime The current elapsed real time + * @param uid The uid that has a pending state + */ + private void updatePendingState(long currentTime, int uid) { + synchronized (this) { + mLastRealtime = max(currentTime, mLastRealtime); + updatePendingStateIfNeededLocked(mUidStates.get(uid)); + } + } + public void updateUidProcState(int uid, int procState) { synchronized (this) { final UidState uidState = getUidStateLocked(uid, true); @@ -959,7 +974,12 @@ public class AppOpsService extends IAppOpsService.Stub { } else { settleTime = mConstants.BG_STATE_SETTLE_TIME; } - uidState.pendingStateCommitTime = SystemClock.elapsedRealtime() + settleTime; + final long commitTime = SystemClock.elapsedRealtime() + settleTime; + uidState.pendingStateCommitTime = commitTime; + + mHandler.sendMessageDelayed( + PooledLambda.obtainMessage(AppOpsService::updatePendingState, this, + commitTime + 1, uid), settleTime + 1); } if (uidState.startNesting != 0) { // There is some actively running operation... need to find it @@ -2485,6 +2505,18 @@ public class AppOpsService extends IAppOpsService.Stub { uidState = new UidState(uid); mUidStates.put(uid, uidState); } else { + updatePendingStateIfNeededLocked(uidState); + } + return uidState; + } + + /** + * Check if the pending state should be updated and do so if needed + * + * @param uidState The uidState that might have a pending state + */ + private void updatePendingStateIfNeededLocked(@NonNull UidState uidState) { + if (uidState != null) { if (uidState.pendingStateCommitTime != 0) { if (uidState.pendingStateCommitTime < mLastRealtime) { commitUidPendingStateLocked(uidState); @@ -2496,7 +2528,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - return uidState; } private void commitUidPendingStateLocked(UidState uidState) {