Loading core/java/android/permission/flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -255,3 +255,14 @@ flag { description: "This fixed read-only flag is used to enable replacing permission BODY_SENSORS (and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE (and READ_HEALTH_DATA_IN_BACKGROUND)" bug: "364638912" } flag { name: "delay_uid_state_changes_from_capability_updates" is_fixed_read_only: true namespace: "permissions" description: "If proc state is decreasing over the restriction threshold and capability is changed, delay if no new capabilities are added" bug: "308573169" metadata { purpose: PURPOSE_BUGFIX } } services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java +12 −5 Original line number Diff line number Diff line Loading @@ -36,6 +36,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_NONEXISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates; import static android.permission.flags.Flags.finishRunningOpsForKilledPackages; import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; Loading Loading @@ -236,20 +237,26 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { mPendingUidStates.put(uid, uidState); mPendingCapability.put(uid, capability); boolean hasLostCapability = (prevCapability & ~capability) != 0; if (procState == PROCESS_STATE_NONEXISTENT) { mPendingGone.put(uid, true); commitUidPendingState(uid); } else if (uidState < prevUidState || (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED && prevUidState > UID_STATE_MAX_LAST_NON_RESTRICTED)) { } else if (uidState < prevUidState) { // We are moving to a more important state, or the new state may be in the // foreground and the old state is in the background, then always do it // immediately. commitUidPendingState(uid); } else if (uidState == prevUidState && capability != prevCapability) { } else if (delayUidStateChangesFromCapabilityUpdates() && uidState == prevUidState && !hasLostCapability) { // No change on process state, but process capability hasn't decreased. commitUidPendingState(uid); } else if (!delayUidStateChangesFromCapabilityUpdates() && uidState == prevUidState && capability != prevCapability) { // No change on process state, but process capability has changed. commitUidPendingState(uid); } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED) { } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED && (!delayUidStateChangesFromCapabilityUpdates() || !hasLostCapability)) { // We are moving to a less important state, but it doesn't cross the restriction // threshold. commitUidPendingState(uid); Loading services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java +72 −0 Original line number Diff line number Diff line Loading @@ -31,12 +31,14 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND; 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_TOP; import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates; import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; Loading Loading @@ -325,6 +327,10 @@ public class AppOpsUidStateTrackerTest { .backgroundState() .update(); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .microphoneCapability() Loading @@ -342,10 +348,23 @@ public class AppOpsUidStateTrackerTest { .microphoneCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .update(); if (delayUidStateChangesFromCapabilityUpdates()) { mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); mClock.advanceTime(1); } assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); Loading @@ -357,6 +376,8 @@ public class AppOpsUidStateTrackerTest { .backgroundState() .update(); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .cameraCapability() Loading @@ -372,10 +393,18 @@ public class AppOpsUidStateTrackerTest { .cameraCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .update(); if (delayUidStateChangesFromCapabilityUpdates()) { mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); mClock.advanceTime(1); } assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); } Loading @@ -385,6 +414,9 @@ public class AppOpsUidStateTrackerTest { .backgroundState() .update(); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .locationCapability() Loading @@ -401,14 +433,54 @@ public class AppOpsUidStateTrackerTest { .locationCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .update(); if (delayUidStateChangesFromCapabilityUpdates()) { mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); mClock.advanceTime(1); } assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); } @Test public void testProcStateChangesAndStaysUnrestrictedAndCapabilityRemoved() { assumeTrue(delayUidStateChangesFromCapabilityUpdates()); procStateBuilder(UID) .topState() .microphoneCapability() .cameraCapability() .locationCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); procStateBuilder(UID) .foregroundState() .update(); mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); mClock.advanceTime(1); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); } @Test public void testVisibleAppWidget() { procStateBuilder(UID) Loading Loading
core/java/android/permission/flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -255,3 +255,14 @@ flag { description: "This fixed read-only flag is used to enable replacing permission BODY_SENSORS (and BODY_SENSORS_BACKGROUND) with granular health permission READ_HEART_RATE (and READ_HEALTH_DATA_IN_BACKGROUND)" bug: "364638912" } flag { name: "delay_uid_state_changes_from_capability_updates" is_fixed_read_only: true namespace: "permissions" description: "If proc state is decreasing over the restriction threshold and capability is changed, delay if no new capabilities are added" bug: "308573169" metadata { purpose: PURPOSE_BUGFIX } }
services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java +12 −5 Original line number Diff line number Diff line Loading @@ -36,6 +36,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_NONEXISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates; import static android.permission.flags.Flags.finishRunningOpsForKilledPackages; import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; Loading Loading @@ -236,20 +237,26 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { mPendingUidStates.put(uid, uidState); mPendingCapability.put(uid, capability); boolean hasLostCapability = (prevCapability & ~capability) != 0; if (procState == PROCESS_STATE_NONEXISTENT) { mPendingGone.put(uid, true); commitUidPendingState(uid); } else if (uidState < prevUidState || (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED && prevUidState > UID_STATE_MAX_LAST_NON_RESTRICTED)) { } else if (uidState < prevUidState) { // We are moving to a more important state, or the new state may be in the // foreground and the old state is in the background, then always do it // immediately. commitUidPendingState(uid); } else if (uidState == prevUidState && capability != prevCapability) { } else if (delayUidStateChangesFromCapabilityUpdates() && uidState == prevUidState && !hasLostCapability) { // No change on process state, but process capability hasn't decreased. commitUidPendingState(uid); } else if (!delayUidStateChangesFromCapabilityUpdates() && uidState == prevUidState && capability != prevCapability) { // No change on process state, but process capability has changed. commitUidPendingState(uid); } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED) { } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED && (!delayUidStateChangesFromCapabilityUpdates() || !hasLostCapability)) { // We are moving to a less important state, but it doesn't cross the restriction // threshold. commitUidPendingState(uid); Loading
services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java +72 −0 Original line number Diff line number Diff line Loading @@ -31,12 +31,14 @@ import static android.app.AppOpsManager.UID_STATE_FOREGROUND; 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_TOP; import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates; import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; Loading Loading @@ -325,6 +327,10 @@ public class AppOpsUidStateTrackerTest { .backgroundState() .update(); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .microphoneCapability() Loading @@ -342,10 +348,23 @@ public class AppOpsUidStateTrackerTest { .microphoneCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .update(); if (delayUidStateChangesFromCapabilityUpdates()) { mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); mClock.advanceTime(1); } assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO, MODE_FOREGROUND)); Loading @@ -357,6 +376,8 @@ public class AppOpsUidStateTrackerTest { .backgroundState() .update(); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .cameraCapability() Loading @@ -372,10 +393,18 @@ public class AppOpsUidStateTrackerTest { .cameraCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .update(); if (delayUidStateChangesFromCapabilityUpdates()) { mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); mClock.advanceTime(1); } assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); } Loading @@ -385,6 +414,9 @@ public class AppOpsUidStateTrackerTest { .backgroundState() .update(); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .locationCapability() Loading @@ -401,14 +433,54 @@ public class AppOpsUidStateTrackerTest { .locationCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); procStateBuilder(UID) .backgroundState() .update(); if (delayUidStateChangesFromCapabilityUpdates()) { mClock.advanceTime(mConstants.BG_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); mClock.advanceTime(1); } assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_FINE_LOCATION, MODE_FOREGROUND)); } @Test public void testProcStateChangesAndStaysUnrestrictedAndCapabilityRemoved() { assumeTrue(delayUidStateChangesFromCapabilityUpdates()); procStateBuilder(UID) .topState() .microphoneCapability() .cameraCapability() .locationCapability() .update(); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); procStateBuilder(UID) .foregroundState() .update(); mClock.advanceTime(mConstants.TOP_STATE_SETTLE_TIME - 1); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); assertEquals(MODE_ALLOWED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); mClock.advanceTime(1); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_RECORD_AUDIO, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_CAMERA, MODE_FOREGROUND)); assertEquals(MODE_IGNORED, mIntf.evalMode(UID, OP_COARSE_LOCATION, MODE_FOREGROUND)); } @Test public void testVisibleAppWidget() { procStateBuilder(UID) Loading