Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e1aef37 authored by Nate Myren's avatar Nate Myren Committed by Android (Google) Code Review
Browse files

Merge "Create "trusted chain" mechanism for AttributionSource" into sc-dev

parents 3196d0fa 4c426c4d
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -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
@@ -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 {}

+6 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;
        }

+22 −4
Original line number Diff line number Diff line
@@ -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 {

@@ -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
+65 −34
Original line number Diff line number Diff line
@@ -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;
@@ -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();
@@ -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());
@@ -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());
@@ -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);
@@ -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,
@@ -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,
@@ -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());
@@ -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();
@@ -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());
@@ -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
@@ -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);
@@ -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();
@@ -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();

@@ -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(
@@ -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);
@@ -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())
@@ -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());
@@ -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());
@@ -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(
@@ -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());
@@ -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);
@@ -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());
@@ -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());
@@ -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());
@@ -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());
@@ -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());
@@ -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());
@@ -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());
@@ -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());
+13 −9
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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);
@@ -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