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

Commit 031cee90 authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Allow connection from secondary profiles

... and send device-attached broadcasts to all apps instead of just the
current user.

Note: Usb*Manager.open* needs to be called with the identity of the
app.

Bug: 29233186
Change-Id: I225c47bdb409eee1c8fe0499d600fded470aa101
parent c3e8cbe3
Loading
Loading
Loading
Loading
+15 −12
Original line number Diff line number Diff line
@@ -137,7 +137,7 @@ public class UsbDeviceManager {
    private final Context mContext;
    private final ContentResolver mContentResolver;
    @GuardedBy("mLock")
    private UsbSettingsManager mCurrentSettings;
    private UsbUserSettingsManager mCurrentUserSettings;
    private NotificationManager mNotificationManager;
    private final boolean mHasUsbAccessory;
    private boolean mUseUsbNotification;
@@ -150,6 +150,7 @@ public class UsbDeviceManager {
    private String[] mAccessoryStrings;
    private UsbDebuggingManager mDebuggingManager;
    private final UsbAlsaManager mUsbAlsaManager;
    private final UsbSettingsManager mSettingsManager;
    private Intent mBroadcastedIntent;

    private class AdbSettingsObserver extends ContentObserver {
@@ -192,9 +193,11 @@ public class UsbDeviceManager {
        }
    };

    public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
    public UsbDeviceManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager) {
        mContext = context;
        mUsbAlsaManager = alsaManager;
        mSettingsManager = settingsManager;
        mContentResolver = context.getContentResolver();
        PackageManager pm = mContext.getPackageManager();
        mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
@@ -218,9 +221,9 @@ public class UsbDeviceManager {
                new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
    }

    private UsbSettingsManager getCurrentSettings() {
    private UsbUserSettingsManager getCurrentUserSettings() {
        synchronized (mLock) {
            return mCurrentSettings;
            return mCurrentUserSettings;
        }
    }

@@ -255,10 +258,10 @@ public class UsbDeviceManager {
        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
    }

    public void setCurrentUser(int userId, UsbSettingsManager settings) {
    public void setCurrentUser(int newCurrentUserId, UsbUserSettingsManager settings) {
        synchronized (mLock) {
            mCurrentSettings = settings;
            mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
            mCurrentUserSettings = settings;
            mHandler.obtainMessage(MSG_USER_SWITCHED, newCurrentUserId, 0).sendToTarget();
        }
    }

@@ -571,7 +574,7 @@ public class UsbDeviceManager {
                    Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
                    // defer accessoryAttached if system is not ready
                    if (mBootCompleted) {
                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
                        getCurrentUserSettings().accessoryAttached(mCurrentAccessory);
                    } // else handle in boot completed
                } else {
                    Slog.e(TAG, "nativeGetAccessoryStrings failed");
@@ -584,7 +587,7 @@ public class UsbDeviceManager {

                if (mCurrentAccessory != null) {
                    if (mBootCompleted) {
                        getCurrentSettings().accessoryDetached(mCurrentAccessory);
                        mSettingsManager.usbAccessoryRemoved(mCurrentAccessory);
                    }
                    mCurrentAccessory = null;
                    mAccessoryStrings = null;
@@ -764,7 +767,7 @@ public class UsbDeviceManager {
                case MSG_BOOT_COMPLETED:
                    mBootCompleted = true;
                    if (mCurrentAccessory != null) {
                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
                        getCurrentUserSettings().accessoryAttached(mCurrentAccessory);
                    }
                    if (mDebuggingManager != null) {
                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
@@ -947,7 +950,7 @@ public class UsbDeviceManager {
    }

    /* opens the currently attached USB accessory */
    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
    public ParcelFileDescriptor openAccessory(UsbAccessory accessory, UsbUserSettingsManager settings) {
        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
        if (currentAccessory == null) {
            throw new IllegalArgumentException("no accessory attached");
@@ -958,7 +961,7 @@ public class UsbDeviceManager {
                    + currentAccessory;
            throw new IllegalArgumentException(error);
        }
        getCurrentSettings().checkPermission(accessory);
        settings.checkPermission(accessory);
        return nativeOpenAccessory();
    }

+18 −13
Original line number Diff line number Diff line
@@ -32,8 +32,6 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;

@@ -62,18 +60,21 @@ public class UsbHostManager {
    private ArrayList<UsbEndpoint> mNewEndpoints;

    private final UsbAlsaManager mUsbAlsaManager;
    private final UsbSettingsManager mSettingsManager;

    @GuardedBy("mLock")
    private UsbSettingsManager mCurrentSettings;
    private UsbUserSettingsManager mCurrentUserSettings;

    @GuardedBy("mLock")
    private ComponentName mUsbDeviceConnectionHandler;

    public UsbHostManager(Context context, UsbAlsaManager alsaManager) {
    public UsbHostManager(Context context, UsbAlsaManager alsaManager,
            UsbSettingsManager settingsManager) {
        mContext = context;
        mHostBlacklist = context.getResources().getStringArray(
                com.android.internal.R.array.config_usbHostBlacklist);
        mUsbAlsaManager = alsaManager;
        mSettingsManager = settingsManager;
        String deviceConnectionHandler = context.getResources().getString(
                com.android.internal.R.string.config_UsbDeviceConnectionHandling_component);
        if (!TextUtils.isEmpty(deviceConnectionHandler)) {
@@ -82,15 +83,15 @@ public class UsbHostManager {
        }
    }

    public void setCurrentSettings(UsbSettingsManager settings) {
    public void setCurrentUserSettings(UsbUserSettingsManager settings) {
        synchronized (mLock) {
            mCurrentSettings = settings;
            mCurrentUserSettings = settings;
        }
    }

    private UsbSettingsManager getCurrentSettings() {
    private UsbUserSettingsManager getCurrentUserSettings() {
        synchronized (mLock) {
            return mCurrentSettings;
            return mCurrentUserSettings;
        }
    }

@@ -247,11 +248,14 @@ public class UsbHostManager {
                                new UsbConfiguration[mNewConfigurations.size()]));
                mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
                Slog.d(TAG, "Added device " + mNewDevice);

                // It is fine to call this only for the current user as all broadcasts are sent to
                // all profiles of the user and the dialogs should only show once.
                ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
                if (usbDeviceConnectionHandler == null) {
                    getCurrentSettings().deviceAttached(mNewDevice);
                    getCurrentUserSettings().deviceAttached(mNewDevice);
                } else {
                    getCurrentSettings().deviceAttachedForFixedHandler(mNewDevice,
                    getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
                            usbDeviceConnectionHandler);
                }
                mUsbAlsaManager.usbDeviceAdded(mNewDevice);
@@ -273,7 +277,8 @@ public class UsbHostManager {
            UsbDevice device = mDevices.remove(deviceName);
            if (device != null) {
                mUsbAlsaManager.usbDeviceRemoved(device);
                getCurrentSettings().deviceDetached(device);
                mSettingsManager.usbDeviceRemoved(device);
                getCurrentUserSettings().usbDeviceRemoved(device);
            }
        }
    }
@@ -301,7 +306,7 @@ public class UsbHostManager {
    }

    /* Opens the specified USB device */
    public ParcelFileDescriptor openDevice(String deviceName) {
    public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) {
        synchronized (mLock) {
            if (isBlackListed(deviceName)) {
                throw new SecurityException("USB device is on a restricted bus");
@@ -312,7 +317,7 @@ public class UsbHostManager {
                throw new IllegalArgumentException(
                        "device " + deviceName + " does not exist or is restricted");
            }
            getCurrentSettings().checkPermission(device);
            settings.checkPermission(device);
            return nativeOpenDevice(deviceName);
        }
    }
+114 −52
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.usb;

import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -36,7 +37,6 @@ import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
@@ -75,57 +75,65 @@ public class UsbService extends IUsbManager.Stub {
                mUsbService.bootCompleted();
            }
        }

        @Override
        public void onSwitchUser(int newUserId) {
            mUsbService.onSwitchUser(newUserId);
        }

        @Override
        public void onStopUser(int userHandle) {
            mUsbService.onStopUser(userHandle);
        }
    }

    private static final String TAG = "UsbService";

    private final Context mContext;
    private final UserManager mUserManager;

    private UsbDeviceManager mDeviceManager;
    private UsbHostManager mHostManager;
    private UsbPortManager mPortManager;
    private final UsbAlsaManager mAlsaManager;

    private final Object mLock = new Object();
    private final UsbSettingsManager mSettingsManager;

    /** Map from {@link UserHandle} to {@link UsbSettingsManager} */
    /**
     * The user id of the current user. There might be several profiles (with separate user ids)
     * per user.
     */
    @GuardedBy("mLock")
    private final SparseArray<UsbSettingsManager>
            mSettingsByUser = new SparseArray<UsbSettingsManager>();
    private @UserIdInt int mCurrentUserId;

    private UsbSettingsManager getSettingsForUser(int userId) {
        synchronized (mLock) {
            UsbSettingsManager settings = mSettingsByUser.get(userId);
            if (settings == null) {
                settings = new UsbSettingsManager(mContext, new UserHandle(userId));
                mSettingsByUser.put(userId, settings);
            }
            return settings;
        }
    private final Object mLock = new Object();

    private UsbUserSettingsManager getSettingsForUser(@UserIdInt int userIdInt) {
        return mSettingsManager.getSettingsForUser(userIdInt);
    }

    public UsbService(Context context) {
        mContext = context;

        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mSettingsManager = new UsbSettingsManager(context);
        mAlsaManager = new UsbAlsaManager(context);

        final PackageManager pm = mContext.getPackageManager();
        if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
            mHostManager = new UsbHostManager(context, mAlsaManager);
            mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager);
        }
        if (new File("/sys/class/android_usb").exists()) {
            mDeviceManager = new UsbDeviceManager(context, mAlsaManager);
            mDeviceManager = new UsbDeviceManager(context, mAlsaManager, mSettingsManager);
        }
        if (mHostManager != null || mDeviceManager != null) {
            mPortManager = new UsbPortManager(context);
        }

        setCurrentUser(UserHandle.USER_SYSTEM);
        onSwitchUser(UserHandle.USER_SYSTEM);

        final IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        filter.addAction(Intent.ACTION_USER_STOPPED);
        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
        mContext.registerReceiver(mReceiver, filter, null, null);
    }
@@ -133,15 +141,8 @@ public class UsbService extends IUsbManager.Stub {
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
            final String action = intent.getAction();
            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                setCurrentUser(userId);
            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                synchronized (mLock) {
                    mSettingsByUser.remove(userId);
                }
            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
                    .equals(action)) {
                if (mDeviceManager != null) {
                    mDeviceManager.updateUserRestrictions();
@@ -150,16 +151,37 @@ public class UsbService extends IUsbManager.Stub {
        }
    };

    private void setCurrentUser(int userId) {
        final UsbSettingsManager userSettings = getSettingsForUser(userId);
    /**
     * Set new {@link #mCurrentUserId} and propagate it to other modules.
     *
     * @param newUserId The user id of the new current user.
     */
    private void onSwitchUser(@UserIdInt int newUserId) {
        synchronized (mLock) {
            mCurrentUserId = newUserId;

            // The following two modules need to know about the current user. If they need to
            // distinguish by profile of the user, the id has to be passed in the call to the
            // module.
            UsbUserSettingsManager userSettings = getSettingsForUser(newUserId);
            if (mHostManager != null) {
            mHostManager.setCurrentSettings(userSettings);
                mHostManager.setCurrentUserSettings(userSettings);
            }
            if (mDeviceManager != null) {
            mDeviceManager.setCurrentUser(userId, userSettings);
                mDeviceManager.setCurrentUser(newUserId, userSettings);
            }
        }
    }

    /**
     * Execute operations when a user is stopped.
     *
     * @param stoppedUserId The id of the used that is stopped
     */
    private void onStopUser(@UserIdInt int stoppedUserId) {
        mSettingsManager.remove(stoppedUserId);
    }

    public void systemReady() {
        mAlsaManager.systemReady();

@@ -188,16 +210,47 @@ public class UsbService extends IUsbManager.Stub {
        }
    }

    /**
     * Check if the calling user is in the same profile group as the {@link #mCurrentUserId
     * current user}.
     *
     * @return Iff the caller is in the current user's profile group
     */
    private boolean isCallerInCurrentUserProfileGroupLocked() {
        int userIdInt = UserHandle.getCallingUserId();

        long ident = clearCallingIdentity();
        try {
            return mUserManager.isSameProfileGroup(userIdInt, mCurrentUserId);
        } finally {
            restoreCallingIdentity(ident);
        }
    }

    /* Opens the specified USB device (host mode) */
    @Override
    public ParcelFileDescriptor openDevice(String deviceName) {
        ParcelFileDescriptor fd = null;

        if (mHostManager != null) {
            return mHostManager.openDevice(deviceName);
            synchronized (mLock) {
                if (deviceName != null) {
                    int userIdInt = UserHandle.getCallingUserId();
                    boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();

                    if (isCurrentUser) {
                        fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt));
                    } else {
            return null;
                        Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt +
                               " as user is not active.");
                    }
                }
            }
        }

        return fd;
    }

    /* returns the currently attached USB accessory (device mode) */
    @Override
    public UsbAccessory getCurrentAccessory() {
@@ -212,12 +265,23 @@ public class UsbService extends IUsbManager.Stub {
    @Override
    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
        if (mDeviceManager != null) {
            return mDeviceManager.openAccessory(accessory);
            int userIdInt = UserHandle.getCallingUserId();

            synchronized (mLock) {
                boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();

                if (isCurrentUser) {
                    return mDeviceManager.openAccessory(accessory, getSettingsForUser(userIdInt));
                } else {
            return null;
                    Slog.w(TAG, "Cannot open " + accessory + " for user " + userIdInt +
                            " as user is not active.");
                }
            }
        }

        return null;
    }

    @Override
    public void setDevicePackage(UsbDevice device, String packageName, int userId) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
@@ -388,9 +452,16 @@ public class UsbService extends IUsbManager.Stub {
    @Override
    public void setUsbDeviceConnectionHandler(ComponentName usbDeviceConnectionHandler) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
        synchronized (mLock) {
            if (mCurrentUserId == UserHandle.getCallingUserId()) {
                if (mHostManager != null) {
                    mHostManager.setUsbDeviceConnectionHandler(usbDeviceConnectionHandler);
                }
            } else {
                throw new IllegalArgumentException("Only the current user can register a usb " +
                        "connection handler");
            }
        }
    }

    @Override
@@ -414,16 +485,7 @@ public class UsbService extends IUsbManager.Stub {
                }
                mAlsaManager.dump(pw);

                synchronized (mLock) {
                    for (int i = 0; i < mSettingsByUser.size(); i++) {
                        final int userId = mSettingsByUser.keyAt(i);
                        final UsbSettingsManager settings = mSettingsByUser.valueAt(i);
                        pw.println("Settings for user " + userId + ":");
                        pw.increaseIndent();
                        settings.dump(pw);
                        pw.decreaseIndent();
                    }
                }
                mSettingsManager.dump(pw);
            } else if (args.length == 4 && "set-port-roles".equals(args[0])) {
                final String portId = args[1];
                final int powerRole;
+84 −1223

File changed.

Preview size limit exceeded, changes collapsed.

+1288 −0

File added.

Preview size limit exceeded, changes collapsed.