Loading core/java/android/app/AppOpsManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -482,7 +482,8 @@ public class AppOpsManager { UID_STATE_FOREGROUND_SERVICE, UID_STATE_FOREGROUND, UID_STATE_BACKGROUND, UID_STATE_CACHED UID_STATE_CACHED, UID_STATE_NONEXISTENT }) public @interface UidState {} Loading Loading @@ -565,6 +566,12 @@ public class AppOpsManager { */ public static final int MIN_PRIORITY_UID_STATE = UID_STATE_CACHED; /** * Special uid state: The UID is not running * @hide */ public static final int UID_STATE_NONEXISTENT = Integer.MAX_VALUE; /** * Resolves the first unrestricted state given an app op. * @param op The op to resolve. Loading Loading @@ -596,6 +603,7 @@ public class AppOpsManager { UID_STATE_FOREGROUND, UID_STATE_BACKGROUND, UID_STATE_CACHED // UID_STATE_NONEXISTENT isn't a real UID state, so it is excluded }; /** @hide */ Loading @@ -615,6 +623,8 @@ public class AppOpsManager { return "bg"; case UID_STATE_CACHED: return "cch"; case UID_STATE_NONEXISTENT: return "gone"; default: return "unknown"; } Loading core/java/android/permission/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,16 @@ flag { bug: "325356776" } flag { name: "finish_running_ops_for_killed_packages" namespace: "permissions" description: "Finish all appops for a dead app process" bug: "234630570" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "runtime_permission_appops_mapping_enabled" is_fixed_read_only: true Loading services/core/java/com/android/server/appop/AppOpsService.java +89 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,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.UID_STATE_NONEXISTENT; import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager._NUM_OP; import static android.app.AppOpsManager.extractFlagsFromKey; Loading @@ -70,7 +71,6 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.EXTRA_REPLACING; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP; import static android.permission.flags.Flags.runtimePermissionAppopsMappingEnabled; import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; Loading Loading @@ -130,6 +130,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.storage.StorageManagerInternal; import android.permission.PermissionManager; import android.permission.flags.Flags; import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; Loading @@ -140,6 +141,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; Loading @@ -153,7 +155,6 @@ import com.android.internal.app.IAppOpsNotedCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IAppOpsStartedCallback; import com.android.internal.app.MessageSamplingConfig; import com.android.internal.camera.flags.Flags; import com.android.internal.compat.IPlatformCompat; import com.android.internal.os.Clock; import com.android.internal.pm.pkg.component.ParsedAttribution; Loading Loading @@ -1421,6 +1422,9 @@ public class AppOpsService extends IAppOpsService.Stub { // The callback method from AppOpsUidStateTracker private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) { synchronized (this) { if (state == UID_STATE_NONEXISTENT) { onUidProcessDeathLocked(uid); } UidState uidState = getUidStateLocked(uid, false); boolean hasForegroundWatchers = false; Loading Loading @@ -1508,6 +1512,11 @@ public class AppOpsService extends IAppOpsService.Stub { } } if (state == UID_STATE_NONEXISTENT) { // For UID_STATE_NONEXISTENT, we don't call onUidStateChanged for AttributedOps return; } if (uidState != null) { int numPkgs = uidState.pkgOps.size(); for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { Loading @@ -1532,6 +1541,81 @@ public class AppOpsService extends IAppOpsService.Stub { } } @GuardedBy("this") private void onUidProcessDeathLocked(int uid) { if (!mUidStates.contains(uid) || !Flags.finishRunningOpsForKilledPackages()) { return; } final SparseLongArray chainsToFinish = new SparseLongArray(); doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> { attributedOp.doForAllInProgressStartOpEvents((event) -> { int chainId = event.getAttributionChainId(); if (chainId != ATTRIBUTION_CHAIN_ID_NONE) { long currentEarliestStartTime = chainsToFinish.get(chainId, Long.MAX_VALUE); if (event.getStartTime() < currentEarliestStartTime) { // Store the earliest chain link we're finishing, so that we can go back // and finish any links in the chain that started after this one chainsToFinish.put(chainId, event.getStartTime()); } } attributedOp.finished(event.getClientId()); }); }); finishChainsLocked(chainsToFinish); } @GuardedBy("this") private void finishChainsLocked(SparseLongArray chainsToFinish) { doForAllAttributedOpsLocked((attributedOp) -> { attributedOp.doForAllInProgressStartOpEvents((event) -> { int chainId = event.getAttributionChainId(); // If this event is part of a chain, and this event started after the event in the // chain we already finished, then finish this event, too long earliestEventStart = chainsToFinish.get(chainId, Long.MAX_VALUE); if (chainId != ATTRIBUTION_CHAIN_ID_NONE && event.getStartTime() >= earliestEventStart) { attributedOp.finished(event.getClientId()); } }); }); } @GuardedBy("this") private void doForAllAttributedOpsLocked(Consumer<AttributedOp> action) { int numUids = mUidStates.size(); for (int uidNum = 0; uidNum < numUids; uidNum++) { int uid = mUidStates.keyAt(uidNum); doForAllAttributedOpsInUidLocked(uid, action); } } @GuardedBy("this") private void doForAllAttributedOpsInUidLocked(int uid, Consumer<AttributedOp> action) { UidState uidState = mUidStates.get(uid); if (uidState == null) { return; } int numPkgs = uidState.pkgOps.size(); for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { Ops ops = uidState.pkgOps.valueAt(pkgNum); int numOps = ops.size(); for (int opNum = 0; opNum < numOps; opNum++) { Op op = ops.valueAt(opNum); int numDevices = op.mDeviceAttributedOps.size(); for (int deviceNum = 0; deviceNum < numDevices; deviceNum++) { ArrayMap<String, AttributedOp> attrOps = op.mDeviceAttributedOps.valueAt(deviceNum); int numAttributions = attrOps.size(); for (int attrNum = 0; attrNum < numAttributions; attrNum++) { action.accept(attrOps.valueAt(attrNum)); } } } } } /** * Notify the proc state or capability has changed for a certain UID. */ Loading Loading @@ -2702,7 +2786,7 @@ public class AppOpsService extends IAppOpsService.Stub { * have information on them. */ private static boolean isOpAllowedForUid(int uid) { return runtimePermissionAppopsMappingEnabled() return Flags.runtimePermissionAppopsMappingEnabled() && (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID); } Loading Loading @@ -4775,8 +4859,8 @@ public class AppOpsService extends IAppOpsService.Stub { if ((code == OP_CAMERA) && isAutomotive()) { final long identity = Binder.clearCallingIdentity(); try { if ((Flags.cameraPrivacyAllowlist()) && (mSensorPrivacyManager.isCameraPrivacyEnabled(packageName))) { if (com.android.internal.camera.flags.Flags.cameraPrivacyAllowlist() && mSensorPrivacyManager.isCameraPrivacyEnabled(packageName)) { return true; } } finally { Loading services/core/java/com/android/server/appop/AppOpsUidStateTracker.java +1 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ interface AppOpsUidStateTracker { return UID_STATE_BACKGROUND; } // UID_STATE_NONEXISTENT is deliberately excluded here return UID_STATE_CACHED; } Loading services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java +17 −4 Original line number Diff line number Diff line Loading @@ -34,7 +34,9 @@ import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS; 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_NONEXISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; import static android.permission.flags.Flags.finishRunningOpsForKilledPackages; import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; Loading Loading @@ -343,14 +345,15 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE); boolean appWidgetVisible = mAppWidgetVisible.get(uid, false); if (uidState != pendingUidState || capability != pendingCapability || appWidgetVisible != pendingAppWidgetVisible) { boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED || capability != pendingCapability || appWidgetVisible != pendingAppWidgetVisible; if (uidState != pendingUidState || capability != pendingCapability || appWidgetVisible != pendingAppWidgetVisible) { if (foregroundChange) { // To save on memory usage, log only interesting changes. mEventLog.logCommitUidState(uid, pendingUidState, pendingCapability, Loading @@ -372,6 +375,16 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { mCapability.delete(uid); mAppWidgetVisible.delete(uid); mPendingGone.delete(uid); if (finishRunningOpsForKilledPackages()) { for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) { UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i); Executor executor = mUidStateChangedCallbacks.valueAt(i); executor.execute(PooledLambda.obtainRunnable( UidStateChangedCallback::onUidStateChanged, cb, uid, UID_STATE_NONEXISTENT, foregroundChange)); } } } else { mUidStates.put(uid, pendingUidState); mCapability.put(uid, pendingCapability); Loading Loading
core/java/android/app/AppOpsManager.java +11 −1 Original line number Diff line number Diff line Loading @@ -482,7 +482,8 @@ public class AppOpsManager { UID_STATE_FOREGROUND_SERVICE, UID_STATE_FOREGROUND, UID_STATE_BACKGROUND, UID_STATE_CACHED UID_STATE_CACHED, UID_STATE_NONEXISTENT }) public @interface UidState {} Loading Loading @@ -565,6 +566,12 @@ public class AppOpsManager { */ public static final int MIN_PRIORITY_UID_STATE = UID_STATE_CACHED; /** * Special uid state: The UID is not running * @hide */ public static final int UID_STATE_NONEXISTENT = Integer.MAX_VALUE; /** * Resolves the first unrestricted state given an app op. * @param op The op to resolve. Loading Loading @@ -596,6 +603,7 @@ public class AppOpsManager { UID_STATE_FOREGROUND, UID_STATE_BACKGROUND, UID_STATE_CACHED // UID_STATE_NONEXISTENT isn't a real UID state, so it is excluded }; /** @hide */ Loading @@ -615,6 +623,8 @@ public class AppOpsManager { return "bg"; case UID_STATE_CACHED: return "cch"; case UID_STATE_NONEXISTENT: return "gone"; default: return "unknown"; } Loading
core/java/android/permission/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,16 @@ flag { bug: "325356776" } flag { name: "finish_running_ops_for_killed_packages" namespace: "permissions" description: "Finish all appops for a dead app process" bug: "234630570" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "runtime_permission_appops_mapping_enabled" is_fixed_read_only: true Loading
services/core/java/com/android/server/appop/AppOpsService.java +89 −5 Original line number Diff line number Diff line Loading @@ -55,6 +55,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.UID_STATE_NONEXISTENT; import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager._NUM_OP; import static android.app.AppOpsManager.extractFlagsFromKey; Loading @@ -70,7 +71,6 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.EXTRA_REPLACING; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP; import static android.permission.flags.Flags.runtimePermissionAppopsMappingEnabled; import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; Loading Loading @@ -130,6 +130,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.storage.StorageManagerInternal; import android.permission.PermissionManager; import android.permission.flags.Flags; import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; Loading @@ -140,6 +141,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; Loading @@ -153,7 +155,6 @@ import com.android.internal.app.IAppOpsNotedCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IAppOpsStartedCallback; import com.android.internal.app.MessageSamplingConfig; import com.android.internal.camera.flags.Flags; import com.android.internal.compat.IPlatformCompat; import com.android.internal.os.Clock; import com.android.internal.pm.pkg.component.ParsedAttribution; Loading Loading @@ -1421,6 +1422,9 @@ public class AppOpsService extends IAppOpsService.Stub { // The callback method from AppOpsUidStateTracker private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) { synchronized (this) { if (state == UID_STATE_NONEXISTENT) { onUidProcessDeathLocked(uid); } UidState uidState = getUidStateLocked(uid, false); boolean hasForegroundWatchers = false; Loading Loading @@ -1508,6 +1512,11 @@ public class AppOpsService extends IAppOpsService.Stub { } } if (state == UID_STATE_NONEXISTENT) { // For UID_STATE_NONEXISTENT, we don't call onUidStateChanged for AttributedOps return; } if (uidState != null) { int numPkgs = uidState.pkgOps.size(); for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { Loading @@ -1532,6 +1541,81 @@ public class AppOpsService extends IAppOpsService.Stub { } } @GuardedBy("this") private void onUidProcessDeathLocked(int uid) { if (!mUidStates.contains(uid) || !Flags.finishRunningOpsForKilledPackages()) { return; } final SparseLongArray chainsToFinish = new SparseLongArray(); doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> { attributedOp.doForAllInProgressStartOpEvents((event) -> { int chainId = event.getAttributionChainId(); if (chainId != ATTRIBUTION_CHAIN_ID_NONE) { long currentEarliestStartTime = chainsToFinish.get(chainId, Long.MAX_VALUE); if (event.getStartTime() < currentEarliestStartTime) { // Store the earliest chain link we're finishing, so that we can go back // and finish any links in the chain that started after this one chainsToFinish.put(chainId, event.getStartTime()); } } attributedOp.finished(event.getClientId()); }); }); finishChainsLocked(chainsToFinish); } @GuardedBy("this") private void finishChainsLocked(SparseLongArray chainsToFinish) { doForAllAttributedOpsLocked((attributedOp) -> { attributedOp.doForAllInProgressStartOpEvents((event) -> { int chainId = event.getAttributionChainId(); // If this event is part of a chain, and this event started after the event in the // chain we already finished, then finish this event, too long earliestEventStart = chainsToFinish.get(chainId, Long.MAX_VALUE); if (chainId != ATTRIBUTION_CHAIN_ID_NONE && event.getStartTime() >= earliestEventStart) { attributedOp.finished(event.getClientId()); } }); }); } @GuardedBy("this") private void doForAllAttributedOpsLocked(Consumer<AttributedOp> action) { int numUids = mUidStates.size(); for (int uidNum = 0; uidNum < numUids; uidNum++) { int uid = mUidStates.keyAt(uidNum); doForAllAttributedOpsInUidLocked(uid, action); } } @GuardedBy("this") private void doForAllAttributedOpsInUidLocked(int uid, Consumer<AttributedOp> action) { UidState uidState = mUidStates.get(uid); if (uidState == null) { return; } int numPkgs = uidState.pkgOps.size(); for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { Ops ops = uidState.pkgOps.valueAt(pkgNum); int numOps = ops.size(); for (int opNum = 0; opNum < numOps; opNum++) { Op op = ops.valueAt(opNum); int numDevices = op.mDeviceAttributedOps.size(); for (int deviceNum = 0; deviceNum < numDevices; deviceNum++) { ArrayMap<String, AttributedOp> attrOps = op.mDeviceAttributedOps.valueAt(deviceNum); int numAttributions = attrOps.size(); for (int attrNum = 0; attrNum < numAttributions; attrNum++) { action.accept(attrOps.valueAt(attrNum)); } } } } } /** * Notify the proc state or capability has changed for a certain UID. */ Loading Loading @@ -2702,7 +2786,7 @@ public class AppOpsService extends IAppOpsService.Stub { * have information on them. */ private static boolean isOpAllowedForUid(int uid) { return runtimePermissionAppopsMappingEnabled() return Flags.runtimePermissionAppopsMappingEnabled() && (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID); } Loading Loading @@ -4775,8 +4859,8 @@ public class AppOpsService extends IAppOpsService.Stub { if ((code == OP_CAMERA) && isAutomotive()) { final long identity = Binder.clearCallingIdentity(); try { if ((Flags.cameraPrivacyAllowlist()) && (mSensorPrivacyManager.isCameraPrivacyEnabled(packageName))) { if (com.android.internal.camera.flags.Flags.cameraPrivacyAllowlist() && mSensorPrivacyManager.isCameraPrivacyEnabled(packageName)) { return true; } } finally { Loading
services/core/java/com/android/server/appop/AppOpsUidStateTracker.java +1 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ interface AppOpsUidStateTracker { return UID_STATE_BACKGROUND; } // UID_STATE_NONEXISTENT is deliberately excluded here return UID_STATE_CACHED; } Loading
services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java +17 −4 Original line number Diff line number Diff line Loading @@ -34,7 +34,9 @@ import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS; 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_NONEXISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; import static android.permission.flags.Flags.finishRunningOpsForKilledPackages; import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; Loading Loading @@ -343,14 +345,15 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE); boolean appWidgetVisible = mAppWidgetVisible.get(uid, false); if (uidState != pendingUidState || capability != pendingCapability || appWidgetVisible != pendingAppWidgetVisible) { boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED || capability != pendingCapability || appWidgetVisible != pendingAppWidgetVisible; if (uidState != pendingUidState || capability != pendingCapability || appWidgetVisible != pendingAppWidgetVisible) { if (foregroundChange) { // To save on memory usage, log only interesting changes. mEventLog.logCommitUidState(uid, pendingUidState, pendingCapability, Loading @@ -372,6 +375,16 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { mCapability.delete(uid); mAppWidgetVisible.delete(uid); mPendingGone.delete(uid); if (finishRunningOpsForKilledPackages()) { for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) { UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i); Executor executor = mUidStateChangedCallbacks.valueAt(i); executor.execute(PooledLambda.obtainRunnable( UidStateChangedCallback::onUidStateChanged, cb, uid, UID_STATE_NONEXISTENT, foregroundChange)); } } } else { mUidStates.put(uid, pendingUidState); mCapability.put(uid, pendingCapability); Loading