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

Commit 49156faf authored by Dorin Drimus's avatar Dorin Drimus
Browse files

Check wiu permissions on any deviceId to start a fgs

Some of the wiu permissions required to start a foreground service can
be device aware (RECORD_AUDIO and CAMERA) and they can be different
depending on the resources (virtual audio or camera devices) used.
This relaxes the check to allow the fgs to start if it has the permission
on any of the active deviceIds (virtual devices).

CTS test added in ag/32131429, @Ignore for the immediate release (though
it passes and will be reenabled by b/402139346).

Bug: 381386115
Bug: 400753852
Test: manual VDM demo sample app with Pixel Recorder app
Test: atest android.virtualdevice.cts.audio.VirtualAudioPermissionTest
Test: atest ActivityManagerForegroundServiceTypeTest
Flag: EXEMPT, bugfix
Change-Id: I91b01ba2dddda83801a2a9b586cd03bbdc780754
parent 546ca204
Loading
Loading
Loading
Loading
+41 −6
Original line number Diff line number Diff line
@@ -49,11 +49,14 @@ import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.compat.CompatChanges;
import android.app.role.RoleManager;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.Overridable;
import android.content.AttributionSource;
import android.content.Context;
import android.content.PermissionChecker;
import android.content.pm.PackageManager;
@@ -67,6 +70,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.permission.PermissionCheckerManager;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -1174,17 +1178,48 @@ public abstract class ForegroundServiceTypePolicy {
        @PackageManager.PermissionResult
        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                String packageName, boolean allowWhileInUse) {
            return checkPermission(context, mName, callerUid, callerPid, packageName,
                    allowWhileInUse);
            int permissionResult = checkPermission(context, mName, callerUid, callerPid,
                    packageName, allowWhileInUse, Context.DEVICE_ID_DEFAULT);

            if (permissionResult == PERMISSION_GRANTED
                    || !PermissionManager.DEVICE_AWARE_PERMISSIONS.contains(mName)) {
                return permissionResult;
            }

            // For device aware permissions, check if the permission is granted on any other
            // active virtual device
            VirtualDeviceManager vdm = context.getSystemService(VirtualDeviceManager.class);
            if (vdm == null) {
                return permissionResult;
            }

            final List<VirtualDevice> virtualDevices = vdm.getVirtualDevices();
            for (int i = 0, size = virtualDevices.size(); i < size; i++) {
                final VirtualDevice virtualDevice = virtualDevices.get(i);
                int resolvedDeviceId = PermissionManager.resolveDeviceIdForPermissionCheck(
                        context, virtualDevice.getDeviceId(), mName);
                // we already checked on the default device context
                if (resolvedDeviceId == Context.DEVICE_ID_DEFAULT) {
                    continue;
                }
                permissionResult = checkPermission(context, mName, callerUid, callerPid,
                        packageName, allowWhileInUse, resolvedDeviceId);
                if (permissionResult == PERMISSION_GRANTED) {
                    break;
                }
            }

            return permissionResult;
        }

        @SuppressLint("AndroidFrameworkRequiresPermission")
        @PackageManager.PermissionResult
        int checkPermission(@NonNull Context context, @NonNull String name, int callerUid,
                int callerPid, String packageName, boolean allowWhileInUse) {
                int callerPid, String packageName, boolean allowWhileInUse, int deviceId) {
            final AttributionSource attributionSource = new AttributionSource(callerUid,
                    packageName, null /*attributionTag*/, deviceId);
            @PermissionCheckerManager.PermissionResult final int result =
                    PermissionChecker.checkPermissionForPreflight(context, name,
                            callerPid, callerUid, packageName);
                    PermissionChecker.checkPermissionForPreflight(context, name, attributionSource);
            if (result == PERMISSION_HARD_DENIED) {
                // If the user didn't grant this permission at all.
                return PERMISSION_DENIED;
@@ -1196,7 +1231,7 @@ public abstract class ForegroundServiceTypePolicy {
                        ? PERMISSION_GRANTED : PERMISSION_DENIED;
            }
            final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
            final int mode = appOpsManager.unsafeCheckOpRawNoThrow(opCode, callerUid, packageName);
            final int mode = appOpsManager.unsafeCheckOpRawNoThrow(opCode, attributionSource);
            switch (mode) {
                case MODE_ALLOWED:
                    // The appop is just allowed, plain and simple.