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

Commit 4c426c4d authored by Nate Myren's avatar Nate Myren
Browse files

Create "trusted chain" mechanism for AttributionSource

Add and populate a "trusted" attribution flag, that verifies the
attribution sources used to create it were trusted.

Fixes: 192270935
Test: atest RuntimePermissionsAppOpTrackingTest
Change-Id: Ifd8f825151bec55aa795da7bee0a3069509f5abe
parent c2a780db
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