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

Commit 3db806e1 authored by Charles Chen's avatar Charles Chen
Browse files

Hide camera and microphone indicators

Both indicators need to be hidden for VisualQueryDetectionService which
does not have a designated AppOp defined for its access to the camera
or audio service.

Bug: 269304889
Test: Indicators are not shown
Test: atest android.cts.statsdatom.appops.AppOpsTests#testAppOps
Change-Id: I5a97e41f7ea4b000604e2dd47473ed7d70c81c45
parent 9af3f455
Loading
Loading
Loading
Loading
+38 −2
Original line number Diff line number Diff line
@@ -1461,9 +1461,25 @@ public class AppOpsManager {
     */
    public static final int OP_USE_FULL_SCREEN_INTENT = AppProtoEnums.APP_OP_USE_FULL_SCREEN_INTENT;

    /**
     * Hides camera indicator for sandboxed detection apps that directly access the service.
     *
     * @hide
     */
    public static final int OP_CAMERA_SANDBOXED =
            AppProtoEnums.APP_OP_CAMERA_SANDBOXED;

    /**
     * Hides microphone indicator for sandboxed detection apps that directly access the service.
     *
     * @hide
     */
    public static final int OP_RECORD_AUDIO_SANDBOXED =
            AppProtoEnums.APP_OP_RECORD_AUDIO_SANDBOXED;

    /** @hide */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public static final int _NUM_OP = 134;
    public static final int _NUM_OP = 136;

    /**
     * All app ops represented as strings.
@@ -1605,6 +1621,8 @@ public class AppOpsManager {
            OPSTR_CAPTURE_CONSENTLESS_BUGREPORT_ON_USERDEBUG_BUILD,
            OPSTR_BODY_SENSORS_WRIST_TEMPERATURE,
            OPSTR_USE_FULL_SCREEN_INTENT,
            OPSTR_CAMERA_SANDBOXED,
            OPSTR_RECORD_AUDIO_SANDBOXED
    })
    public @interface AppOpString {}

@@ -2012,6 +2030,20 @@ public class AppOpsManager {
     */
    public static final String OPSTR_COARSE_LOCATION_SOURCE = "android:coarse_location_source";

    /**
     * Camera is being recorded in sandboxed detection process.
     *
     * @hide
     */
    public static final String OPSTR_CAMERA_SANDBOXED = "android:camera_sandboxed";

    /**
     * Audio is being recorded in sandboxed detection process.
     *
     * @hide
     */
    public static final String OPSTR_RECORD_AUDIO_SANDBOXED = "android:record_audio_sandboxed";

    /**
     * Allow apps to create the requests to manage the media files without user confirmation.
     *
@@ -2738,7 +2770,11 @@ public class AppOpsManager {
                .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
        new AppOpInfo.Builder(OP_USE_FULL_SCREEN_INTENT, OPSTR_USE_FULL_SCREEN_INTENT,
                "USE_FULL_SCREEN_INTENT").setPermission(Manifest.permission.USE_FULL_SCREEN_INTENT)
                .build()
                .build(),
        new AppOpInfo.Builder(OP_CAMERA_SANDBOXED, OPSTR_CAMERA_SANDBOXED,
            "CAMERA_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build(),
        new AppOpInfo.Builder(OP_RECORD_AUDIO_SANDBOXED, OPSTR_RECORD_AUDIO_SANDBOXED,
                "RECORD_AUDIO_SANDBOXED").setDefaultMode(AppOpsManager.MODE_ALLOWED).build()
    };

    // The number of longs needed to form a full bitmask of app ops
+19 −5
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_CAMERA_SANDBOXED;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
@@ -42,6 +43,7 @@ import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_SANDBOXED;
import static android.app.AppOpsManager.OP_VIBRATE;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
@@ -3027,17 +3029,29 @@ public class AppOpsService extends IAppOpsService.Stub {
                    packageName);
        }

        // As a special case for OP_RECORD_AUDIO_HOTWORD, which we use only for attribution
        // purposes and not as a check, also make sure that the caller is allowed to access
        // the data gated by OP_RECORD_AUDIO.
        // As a special case for OP_RECORD_AUDIO_HOTWORD, OP_RECEIVE_AMBIENT_TRIGGER_AUDIO and
        // OP_RECORD_AUDIO_SANDBOXED which we use only for attribution purposes and not as a check,
        // also make sure that the caller is allowed to access the data gated by OP_RECORD_AUDIO.
        //
        // TODO: Revert this change before Android 12.
        if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO) {
            int result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
        int result = MODE_DEFAULT;
        if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO
                || code == OP_RECORD_AUDIO_SANDBOXED) {
            result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
            // Check result
            if (result != AppOpsManager.MODE_ALLOWED) {
                return new SyncNotedAppOp(result, code, attributionTag, packageName);
            }
        }
        // As a special case for OP_CAMERA_SANDBOXED.
        if (code == OP_CAMERA_SANDBOXED) {
            result = checkOperation(OP_CAMERA, uid, packageName);
            // Check result
            if (result != AppOpsManager.MODE_ALLOWED) {
                return new SyncNotedAppOp(result, code, attributionTag, packageName);
            }
        }

        return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
                Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
                shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
+23 −0
Original line number Diff line number Diff line
@@ -316,6 +316,7 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
    private int resolveDatasourceOp(int code, int uid, @NonNull String packageName,
            @Nullable String attributionTag) {
        code = resolveRecordAudioOp(code, uid);
        code = resolveSandboxedServiceOp(code, uid);
        if (attributionTag == null) {
            return code;
        }
@@ -439,6 +440,28 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat
        return code;
    }

    private int resolveSandboxedServiceOp(int code, int uid) {
        if (!Process.isIsolated(uid) // simple check which fails-fast for the common case
                 || !(code == AppOpsManager.OP_RECORD_AUDIO || code == AppOpsManager.OP_CAMERA)) {
            return code;
        }
        final HotwordDetectionServiceIdentity hotwordDetectionServiceIdentity =
                mVoiceInteractionManagerInternal.getHotwordDetectionServiceIdentity();
        if (hotwordDetectionServiceIdentity != null
                && uid == hotwordDetectionServiceIdentity.getIsolatedUid()) {
            // Upgrade the op such that no indicators is shown for camera or audio service. This
            // will bypass the permission checking for the original OP_RECORD_AUDIO and OP_CAMERA.
            switch (code) {
                case AppOpsManager.OP_RECORD_AUDIO:
                    return AppOpsManager.OP_RECORD_AUDIO_SANDBOXED;
                case AppOpsManager.OP_CAMERA:
                    return AppOpsManager.OP_CAMERA_SANDBOXED;
            }
        }
        return code;
    }


    private int resolveUid(int code, int uid) {
        // The HotwordDetectionService is an isolated service, which ordinarily cannot hold
        // permissions. So we allow it to assume the owning package identity for certain