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

Commit e0e99a80 authored by Sally's avatar Sally
Browse files

Check for the COMPANION_DEVICE_APP_STREAMING role when registering a proxy

If an app doesn't have the MANAGE_ACCESSIBILITY permission, check for
the streaming role, which is equivalent to DEVICE_PROFILE_APP_STREAMING

Test: atest AccessibilityDisplayProxyTest, manual with Exo
Bug: 280661435
Change-Id: I2d243bdf86d6da1ad6c17fefefd3abd135dd2b30
parent 2d750615
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -4006,8 +4006,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
    @Override
    @Override
    public boolean registerProxyForDisplay(IAccessibilityServiceClient client, int displayId)
    public boolean registerProxyForDisplay(IAccessibilityServiceClient client, int displayId)
            throws RemoteException {
            throws RemoteException {
        mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
        mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.CREATE_VIRTUAL_DEVICE);
        mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.CREATE_VIRTUAL_DEVICE);
        mSecurityPolicy.checkForAccessibilityPermissionOrRole();
        if (client == null) {
        if (client == null) {
            return false;
            return false;
        }
        }
@@ -4043,8 +4043,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub


    @Override
    @Override
    public boolean unregisterProxyForDisplay(int displayId) {
    public boolean unregisterProxyForDisplay(int displayId) {
        mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
        mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.CREATE_VIRTUAL_DEVICE);
        mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.CREATE_VIRTUAL_DEVICE);
        mSecurityPolicy.checkForAccessibilityPermissionOrRole();
        final long identity = Binder.clearCallingIdentity();
        final long identity = Binder.clearCallingIdentity();
        try {
        try {
            return mProxyManager.unregisterProxy(displayId);
            return mProxyManager.unregisterProxy(displayId);
+38 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.accessibility;


import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_BY_ADMIN;
import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_FAIL_BY_ADMIN;
import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_SUCCESS;
import static android.accessibilityservice.AccessibilityService.SoftKeyboardController.ENABLE_IME_SUCCESS;
import static android.companion.AssociationRequest.DEVICE_PROFILE_APP_STREAMING;


import android.Manifest;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityService;
@@ -25,6 +26,7 @@ import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.AppOpsManager;
import android.app.role.RoleManager;
import android.appwidget.AppWidgetManagerInternal;
import android.appwidget.AppWidgetManagerInternal;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
@@ -674,6 +676,42 @@ public class AccessibilitySecurityPolicy {
        }
        }
    }
    }


    /**
     * Throws a SecurityException if the caller has neither the MANAGE_ACCESSIBILITY permission nor
     * the COMPANION_DEVICE_APP_STREAMING role.
     */
    public void checkForAccessibilityPermissionOrRole() {
        final boolean canManageAccessibility =
                mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
                        == PackageManager.PERMISSION_GRANTED;
        if (canManageAccessibility) {
            return;
        }
        final int callingUid = Binder.getCallingUid();
        final long identity = Binder.clearCallingIdentity();
        try {
            final RoleManager roleManager = mContext.getSystemService(RoleManager.class);
            if (roleManager != null) {
                final List<String> holders = roleManager.getRoleHoldersAsUser(
                        DEVICE_PROFILE_APP_STREAMING, UserHandle.getUserHandleForUid(callingUid));
                final String[] packageNames = mPackageManager.getPackagesForUid(callingUid);
                if (packageNames != null) {
                    for (String packageName : packageNames) {
                        if (holders.contains(packageName)) {
                            return;
                        }
                    }
                }
            }
            throw new SecurityException(
                    "Cannot register a proxy for a device without the "
                            + "android.app.role.COMPANION_DEVICE_APP_STREAMING role or the"
                            + " MANAGE_ACCESSIBILITY permission.");
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
    /**
     * Called after a service was bound or unbound. Checks the current bound accessibility
     * Called after a service was bound or unbound. Checks the current bound accessibility
     * services and updates alarms.
     * services and updates alarms.
+4 −4
Original line number Original line Diff line number Diff line
@@ -290,9 +290,9 @@ public class AccessibilityManagerServiceTest {


    @SmallTest
    @SmallTest
    @Test
    @Test
    public void testRegisterProxyWithoutA11yPermission() throws Exception {
    public void testRegisterProxyWithoutA11yPermissionOrRole() throws Exception {
        doThrow(SecurityException.class).when(mMockSecurityPolicy)
        doThrow(SecurityException.class).when(mMockSecurityPolicy)
                .enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
                .checkForAccessibilityPermissionOrRole();


        assertThrows(SecurityException.class,
        assertThrows(SecurityException.class,
                () -> mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY));
                () -> mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY));
@@ -342,9 +342,9 @@ public class AccessibilityManagerServiceTest {


    @SmallTest
    @SmallTest
    @Test
    @Test
    public void testUnRegisterProxyWithoutA11yPermission() {
    public void testUnRegisterProxyWithoutA11yPermissionOrRole() {
        doThrow(SecurityException.class).when(mMockSecurityPolicy)
        doThrow(SecurityException.class).when(mMockSecurityPolicy)
                .enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
                .checkForAccessibilityPermissionOrRole();


        assertThrows(SecurityException.class,
        assertThrows(SecurityException.class,
                () -> mA11yms.unregisterProxyForDisplay(TEST_DISPLAY));
                () -> mA11yms.unregisterProxyForDisplay(TEST_DISPLAY));