diff options
| author | 2020-02-06 18:21:52 +0000 | |
|---|---|---|
| committer | 2020-02-06 18:21:52 +0000 | |
| commit | 053dbad9fd598965f4f99cc2a717934107d27b14 (patch) | |
| tree | 1dfbfda1779486865ef491ba47dee00d719ed715 | |
| parent | 8301f05cd78f1fff3197d225515dd082ebbd606e (diff) | |
| parent | fe2fc3a9bc878cf34fedd665f9214bad6c43aafa (diff) | |
Merge changes from topic "AppOpsFgBackgroundMode"
* changes:
Package manager is not ready when reading app-ops state
Use setUidMode when reading state
Expose syntax for app-ops settings as test-api
Callback startWatchingMode with the right op
Force update uid state when pending uid state is applied
Notify all packages is uid-mode is changed
| -rw-r--r-- | api/test-current.txt | 3 | ||||
| -rw-r--r-- | core/java/android/app/AppOpsManager.java | 46 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 4 | ||||
| -rw-r--r-- | services/core/java/com/android/server/appop/AppOpsService.java | 240 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml (renamed from services/tests/servicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml) | 0 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java | 3 | ||||
| -rw-r--r-- | services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java (renamed from services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java) | 28 |
7 files changed, 238 insertions, 86 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index d3e7ea161fc6..e1f83822609d 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -183,6 +183,9 @@ package android.app { field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0 field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1 field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2 + field public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time"; + field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time"; + field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time"; field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover"; field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications"; field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 861d41d4ce88..dfbaea10973d 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -27,6 +27,8 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.app.usage.UsageStatsManager; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; @@ -101,6 +103,18 @@ import java.util.function.Supplier; @SystemService(Context.APP_OPS_SERVICE) public class AppOpsManager { /** + * This is a subtle behavior change to {@link #startWatchingMode}. + * + * Before this change the system called back for the switched op. After the change the system + * will call back for the actually requested op or all switched ops if no op is specified. + * + * @hide + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + public static final long CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE = 148180766L; + + /** * <p>App ops allows callers to:</p> * * <ul> @@ -147,6 +161,38 @@ public class AppOpsManager { static IBinder sClientId; + /** + * How many seconds we want for a drop in uid state from top to settle before applying it. + * + * <>Set a parameter to {@link android.provider.Settings.Global#APP_OPS_CONSTANTS} + * + * @hide + */ + @TestApi + public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time"; + + /** + * How many second we want for a drop in uid state from foreground to settle before applying it. + * + * <>Set a parameter to {@link android.provider.Settings.Global#APP_OPS_CONSTANTS} + * + * @hide + */ + @TestApi + public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = + "fg_service_state_settle_time"; + + /** + * How many seconds we want for a drop in uid state from background to settle before applying + * it. + * + * <>Set a parameter to {@link android.provider.Settings.Global#APP_OPS_CONSTANTS} + * + * @hide + */ + @TestApi + public static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time"; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, prefix = { "HISTORICAL_MODE_" }, value = { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 12b1cbf877a3..3ad96ea193bf 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -2617,7 +2617,7 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessCpuThread.start(); mBatteryStatsService.publish(); - mAppOpsService.publish(mContext); + mAppOpsService.publish(); Slog.d("AppOps", "AppOpsService published"); LocalServices.addService(ActivityManagerInternal.class, mInternal); mActivityTaskManager.onActivityManagerInternalAdded(); @@ -19510,7 +19510,7 @@ public class ActivityManagerService extends IActivityManager.Stub } public AppOpsService getAppOpsService(File file, Handler handler) { - return new AppOpsService(file, handler); + return new AppOpsService(file, handler, getContext()); } public Handler getUiHandler(ActivityManagerService service) { diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a0589c53c366..06561f57f495 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -19,11 +19,15 @@ package com.android.server.appop; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; +import static android.app.AppOpsManager.CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE; import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID; import static android.app.AppOpsManager.FILTER_BY_OP_NAMES; import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME; import static android.app.AppOpsManager.FILTER_BY_UID; import static android.app.AppOpsManager.HistoricalOpsRequestFilter; +import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME; +import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME; +import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.NoteOpEvent; import static android.app.AppOpsManager.OP_CAMERA; @@ -41,6 +45,7 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE; import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; import static android.app.AppOpsManager.UID_STATE_PERSISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; +import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager._NUM_OP; import static android.app.AppOpsManager.extractFlagsFromKey; import static android.app.AppOpsManager.extractUidStateFromKey; @@ -53,6 +58,10 @@ import static android.content.Intent.EXTRA_REPLACING; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.os.Process.STATSD_UID; +import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; + +import static java.lang.Long.max; + import android.Manifest; import android.annotation.IntRange; import android.annotation.NonNull; @@ -70,6 +79,7 @@ import android.app.AppOpsManager.OpFlags; import android.app.AppOpsManagerInternal; import android.app.AppOpsManagerInternal.CheckOpsDelegate; import android.app.AsyncNotedAppOp; +import android.compat.Compatibility; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -129,7 +139,6 @@ import com.android.internal.app.IAppOpsNotedCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.os.Zygote; import com.android.internal.util.ArrayUtils; -import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; @@ -216,7 +225,7 @@ public class AppOpsService extends IAppOpsService.Stub { //TODO: remove this when development is done. private static final int TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31; - Context mContext; + final Context mContext; final AtomicFile mFile; final Handler mHandler; @@ -291,8 +300,11 @@ public class AppOpsService extends IAppOpsService.Stub { @GuardedBy("this") private CheckOpsDelegate mCheckOpsDelegate; - @GuardedBy("this") - private SparseArray<List<Integer>> mSwitchOpToOps; + /** + * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never + * changed + */ + private final SparseArray<int[]> mSwitchedOps = new SparseArray<>(); private ActivityManagerInternal mActivityManagerInternal; @@ -343,30 +355,25 @@ public class AppOpsService extends IAppOpsService.Stub { */ @VisibleForTesting final class Constants extends ContentObserver { - // Key names stored in the settings value. - private static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time"; - private static final String KEY_FG_SERVICE_STATE_SETTLE_TIME - = "fg_service_state_settle_time"; - private static final String KEY_BG_STATE_SETTLE_TIME = "bg_state_settle_time"; /** * How long we want for a drop in uid state from top to settle before applying it. * @see Settings.Global#APP_OPS_CONSTANTS - * @see #KEY_TOP_STATE_SETTLE_TIME + * @see AppOpsManager#KEY_TOP_STATE_SETTLE_TIME */ public long TOP_STATE_SETTLE_TIME; /** * How long we want for a drop in uid state from foreground to settle before applying it. * @see Settings.Global#APP_OPS_CONSTANTS - * @see #KEY_FG_SERVICE_STATE_SETTLE_TIME + * @see AppOpsManager#KEY_FG_SERVICE_STATE_SETTLE_TIME */ public long FG_SERVICE_STATE_SETTLE_TIME; /** * How long we want for a drop in uid state from background to settle before applying it. * @see Settings.Global#APP_OPS_CONSTANTS - * @see #KEY_BG_STATE_SETTLE_TIME + * @see AppOpsManager#KEY_BG_STATE_SETTLE_TIME */ public long BG_STATE_SETTLE_TIME; @@ -1191,17 +1198,22 @@ public class AppOpsService extends IAppOpsService.Stub { final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager(); final class ModeCallback implements DeathRecipient { + /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */ + public static final int ALL_OPS = -2; + final IAppOpsCallback mCallback; final int mWatchingUid; final int mFlags; + final int mWatchedOpCode; final int mCallingUid; final int mCallingPid; - ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid, - int callingPid) { + ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOp, + int callingUid, int callingPid) { mCallback = callback; mWatchingUid = watchingUid; mFlags = flags; + mWatchedOpCode = watchedOp; mCallingUid = callingUid; mCallingPid = callingPid; try { @@ -1224,6 +1236,10 @@ public class AppOpsService extends IAppOpsService.Stub { UserHandle.formatUid(sb, mWatchingUid); sb.append(" flags=0x"); sb.append(Integer.toHexString(mFlags)); + if (mWatchedOpCode != OP_NONE) { + sb.append(" op="); + sb.append(opToName(mWatchedOpCode)); + } sb.append(" from uid="); UserHandle.formatUid(sb, mCallingUid); sb.append(" pid="); @@ -1337,16 +1353,23 @@ public class AppOpsService extends IAppOpsService.Stub { featureOp.onClientDeath(clientId); } - public AppOpsService(File storagePath, Handler handler) { + public AppOpsService(File storagePath, Handler handler, Context context) { + mContext = context; + LockGuard.installLock(this, LockGuard.INDEX_APP_OPS); mFile = new AtomicFile(storagePath, "appops"); mHandler = handler; mConstants = new Constants(mHandler); readState(); + + for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) { + int switchCode = AppOpsManager.opToSwitch(switchedCode); + mSwitchedOps.put(switchCode, + ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode)); + } } - public void publish(Context context) { - mContext = context; + public void publish() { ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder()); LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal); } @@ -1616,6 +1639,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, @ActivityManager.ProcessCapability int capability) { synchronized (this) { @@ -1647,7 +1683,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.pkgOps != null) { @@ -2014,6 +2055,19 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.evalForegroundOps(mOpModeWatchers); } + notifyOpChangedForAllPkgsInUid(code, uid, false, callbackToIgnore); + 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, + @Nullable IAppOpsCallback callbackToIgnore) { String[] uidPackageNames = getPackagesForUid(uid); ArrayMap<ModeCallback, ArraySet<String>> callbackSpecs = null; @@ -2023,6 +2077,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<String> changedPackages = new ArraySet<>(); Collections.addAll(changedPackages, uidPackageNames); if (callbackSpecs == null) { @@ -2041,6 +2099,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<String> changedPackages = callbackSpecs.get(callback); if (changedPackages == null) { changedPackages = new ArraySet<>(); @@ -2057,7 +2119,6 @@ public class AppOpsService extends IAppOpsService.Stub { } if (callbackSpecs == null) { - notifyOpChangedSync(code, uid, null, mode); return; } @@ -2079,23 +2140,24 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - - notifyOpChangedSync(code, uid, null, mode); } private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) { PackageManager packageManager = mContext.getPackageManager(); + if (packageManager == null) { + // This can only happen during early boot. At this time the permission state and appop + // state are in sync + return; + } + String[] packageNames = packageManager.getPackagesForUid(uid); if (ArrayUtils.isEmpty(packageNames)) { return; } String packageName = packageNames[0]; - List<Integer> ops = getSwitchOpToOps().get(switchCode); - int opsSize = CollectionUtils.size(ops); - for (int i = 0; i < opsSize; i++) { - int code = ops.get(i); - + int[] ops = mSwitchedOps.get(switchCode); + for (int code : ops) { String permissionName = AppOpsManager.opToPermission(code); if (permissionName == null) { continue; @@ -2173,25 +2235,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } - @NonNull - private SparseArray<List<Integer>> getSwitchOpToOps() { - synchronized (this) { - if (mSwitchOpToOps == null) { - mSwitchOpToOps = new SparseArray<>(); - for (int op = 0; op < _NUM_OP; op++) { - int switchOp = AppOpsManager.opToSwitch(op); - List<Integer> ops = mSwitchOpToOps.get(switchOp); - if (ops == null) { - ops = new ArrayList<>(); - mSwitchOpToOps.put(switchOp, ops); - } - ops.add(op); - } - } - return mSwitchOpToOps; - } - } - private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode) { final StorageManagerInternal storageManagerInternal = LocalServices.getService(StorageManagerInternal.class); @@ -2292,16 +2335,29 @@ public class AppOpsService extends IAppOpsService.Stub { if (uid != UID_ANY && callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) { return; } - // 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 { - callback.mCallback.opChanged(code, uid, packageName); - } catch (RemoteException e) { - /* ignore */ - } finally { - Binder.restoreCallingIdentity(identity); + + // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE + int[] switchedCodes; + if (callback.mWatchedOpCode == ALL_OPS) { + switchedCodes = mSwitchedOps.get(code); + } else if (callback.mWatchedOpCode == OP_NONE) { + switchedCodes = new int[]{code}; + } else { + switchedCodes = new int[]{callback.mWatchedOpCode}; + } + + for (int switchedCode : switchedCodes) { + // There are features watching for mode changes such as window manager + // and location manager which are in our process. The callbacks in these + // features may require permissions our remote caller does not have. + final long identity = Binder.clearCallingIdentity(); + try { + callback.mCallback.opChanged(switchedCode, uid, packageName); + } catch (RemoteException e) { + /* ignore */ + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -2496,17 +2552,32 @@ public class AppOpsService extends IAppOpsService.Stub { return; } synchronized (this) { - op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op; + int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op; + + // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE + int notifiedOps; + if (Compatibility.isChangeEnabled( + CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE)) { + if (op == OP_NONE) { + notifiedOps = ALL_OPS; + } else { + notifiedOps = op; + } + } else { + notifiedOps = switchOp; + } + ModeCallback cb = mModeWatchers.get(callback.asBinder()); if (cb == null) { - cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid); + cb = new ModeCallback(callback, watchedUid, flags, notifiedOps, callingUid, + callingPid); mModeWatchers.put(callback.asBinder(), cb); } - if (op != AppOpsManager.OP_NONE) { - ArraySet<ModeCallback> cbs = mOpModeWatchers.get(op); + if (switchOp != AppOpsManager.OP_NONE) { + ArraySet<ModeCallback> cbs = mOpModeWatchers.get(switchOp); if (cbs == null) { cbs = new ArraySet<>(); - mOpModeWatchers.put(op, cbs); + mOpModeWatchers.put(switchOp, cbs); } cbs.add(cb); } @@ -3325,6 +3396,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); @@ -3336,7 +3419,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } } - return uidState; } private void commitUidPendingStateLocked(UidState uidState) { @@ -3356,24 +3438,28 @@ public class AppOpsService extends IAppOpsService.Stub { && uidState.appWidgetVisible == uidState.pendingAppWidgetVisible) { continue; } - final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); - if (callbacks != null) { - for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { - final ModeCallback callback = callbacks.valueAt(cbi); - if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 - || !callback.isWatchingUid(uidState.uid)) { - 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, null)); + } else { + final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code); + if (callbacks != null) { + for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) { + final ModeCallback callback = callbacks.valueAt(cbi); + if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0 + || !callback.isWatchingUid(uidState.uid)) { + 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, @@ -3798,11 +3884,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (tagName.equals("op")) { final int code = Integer.parseInt(parser.getAttributeValue(null, "n")); final int mode = Integer.parseInt(parser.getAttributeValue(null, "m")); - UidState uidState = getUidStateLocked(uid, true); - if (uidState.opModes == null) { - uidState.opModes = new SparseIntArray(); - } - uidState.opModes.put(code, mode); + setUidMode(code, uid, mode); } else { Slog.w(TAG, "Unknown element under <uid-ops>: " + parser.getName()); diff --git a/services/tests/servicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml b/services/tests/mockingservicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml index a37d84f7a08c..a37d84f7a08c 100644 --- a/services/tests/servicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml +++ b/services/tests/mockingservicestests/assets/AppOpsUpgradeTest/appops-unversioned.xml 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 155de3bc0266..2d5fa237f6b7 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -101,9 +101,8 @@ public class AppOpsServiceTest { private StaticMockitoSession mMockingSession; private void setupAppOpsService() { - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); + mAppOpsService = new AppOpsService(mAppOpsFile, mHandler, spy(sContext)); mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver()); - mAppOpsService.mContext = spy(sContext); // Always approve all permission checks doNothing().when(mAppOpsService.mContext).enforcePermission(anyString(), anyInt(), diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java index 66d2baba2909..e48b67167cdf 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,17 @@ package com.android.server.appop; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.os.Handler; import android.os.HandlerThread; @@ -133,10 +141,24 @@ public class AppOpsUpgradeTest { AppOpsDataParser parser = new AppOpsDataParser(mAppOpsFile); assertTrue(parser.parse()); assertEquals(AppOpsDataParser.NO_VERSION, parser.mVersion); - AppOpsService testService = new AppOpsService(mAppOpsFile, mHandler); // trigger upgrade + + // Use mock context and package manager to fake permision package manager calls. + Context testContext = spy(mContext); + + // Pretent everybody has all permissions + doNothing().when(testContext).enforcePermission(anyString(), anyInt(), anyInt(), + nullable(String.class)); + + PackageManager testPM = mock(PackageManager.class); + when(testContext.getPackageManager()).thenReturn(testPM); + + // Stub out package calls to disable AppOpsService#updatePermissionRevokedCompat + when(testPM.getPackagesForUid(anyInt())).thenReturn(null); + + AppOpsService testService = spy( + new AppOpsService(mAppOpsFile, mHandler, testContext)); // trigger upgrade assertSameModes(testService.mUidStates, AppOpsManager.OP_RUN_IN_BACKGROUND, AppOpsManager.OP_RUN_ANY_IN_BACKGROUND); - testService.mContext = mContext; mHandler.removeCallbacks(testService.mWriteRunner); testService.writeState(); assertTrue(parser.parse()); |