Loading core/java/android/app/AppOpsManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -741,6 +741,13 @@ public class AppOpsManager { @TestApi public static final int ATTRIBUTION_FLAG_RECEIVER = 0x4; /** * Attribution chain flag: Specifies that all attribution sources in the chain were trusted. * Must only be set by system server. * @hide */ public static final int ATTRIBUTION_FLAG_TRUSTED = 0x8; /** * No attribution flags. * @hide Loading @@ -760,7 +767,8 @@ public class AppOpsManager { @IntDef(flag = true, prefix = { "FLAG_" }, value = { ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_FLAG_INTERMEDIARY, ATTRIBUTION_FLAG_RECEIVER ATTRIBUTION_FLAG_RECEIVER, ATTRIBUTION_FLAG_TRUSTED }) public @interface AttributionFlags {} Loading core/java/android/permission/PermissionUsageHelper.java +6 −1 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package android.permission; import static android.Manifest.permission_group.CAMERA; import static android.Manifest.permission_group.LOCATION; import static android.Manifest.permission_group.MICROPHONE; import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAGS_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED; import static android.app.AppOpsManager.AttributionFlags; import static android.app.AppOpsManager.OPSTR_CAMERA; import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION; Loading Loading @@ -180,7 +182,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { if ((attributionFlags & ATTRIBUTION_FLAGS_NONE) != 0) { if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE || attributionFlags == ATTRIBUTION_FLAGS_NONE || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { // If this is not a chain, or it is untrusted, return return; } Loading packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +22 −4 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ import javax.inject.Inject; */ @SysUISingleton public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController, AppOpsManager.OnOpActiveChangedInternalListener, AppOpsManager.OnOpActiveChangedListener, AppOpsManager.OnOpNotedListener, IndividualSensorPrivacyController.Callback, Dumpable { Loading Loading @@ -359,11 +359,29 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon mBGHandler.post(() -> notifySuscribersWorker(code, uid, packageName, active)); } /** * Required to override, delegate to other. Should not be called. */ public void onOpActiveChanged(String op, int uid, String packageName, boolean active) { onOpActiveChanged(op, uid, packageName, null, active, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); } // Get active app ops, and check if their attributions are trusted @Override public void onOpActiveChanged(int code, int uid, String packageName, boolean active) { public void onOpActiveChanged(String op, int uid, String packageName, String attributionTag, boolean active, int attributionFlags, int attributionChainId) { int code = AppOpsManager.strOpToOp(op); if (DEBUG) { Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s", code, uid, packageName, Boolean.toString(active))); Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s,%d,%d)", code, uid, packageName, Boolean.toString(active), attributionChainId, attributionFlags)); } if (attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE && attributionFlags != AppOpsManager.ATTRIBUTION_FLAGS_NONE && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR) == 0 && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_TRUSTED) == 0) { // if this attribution chain isn't trusted, and this isn't the accessor, do not show it. return; } boolean activeChanged = updateActives(code, uid, packageName, active); if (!activeChanged) return; // early return Loading packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +65 −34 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ public class AppOpsControllerTest extends SysuiTestCase { private static final int TEST_UID = UserHandle.getUid(0, 0); private static final int TEST_UID_OTHER = UserHandle.getUid(1, 0); private static final int TEST_UID_NON_USER_SENSITIVE = UserHandle.getUid(2, 0); private static final int TEST_CHAIN_ID = 1; @Mock private AppOpsManager mAppOpsManager; Loading Loading @@ -162,7 +163,7 @@ public class AppOpsControllerTest extends SysuiTestCase { new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); mTestableLooper.processAllMessages(); Loading @@ -174,7 +175,7 @@ public class AppOpsControllerTest extends SysuiTestCase { public void addCallback_notIncludedCode() { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback, never()).onActiveStateChanged( anyInt(), anyInt(), anyString(), anyBoolean()); Loading @@ -185,7 +186,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.removeCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback, never()).onActiveStateChanged( anyInt(), anyInt(), anyString(), anyBoolean()); Loading @@ -196,7 +197,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.removeCallback(new int[]{AppOpsManager.OP_CAMERA}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); Loading @@ -204,18 +205,18 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void getActiveItems_sameDetails() { mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); assertEquals(1, mController.getActiveAppOps().size()); } @Test public void getActiveItems_differentDetails() { mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_CAMERA, mController.onOpActiveChanged(AppOpsManager.OPSTR_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, Loading @@ -225,9 +226,9 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void getActiveItemsForUser() { mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_CAMERA, mController.onOpActiveChanged(AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, Loading @@ -242,11 +243,11 @@ public class AppOpsControllerTest extends SysuiTestCase { public void systemAndExemptedRolesAreIgnored() { assumeFalse(mExemptedRolePkgName == null || mExemptedRolePkgName.equals("")); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true); assertEquals(0, mController.getActiveAppOpsForUser( UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size()); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, SYSTEM_PKG, true); assertEquals(0, mController.getActiveAppOpsForUser( UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size()); Loading @@ -257,7 +258,7 @@ public class AppOpsControllerTest extends SysuiTestCase { assumeFalse(mExemptedRolePkgName == null || mExemptedRolePkgName.equals("")); mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true); mTestableLooper.processAllMessages(); Loading @@ -279,8 +280,8 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.setBGHandler(mMockHandler); mController.setListening(true); mController.onOpActiveChanged(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); assertFalse(mController.getActiveAppOps().isEmpty()); Loading Loading @@ -320,6 +321,36 @@ public class AppOpsControllerTest extends SysuiTestCase { verify(mMockHandler, times(2)).scheduleRemoval(any(), anyLong()); } @Test public void testUntrustedChainUsagesDiscarded() { assertTrue(mController.getActiveAppOps().isEmpty()); mController.setBGHandler(mMockHandler); //untrusted receiver access mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_RECEIVER, TEST_CHAIN_ID); //untrusted intermediary access mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_INTERMEDIARY, TEST_CHAIN_ID); assertTrue(mController.getActiveAppOps().isEmpty()); } @Test public void testTrustedChainUsagesKept() { //untrusted accessor access mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, TEST_CHAIN_ID); //trusted access mController.onOpActiveChanged(AppOpsManager.OPSTR_CAMERA, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_RECEIVER | AppOpsManager.ATTRIBUTION_FLAG_TRUSTED, TEST_CHAIN_ID); assertEquals(2, mController.getActiveAppOps().size()); } @Test public void testActiveOpNotRemovedAfterNoted() throws InterruptedException { // Replaces the timeout delay with 5 ms Loading @@ -329,7 +360,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.setBGHandler(testHandler); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); Loading Loading @@ -364,7 +395,7 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); Loading @@ -375,7 +406,7 @@ public class AppOpsControllerTest extends SysuiTestCase { assertEquals(2, list.size()); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, false); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, false); mTestableLooper.processAllMessages(); Loading @@ -393,7 +424,7 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged( Loading @@ -405,7 +436,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); Loading @@ -421,7 +452,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback, never()) Loading @@ -434,7 +465,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); assertTrue(mController.getActiveAppOps().isEmpty()); Loading @@ -446,7 +477,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); assertTrue(mController.getActiveAppOps().isEmpty()); Loading @@ -461,7 +492,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged( Loading @@ -477,7 +508,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); mRecordingCallback.onRecordingConfigChanged(Collections.emptyList()); Loading @@ -493,7 +524,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class); Loading @@ -516,7 +547,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -526,7 +557,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add a camera op, and disable the microphone. The camera op should be the only op returned mController.onSensorBlockedChanged(MICROPHONE, true); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -550,7 +581,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -560,7 +591,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add a camera op, and disable the microphone. The camera op should be the only op returned mController.onSensorBlockedChanged(MICROPHONE, true); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -583,7 +614,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -593,7 +624,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add an audio op, and disable the camera. The audio op should be the only op returned mController.onSensorBlockedChanged(CAMERA, true); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -616,7 +647,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_PHONE_CALL_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -626,7 +657,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add an audio op, and disable the camera. The audio op should be the only op returned mController.onSensorBlockedChanged(CAMERA, true); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading services/core/java/com/android/server/appop/AppOpsService.java +13 −9 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ 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.ATTRIBUTION_CHAIN_ID_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED; import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP; import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG; import static android.app.AppOpsManager.FILTER_BY_OP_NAMES; Loading Loading @@ -3332,7 +3333,8 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid)); verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid)); skipProxyOperation = resolveSkipProxyOperation(skipProxyOperation, attributionSource); skipProxyOperation = skipProxyOperation && isCallerAndAttributionTrusted(attributionSource); String resolveProxyPackageName = AppOpsManager.resolvePackageName(proxyUid, proxyPackageName); Loading Loading @@ -3849,7 +3851,8 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid)); verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid)); skipProxyOperation = resolveSkipProxyOperation(skipProxyOperation, attributionSource); boolean isCallerTrusted = isCallerAndAttributionTrusted(attributionSource); skipProxyOperation = isCallerTrusted && skipProxyOperation; String resolvedProxyPackageName = AppOpsManager.resolvePackageName(proxyUid, proxyPackageName); Loading @@ -3858,11 +3861,15 @@ public class AppOpsService extends IAppOpsService.Stub { proxiedPackageName); } final boolean isChainTrusted = isCallerTrusted && attributionChainId != ATTRIBUTION_CHAIN_ID_NONE && ((proxyAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0 || (proxiedAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0); final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid; final boolean isProxyTrusted = mContext.checkPermission( Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) == PackageManager.PERMISSION_GRANTED || isSelfBlame || attributionChainId != ATTRIBUTION_CHAIN_ID_NONE; || isChainTrusted; String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid, proxiedPackageName); Loading Loading @@ -4051,7 +4058,8 @@ public class AppOpsService extends IAppOpsService.Stub { final String proxiedAttributionTag = attributionSource.getNextAttributionTag(); final IBinder proxiedToken = attributionSource.getNextToken(); skipProxyOperation = resolveSkipProxyOperation(skipProxyOperation, attributionSource); skipProxyOperation = skipProxyOperation && isCallerAndAttributionTrusted(attributionSource); verifyIncomingProxyUid(attributionSource); verifyIncomingOp(code); Loading Loading @@ -4334,11 +4342,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } private boolean resolveSkipProxyOperation(boolean requestsSkipProxyOperation, @NonNull AttributionSource attributionSource) { if (!requestsSkipProxyOperation) { return false; } private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) { if (attributionSource.getUid() != Binder.getCallingUid() && attributionSource.isTrusted(mContext)) { return true; Loading Loading
core/java/android/app/AppOpsManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -741,6 +741,13 @@ public class AppOpsManager { @TestApi public static final int ATTRIBUTION_FLAG_RECEIVER = 0x4; /** * Attribution chain flag: Specifies that all attribution sources in the chain were trusted. * Must only be set by system server. * @hide */ public static final int ATTRIBUTION_FLAG_TRUSTED = 0x8; /** * No attribution flags. * @hide Loading @@ -760,7 +767,8 @@ public class AppOpsManager { @IntDef(flag = true, prefix = { "FLAG_" }, value = { ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_FLAG_INTERMEDIARY, ATTRIBUTION_FLAG_RECEIVER ATTRIBUTION_FLAG_RECEIVER, ATTRIBUTION_FLAG_TRUSTED }) public @interface AttributionFlags {} Loading
core/java/android/permission/PermissionUsageHelper.java +6 −1 Original line number Diff line number Diff line Loading @@ -19,9 +19,11 @@ package android.permission; import static android.Manifest.permission_group.CAMERA; import static android.Manifest.permission_group.LOCATION; import static android.Manifest.permission_group.MICROPHONE; import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAGS_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED; import static android.app.AppOpsManager.AttributionFlags; import static android.app.AppOpsManager.OPSTR_CAMERA; import static android.app.AppOpsManager.OPSTR_COARSE_LOCATION; Loading Loading @@ -180,7 +182,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { if ((attributionFlags & ATTRIBUTION_FLAGS_NONE) != 0) { if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE || attributionFlags == ATTRIBUTION_FLAGS_NONE || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { // If this is not a chain, or it is untrusted, return return; } Loading
packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java +22 −4 Original line number Diff line number Diff line Loading @@ -64,7 +64,7 @@ import javax.inject.Inject; */ @SysUISingleton public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController, AppOpsManager.OnOpActiveChangedInternalListener, AppOpsManager.OnOpActiveChangedListener, AppOpsManager.OnOpNotedListener, IndividualSensorPrivacyController.Callback, Dumpable { Loading Loading @@ -359,11 +359,29 @@ public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsCon mBGHandler.post(() -> notifySuscribersWorker(code, uid, packageName, active)); } /** * Required to override, delegate to other. Should not be called. */ public void onOpActiveChanged(String op, int uid, String packageName, boolean active) { onOpActiveChanged(op, uid, packageName, null, active, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE); } // Get active app ops, and check if their attributions are trusted @Override public void onOpActiveChanged(int code, int uid, String packageName, boolean active) { public void onOpActiveChanged(String op, int uid, String packageName, String attributionTag, boolean active, int attributionFlags, int attributionChainId) { int code = AppOpsManager.strOpToOp(op); if (DEBUG) { Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s", code, uid, packageName, Boolean.toString(active))); Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s,%d,%d)", code, uid, packageName, Boolean.toString(active), attributionChainId, attributionFlags)); } if (attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE && attributionFlags != AppOpsManager.ATTRIBUTION_FLAGS_NONE && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR) == 0 && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_TRUSTED) == 0) { // if this attribution chain isn't trusted, and this isn't the accessor, do not show it. return; } boolean activeChanged = updateActives(code, uid, packageName, active); if (!activeChanged) return; // early return Loading
packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java +65 −34 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ public class AppOpsControllerTest extends SysuiTestCase { private static final int TEST_UID = UserHandle.getUid(0, 0); private static final int TEST_UID_OTHER = UserHandle.getUid(1, 0); private static final int TEST_UID_NON_USER_SENSITIVE = UserHandle.getUid(2, 0); private static final int TEST_CHAIN_ID = 1; @Mock private AppOpsManager mAppOpsManager; Loading Loading @@ -162,7 +163,7 @@ public class AppOpsControllerTest extends SysuiTestCase { new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); mTestableLooper.processAllMessages(); Loading @@ -174,7 +175,7 @@ public class AppOpsControllerTest extends SysuiTestCase { public void addCallback_notIncludedCode() { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback, never()).onActiveStateChanged( anyInt(), anyInt(), anyString(), anyBoolean()); Loading @@ -185,7 +186,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.removeCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback, never()).onActiveStateChanged( anyInt(), anyInt(), anyString(), anyBoolean()); Loading @@ -196,7 +197,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.removeCallback(new int[]{AppOpsManager.OP_CAMERA}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); Loading @@ -204,18 +205,18 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void getActiveItems_sameDetails() { mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); assertEquals(1, mController.getActiveAppOps().size()); } @Test public void getActiveItems_differentDetails() { mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_CAMERA, mController.onOpActiveChanged(AppOpsManager.OPSTR_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, Loading @@ -225,9 +226,9 @@ public class AppOpsControllerTest extends SysuiTestCase { @Test public void getActiveItemsForUser() { mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OP_CAMERA, mController.onOpActiveChanged(AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, Loading @@ -242,11 +243,11 @@ public class AppOpsControllerTest extends SysuiTestCase { public void systemAndExemptedRolesAreIgnored() { assumeFalse(mExemptedRolePkgName == null || mExemptedRolePkgName.equals("")); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true); assertEquals(0, mController.getActiveAppOpsForUser( UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size()); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, SYSTEM_PKG, true); assertEquals(0, mController.getActiveAppOpsForUser( UserHandle.getUserId(TEST_UID_NON_USER_SENSITIVE), false).size()); Loading @@ -257,7 +258,7 @@ public class AppOpsControllerTest extends SysuiTestCase { assumeFalse(mExemptedRolePkgName == null || mExemptedRolePkgName.equals("")); mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO, mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_NON_USER_SENSITIVE, mExemptedRolePkgName, true); mTestableLooper.processAllMessages(); Loading @@ -279,8 +280,8 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.setBGHandler(mMockHandler); mController.setListening(true); mController.onOpActiveChanged(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpActiveChanged(AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); assertFalse(mController.getActiveAppOps().isEmpty()); Loading Loading @@ -320,6 +321,36 @@ public class AppOpsControllerTest extends SysuiTestCase { verify(mMockHandler, times(2)).scheduleRemoval(any(), anyLong()); } @Test public void testUntrustedChainUsagesDiscarded() { assertTrue(mController.getActiveAppOps().isEmpty()); mController.setBGHandler(mMockHandler); //untrusted receiver access mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_RECEIVER, TEST_CHAIN_ID); //untrusted intermediary access mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_INTERMEDIARY, TEST_CHAIN_ID); assertTrue(mController.getActiveAppOps().isEmpty()); } @Test public void testTrustedChainUsagesKept() { //untrusted accessor access mController.onOpActiveChanged(AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, TEST_CHAIN_ID); //trusted access mController.onOpActiveChanged(AppOpsManager.OPSTR_CAMERA, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, true, AppOpsManager.ATTRIBUTION_FLAG_RECEIVER | AppOpsManager.ATTRIBUTION_FLAG_TRUSTED, TEST_CHAIN_ID); assertEquals(2, mController.getActiveAppOps().size()); } @Test public void testActiveOpNotRemovedAfterNoted() throws InterruptedException { // Replaces the timeout delay with 5 ms Loading @@ -329,7 +360,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.setBGHandler(testHandler); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); Loading Loading @@ -364,7 +395,7 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); Loading @@ -375,7 +406,7 @@ public class AppOpsControllerTest extends SysuiTestCase { assertEquals(2, list.size()); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, false); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, false); mTestableLooper.processAllMessages(); Loading @@ -393,7 +424,7 @@ public class AppOpsControllerTest extends SysuiTestCase { TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged( Loading @@ -405,7 +436,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback); mController.onOpActiveChanged( AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true); mController.onOpNoted(AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, TEST_ATTRIBUTION_NAME, AppOpsManager.OP_FLAG_SELF, AppOpsManager.MODE_ALLOWED); Loading @@ -421,7 +452,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback, never()) Loading @@ -434,7 +465,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); assertTrue(mController.getActiveAppOps().isEmpty()); Loading @@ -446,7 +477,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); assertTrue(mController.getActiveAppOps().isEmpty()); Loading @@ -461,7 +492,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); verify(mCallback).onActiveStateChanged( Loading @@ -477,7 +508,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); mRecordingCallback.onRecordingConfigChanged(Collections.emptyList()); Loading @@ -493,7 +524,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); AudioRecordingConfiguration mockARC = mock(AudioRecordingConfiguration.class); Loading @@ -516,7 +547,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -526,7 +557,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add a camera op, and disable the microphone. The camera op should be the only op returned mController.onSensorBlockedChanged(MICROPHONE, true); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -550,7 +581,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_PHONE_CALL_MICROPHONE, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -560,7 +591,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add a camera op, and disable the microphone. The camera op should be the only op returned mController.onSensorBlockedChanged(MICROPHONE, true); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -583,7 +614,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -593,7 +624,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add an audio op, and disable the camera. The audio op should be the only op returned mController.onSensorBlockedChanged(CAMERA, true); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -616,7 +647,7 @@ public class AppOpsControllerTest extends SysuiTestCase { mCallback); mTestableLooper.processAllMessages(); mController.onOpActiveChanged( AppOpsManager.OP_PHONE_CALL_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_PHONE_CALL_CAMERA, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); List<AppOpItem> list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading @@ -626,7 +657,7 @@ public class AppOpsControllerTest extends SysuiTestCase { // Add an audio op, and disable the camera. The audio op should be the only op returned mController.onSensorBlockedChanged(CAMERA, true); mController.onOpActiveChanged( AppOpsManager.OP_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); AppOpsManager.OPSTR_RECORD_AUDIO, TEST_UID_OTHER, TEST_PACKAGE_NAME, true); mTestableLooper.processAllMessages(); list = mController.getActiveAppOps(); assertEquals(1, list.size()); Loading
services/core/java/com/android/server/appop/AppOpsService.java +13 −9 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ 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.ATTRIBUTION_CHAIN_ID_NONE; import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED; import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP; import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG; import static android.app.AppOpsManager.FILTER_BY_OP_NAMES; Loading Loading @@ -3332,7 +3333,8 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid)); verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid)); skipProxyOperation = resolveSkipProxyOperation(skipProxyOperation, attributionSource); skipProxyOperation = skipProxyOperation && isCallerAndAttributionTrusted(attributionSource); String resolveProxyPackageName = AppOpsManager.resolvePackageName(proxyUid, proxyPackageName); Loading Loading @@ -3849,7 +3851,8 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid)); verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid)); skipProxyOperation = resolveSkipProxyOperation(skipProxyOperation, attributionSource); boolean isCallerTrusted = isCallerAndAttributionTrusted(attributionSource); skipProxyOperation = isCallerTrusted && skipProxyOperation; String resolvedProxyPackageName = AppOpsManager.resolvePackageName(proxyUid, proxyPackageName); Loading @@ -3858,11 +3861,15 @@ public class AppOpsService extends IAppOpsService.Stub { proxiedPackageName); } final boolean isChainTrusted = isCallerTrusted && attributionChainId != ATTRIBUTION_CHAIN_ID_NONE && ((proxyAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0 || (proxiedAttributionFlags & ATTRIBUTION_FLAG_TRUSTED) != 0); final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid; final boolean isProxyTrusted = mContext.checkPermission( Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid) == PackageManager.PERMISSION_GRANTED || isSelfBlame || attributionChainId != ATTRIBUTION_CHAIN_ID_NONE; || isChainTrusted; String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid, proxiedPackageName); Loading Loading @@ -4051,7 +4058,8 @@ public class AppOpsService extends IAppOpsService.Stub { final String proxiedAttributionTag = attributionSource.getNextAttributionTag(); final IBinder proxiedToken = attributionSource.getNextToken(); skipProxyOperation = resolveSkipProxyOperation(skipProxyOperation, attributionSource); skipProxyOperation = skipProxyOperation && isCallerAndAttributionTrusted(attributionSource); verifyIncomingProxyUid(attributionSource); verifyIncomingOp(code); Loading Loading @@ -4334,11 +4342,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } private boolean resolveSkipProxyOperation(boolean requestsSkipProxyOperation, @NonNull AttributionSource attributionSource) { if (!requestsSkipProxyOperation) { return false; } private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) { if (attributionSource.getUid() != Binder.getCallingUid() && attributionSource.isTrusted(mContext)) { return true; Loading