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

Commit 9727c058 authored by Evan Severson's avatar Evan Severson Committed by Android (Google) Code Review
Browse files

Merge "Separate Usb permissions from Usb settings"

parents 903102c4 e05005b1
Loading
Loading
Loading
Loading
+14 −14
Original line number Diff line number Diff line
@@ -250,7 +250,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
    }

    public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager) {
            UsbSettingsManager settingsManager, UsbPermissionManager permissionManager) {
        mContext = context;
        mContentResolver = context.getContentResolver();
        PackageManager pm = mContext.getPackageManager();
@@ -284,13 +284,13 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
             * Initialze the legacy UsbHandler
             */
            mHandler = new UsbHandlerLegacy(FgThread.get().getLooper(), mContext, this,
                    alsaManager, settingsManager);
                    alsaManager, permissionManager);
        } else {
            /**
             * Initialize HAL based UsbHandler
             */
            mHandler = new UsbHandlerHal(FgThread.get().getLooper(), mContext, this,
                    alsaManager, settingsManager);
                    alsaManager, permissionManager);
        }

        if (nativeIsStartRequested()) {
@@ -468,7 +468,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser

        private final Context mContext;
        private final UsbAlsaManager mUsbAlsaManager;
        private final UsbSettingsManager mSettingsManager;
        private final UsbPermissionManager mPermissionManager;
        private NotificationManager mNotificationManager;

        protected long mScreenUnlockedFunctions;
@@ -489,12 +489,12 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
        protected static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";

        UsbHandler(Looper looper, Context context, UsbDeviceManager deviceManager,
                UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) {
                UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
            super(looper);
            mContext = context;
            mUsbDeviceManager = deviceManager;
            mUsbAlsaManager = alsaManager;
            mSettingsManager = settingsManager;
            mPermissionManager = permissionManager;
            mContentResolver = context.getContentResolver();

            mCurrentUser = ActivityManager.getCurrentUser();
@@ -625,7 +625,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
                // successfully entered accessory mode
                String[] accessoryStrings = mUsbDeviceManager.getAccessoryStrings();
                if (accessoryStrings != null) {
                    UsbSerialReader serialReader = new UsbSerialReader(mContext, mSettingsManager,
                    UsbSerialReader serialReader = new UsbSerialReader(mContext, mPermissionManager,
                            accessoryStrings[UsbAccessory.SERIAL_STRING]);

                    mCurrentAccessory = new UsbAccessory(
@@ -663,7 +663,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser

            if (mCurrentAccessory != null) {
                if (mBootCompleted) {
                    mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
                    mPermissionManager.usbAccessoryRemoved(mCurrentAccessory);
                }
                mCurrentAccessory = null;
            }
@@ -1343,8 +1343,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
        private boolean mUsbDataUnlocked;

        UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
                UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) {
            super(looper, context, deviceManager, alsaManager, settingsManager);
                UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
            super(looper, context, deviceManager, alsaManager, permissionManager);
            try {
                readOemUsbOverrideConfig(context);
                // Restore default functions.
@@ -1738,8 +1738,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
        protected boolean mCurrentUsbFunctionsRequested;

        UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager,
                UsbAlsaManager alsaManager, UsbSettingsManager settingsManager) {
            super(looper, context, deviceManager, alsaManager, settingsManager);
                UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
            super(looper, context, deviceManager, alsaManager, permissionManager);
            try {
                ServiceNotification serviceNotification = new ServiceNotification();

@@ -1977,7 +1977,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
     * @param uid Uid of the caller
     */
    public ParcelFileDescriptor openAccessory(UsbAccessory accessory,
            UsbUserSettingsManager settings, int uid) {
            UsbUserPermissionManager permissions, int uid) {
        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
        if (currentAccessory == null) {
            throw new IllegalArgumentException("no accessory attached");
@@ -1988,7 +1988,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
                    + currentAccessory;
            throw new IllegalArgumentException(error);
        }
        settings.checkPermission(accessory, uid);
        permissions.checkPermission(accessory, uid);
        return nativeOpenAccessory();
    }

+12 −10
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ public class UsbHostManager {
    private final String[] mHostBlacklist;

    private final UsbAlsaManager mUsbAlsaManager;
    private final UsbSettingsManager mSettingsManager;
    private final UsbPermissionManager mPermissionManager;

    private final Object mLock = new Object();
    @GuardedBy("mLock")
@@ -232,13 +232,13 @@ public class UsbHostManager {
     * UsbHostManager
     */
    public UsbHostManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager) {
            UsbPermissionManager permissionManager) {
        mContext = context;

        mHostBlacklist = context.getResources().getStringArray(
                com.android.internal.R.array.config_usbHostBlacklist);
        mUsbAlsaManager = alsaManager;
        mSettingsManager = settingsManager;
        mPermissionManager = permissionManager;
        String deviceConnectionHandler = context.getResources().getString(
                com.android.internal.R.string.config_UsbDeviceConnectionHandling_component);
        if (!TextUtils.isEmpty(deviceConnectionHandler)) {
@@ -393,8 +393,8 @@ public class UsbHostManager {
                addConnectionRecord(deviceAddress, ConnectionRecord.CONNECT_BADDEVICE,
                        parser.getRawDescriptors());
            } else {
                UsbSerialReader serialNumberReader = new UsbSerialReader(mContext, mSettingsManager,
                        newDeviceBuilder.serialNumber);
                UsbSerialReader serialNumberReader = new UsbSerialReader(mContext,
                        mPermissionManager, newDeviceBuilder.serialNumber);
                UsbDevice newDevice = newDeviceBuilder.build(serialNumberReader);
                serialNumberReader.setDevice(newDevice);

@@ -444,7 +444,7 @@ public class UsbHostManager {
            if (device != null) {
                Slog.d(TAG, "Removed device at " + deviceAddress + ": " + device.getProductName());
                mUsbAlsaManager.usbDeviceRemoved(deviceAddress);
                mSettingsManager.usbDeviceRemoved(device);
                mPermissionManager.usbDeviceRemoved(device);
                getCurrentUserSettings().usbDeviceRemoved(device);
                ConnectionRecord current = mConnected.get(deviceAddress);
                // Tracking
@@ -484,9 +484,11 @@ public class UsbHostManager {
        }
    }

    /* Opens the specified USB device */
    public ParcelFileDescriptor openDevice(String deviceAddress, UsbUserSettingsManager settings,
            String packageName, int uid) {
    /**
     *  Opens the specified USB device
     */
    public ParcelFileDescriptor openDevice(String deviceAddress,
            UsbUserPermissionManager permissions, String packageName, int uid) {
        synchronized (mLock) {
            if (isBlackListed(deviceAddress)) {
                throw new SecurityException("USB device is on a restricted bus");
@@ -498,7 +500,7 @@ public class UsbHostManager {
                        "device " + deviceAddress + " does not exist or is restricted");
            }

            settings.checkPermission(device, packageName, uid);
            permissions.checkPermission(device, packageName, uid);
            return nativeOpenDevice(deviceAddress);
        }
    }
+50 −185
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -17,230 +17,95 @@
package com.android.server.usb;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Binder;
import android.os.Process;
import android.os.UserHandle;
import android.service.usb.UsbSettingsAccessoryPermissionProto;
import android.service.usb.UsbSettingsDevicePermissionProto;
import android.service.usb.UsbUserSettingsManagerProto;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.dump.DualDumpOutputStream;

import java.util.HashMap;

/**
 * UsbPermissionManager manages usb device or accessory access permissions.
 *
 * @hide
 */
class UsbPermissionManager {
    private static final String LOG_TAG = UsbPermissionManager.class.getSimpleName();
    private static final boolean DEBUG = false;

    @GuardedBy("mLock")
    /** Temporary mapping USB device name to list of UIDs with permissions for the device*/
    private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
            new HashMap<>();
    @GuardedBy("mLock")
    /** Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory*/
    private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
            new HashMap<>();
    /** Context to be used by this module */
    private final @NonNull Context mContext;

    private final UserHandle mUser;
    private final boolean mDisablePermissionDialogs;
    /** Map from user id to {@link UsbUserPermissionManager} for the user */
    @GuardedBy("mPermissionsByUser")
    private final SparseArray<UsbUserPermissionManager> mPermissionsByUser = new SparseArray<>();

    private final Object mLock = new Object();
    final UsbService mUsbService;

    UsbPermissionManager(@NonNull Context context, @NonNull UserHandle user) {
        mUser = user;
        mDisablePermissionDialogs = context.getResources().getBoolean(
                com.android.internal.R.bool.config_disableUsbPermissionDialogs);
    UsbPermissionManager(@NonNull Context context,
            @NonNull UsbService usbService) {
        mContext = context;
        mUsbService = usbService;
    }

    /**
     * Removes access permissions of all packages for the USB accessory.
     *
     * @param accessory to remove permissions for
     */
    void removeAccessoryPermissions(@NonNull UsbAccessory accessory) {
        synchronized (mLock) {
            mAccessoryPermissionMap.remove(accessory);
        }
    @NonNull UsbUserPermissionManager getPermissionsForUser(@UserIdInt int userId) {
        synchronized (mPermissionsByUser) {
            UsbUserPermissionManager permissions = mPermissionsByUser.get(userId);
            if (permissions == null) {
                permissions = new UsbUserPermissionManager(mContext, UserHandle.of(userId),
                        mUsbService.getSettingsForUser(userId));
                mPermissionsByUser.put(userId, permissions);
            }

    /**
     * Removes access permissions of all packages for the USB device.
     *
     * @param device to remove permissions for
     */
    void removeDevicePermissions(@NonNull UsbDevice device) {
        synchronized (mLock) {
            mDevicePermissionMap.remove(device.getDeviceName());
            return permissions;
        }
    }

    /**
     * Grants permission for USB device without showing system dialog for package with uid.
     *
     * @param device to grant permission for
     * @param uid to grant permission for
     */
    void grantDevicePermission(@NonNull UsbDevice device, int uid) {
        synchronized (mLock) {
            String deviceName = device.getDeviceName();
            SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
            if (uidList == null) {
                uidList = new SparseBooleanArray(1);
                mDevicePermissionMap.put(deviceName, uidList);
            }
            uidList.put(uid, true);
    void remove(@NonNull UserHandle userToRemove) {
        synchronized (mPermissionsByUser) {
            mPermissionsByUser.remove(userToRemove.getIdentifier());
        }
    }

    /**
     * Grants permission for USB accessory without showing system dialog for package with uid.
     * Remove temporary access permission and broadcast that a device was removed.
     *
     * @param accessory to grant permission for
     * @param uid to grant permission for
     * @param device The device that is removed
     */
    void grantAccessoryPermission(@NonNull UsbAccessory accessory, int uid) {
        synchronized (mLock) {
            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
            if (uidList == null) {
                uidList = new SparseBooleanArray(1);
                mAccessoryPermissionMap.put(accessory, uidList);
            }
            uidList.put(uid, true);
    void usbDeviceRemoved(@NonNull UsbDevice device) {
        synchronized (mPermissionsByUser) {
            for (int i = 0; i < mPermissionsByUser.size(); i++) {
                // clear temporary permissions for the device
                mPermissionsByUser.valueAt(i).removeDevicePermissions(device);
            }
        }

    /**
     * Returns true if package with uid has permission to access the device.
     *
     * @param device to check permission for
     * @param uid to check permission for
     * @return {@code true} if package with uid has permission
     */
    boolean hasPermission(@NonNull UsbDevice device, int uid) {
        synchronized (mLock) {
            if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
                return true;
            }
            SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
            if (uidList == null) {
                return false;
            }
            return uidList.get(uid);
        }
    }
        Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        intent.putExtra(UsbManager.EXTRA_DEVICE, device);

    /**
     * Returns true if caller has permission to access the accessory.
     *
     * @param accessory to check permission for
     * @param uid to check permission for
     * @return {@code true} if caller has permssion
     */
    boolean hasPermission(@NonNull UsbAccessory accessory, int uid) {
        synchronized (mLock) {
            if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
                return true;
            }
            SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
            if (uidList == null) {
                return false;
            }
            return uidList.get(uid);
        if (DEBUG) {
            Slog.d(LOG_TAG, "usbDeviceRemoved, sending " + intent);
        }
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    }

    /**
     * Creates UI dialog to request permission for the given package to access the device
     * or accessory.
     * Remove temporary access permission and broadcast that a accessory was removed.
     *
     * @param device The USB device attached
     * @param accessory The USB accessory attached
     * @param canBeDefault Whether the calling pacakge can set as default handler
     * of the USB device or accessory
     * @param packageName The package name of the calling package
     * @param uid The uid of the calling package
     * @param userContext The context to start the UI dialog
     * @param pi PendingIntent for returning result
     * @param accessory The accessory that is removed
     */
    void requestPermissionDialog(@Nullable UsbDevice device,
                                 @Nullable UsbAccessory accessory,
                                 boolean canBeDefault,
                                 @NonNull String packageName,
                                 int uid,
                                 @NonNull Context userContext,
                                 @NonNull PendingIntent pi) {
        long identity = Binder.clearCallingIdentity();
        Intent intent = new Intent();
        if (device != null) {
            intent.putExtra(UsbManager.EXTRA_DEVICE, device);
        } else {
            intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
        }
        intent.putExtra(Intent.EXTRA_INTENT, pi);
        intent.putExtra(Intent.EXTRA_UID, uid);
        intent.putExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, canBeDefault);
        intent.putExtra(UsbManager.EXTRA_PACKAGE, packageName);
        intent.setClassName("com.android.systemui",
                "com.android.systemui.usb.UsbPermissionActivity");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        try {
            userContext.startActivityAsUser(intent, mUser);
        } catch (ActivityNotFoundException e) {
            Slog.e(LOG_TAG, "unable to start UsbPermissionActivity");
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    void usbAccessoryRemoved(@NonNull UsbAccessory accessory) {
        synchronized (mPermissionsByUser) {
            for (int i = 0; i < mPermissionsByUser.size(); i++) {
                // clear temporary permissions for the accessory
                mPermissionsByUser.valueAt(i).removeAccessoryPermissions(accessory);
            }

    void dump(@NonNull DualDumpOutputStream dump) {
        synchronized (mLock) {
            for (String deviceName : mDevicePermissionMap.keySet()) {
                long devicePermissionToken = dump.start("device_permissions",
                        UsbUserSettingsManagerProto.DEVICE_PERMISSIONS);

                dump.write("device_name", UsbSettingsDevicePermissionProto.DEVICE_NAME, deviceName);

                SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
                int count = uidList.size();
                for (int i = 0; i < count; i++) {
                    dump.write("uids", UsbSettingsDevicePermissionProto.UIDS, uidList.keyAt(i));
        }

                dump.end(devicePermissionToken);
            }

            for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
                long accessoryPermissionToken = dump.start("accessory_permissions",
                        UsbUserSettingsManagerProto.ACCESSORY_PERMISSIONS);

                dump.write("accessory_description",
                        UsbSettingsAccessoryPermissionProto.ACCESSORY_DESCRIPTION,
                        accessory.getDescription());

                SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
                int count = uidList.size();
                for (int i = 0; i < count; i++) {
                    dump.write("uids", UsbSettingsAccessoryPermissionProto.UIDS, uidList.keyAt(i));
        Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    }

                dump.end(accessoryPermissionToken);
            }
        }
    }
}
+7 −6
Original line number Diff line number Diff line
@@ -783,7 +783,7 @@ class UsbProfileGroupSettingsManager {
            return;
        }

        mSettingsManager.getSettingsForUser(UserHandle.getUserId(appInfo.uid))
        mSettingsManager.mUsbService.getPermissionsForUser(UserHandle.getUserId(appInfo.uid))
                .grantDevicePermission(device, appInfo.uid);

        Intent activityIntent = new Intent(intent);
@@ -844,14 +844,15 @@ class UsbProfileGroupSettingsManager {
        }

        if (defaultActivity != null) {
            UsbUserSettingsManager defaultRIUserSettings = mSettingsManager.getSettingsForUser(
            UsbUserPermissionManager defaultRIUserPermissions =
                    mSettingsManager.mUsbService.getPermissionsForUser(
                            UserHandle.getUserId(defaultActivity.applicationInfo.uid));
            // grant permission for default activity
            if (device != null) {
                defaultRIUserSettings.
                        grantDevicePermission(device, defaultActivity.applicationInfo.uid);
                defaultRIUserPermissions
                        .grantDevicePermission(device, defaultActivity.applicationInfo.uid);
            } else if (accessory != null) {
                defaultRIUserSettings.grantAccessoryPermission(accessory,
                defaultRIUserPermissions.grantAccessoryPermission(accessory,
                        defaultActivity.applicationInfo.uid);
            }

+8 −7
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ import com.android.internal.util.ArrayUtils;
class UsbSerialReader extends IUsbSerialReader.Stub {
    private final @Nullable String mSerialNumber;
    private final @NonNull Context mContext;
    private final @NonNull UsbSettingsManager mSettingsManager;
    private final @NonNull UsbPermissionManager mPermissionManager;

    private Object mDevice;

@@ -51,10 +51,10 @@ class UsbSerialReader extends IUsbSerialReader.Stub {
     * @param settingsManager The USB settings manager
     * @param serialNumber The serial number that might be read
     */
    UsbSerialReader(@NonNull Context context, @NonNull UsbSettingsManager settingsManager,
    UsbSerialReader(@NonNull Context context, @NonNull UsbPermissionManager permissionManager,
            @Nullable String serialNumber) {
        mContext = context;
        mSettingsManager = settingsManager;
        mPermissionManager = permissionManager;
        mSerialNumber = serialNumber;
    }

@@ -89,13 +89,14 @@ class UsbSerialReader extends IUsbSerialReader.Stub {
                if (packageTargetSdkVersion >= Build.VERSION_CODES.Q) {
                    if (mContext.checkPermission(android.Manifest.permission.MANAGE_USB, pid, uid)
                            == PackageManager.PERMISSION_DENIED) {
                        UsbUserSettingsManager settings = mSettingsManager.getSettingsForUser(
                                UserHandle.getUserId(uid));

                        int userId = UserHandle.getUserId(uid);
                        if (mDevice instanceof UsbDevice) {
                            settings.checkPermission((UsbDevice) mDevice, packageName, uid);
                            mPermissionManager.getPermissionsForUser(userId)
                                    .checkPermission((UsbDevice) mDevice, packageName, uid);
                        } else {
                            settings.checkPermission((UsbAccessory) mDevice, uid);
                            mPermissionManager.getPermissionsForUser(userId)
                                    .checkPermission((UsbAccessory) mDevice, uid);
                        }
                    }
                }
Loading