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

Commit e19dc30b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Check camera permissions for any devices using the VIDEO class"

parents d56c5cf6 c8ed5ecd
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ interface IUsbManager
    /* Returns a file descriptor for communicating with the USB device.
     * The native fd can be passed to usb_device_new() in libusbhost.
     */
    ParcelFileDescriptor openDevice(String deviceName);
    ParcelFileDescriptor openDevice(String deviceName, String packageName);

    /* Returns the currently attached USB accessory */
    UsbAccessory getCurrentAccessory();
@@ -55,7 +55,7 @@ interface IUsbManager
    void setAccessoryPackage(in UsbAccessory accessory, String packageName, int userId);

    /* Returns true if the caller has permission to access the device. */
    boolean hasDevicePermission(in UsbDevice device);
    boolean hasDevicePermission(in UsbDevice device, String packageName);

    /* Returns true if the caller has permission to access the accessory. */
    boolean hasAccessoryPermission(in UsbAccessory accessory);
+9 −2
Original line number Diff line number Diff line
@@ -344,7 +344,7 @@ public class UsbManager {
    public UsbDeviceConnection openDevice(UsbDevice device) {
        try {
            String deviceName = device.getDeviceName();
            ParcelFileDescriptor pfd = mService.openDevice(deviceName);
            ParcelFileDescriptor pfd = mService.openDevice(deviceName, mContext.getPackageName());
            if (pfd != null) {
                UsbDeviceConnection connection = new UsbDeviceConnection(device);
                boolean result = connection.open(deviceName, pfd, mContext);
@@ -400,6 +400,9 @@ public class UsbManager {
     * Permission might have been granted temporarily via
     * {@link #requestPermission(UsbDevice, PendingIntent)} or
     * by the user choosing the caller as the default application for the device.
     * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that
     * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they
     * have additionally the {@link android.Manifest.permission#CAMERA} permission.
     *
     * @param device to check permissions for
     * @return true if caller has permission
@@ -409,7 +412,7 @@ public class UsbManager {
            return false;
        }
        try {
            return mService.hasDevicePermission(device);
            return mService.hasDevicePermission(device, mContext.getPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -450,6 +453,10 @@ public class UsbManager {
     * permission was granted by the user
     * </ul>
     *
     * Permission for USB devices of class {@link UsbConstants#USB_CLASS_VIDEO} for clients that
     * target SDK {@link android.os.Build.VERSION_CODES#P} and above can be granted only if they
     * have additionally the {@link android.Manifest.permission#CAMERA} permission.
     *
     * @param device to request permissions for
     * @param pi PendingIntent for returning result
     */
+3 −2
Original line number Diff line number Diff line
@@ -323,7 +323,8 @@ public class UsbHostManager {
    }

    /* Opens the specified USB device */
    public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) {
    public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings,
            String packageName, int uid) {
        synchronized (mLock) {
            if (isBlackListed(deviceName)) {
                throw new SecurityException("USB device is on a restricted bus");
@@ -334,7 +335,7 @@ public class UsbHostManager {
                throw new IllegalArgumentException(
                        "device " + deviceName + " does not exist or is restricted");
            }
            settings.checkPermission(device);
            settings.checkPermission(device, packageName, uid);
            return nativeOpenDevice(deviceName);
        }
    }
+8 −5
Original line number Diff line number Diff line
@@ -232,7 +232,7 @@ public class UsbService extends IUsbManager.Stub {

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

        if (mHostManager != null) {
@@ -242,7 +242,8 @@ public class UsbService extends IUsbManager.Stub {
                    boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();

                    if (isCurrentUser) {
                        fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt));
                        fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt),
                                packageName, Binder.getCallingUid());
                    } else {
                        Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt +
                               " as user is not active.");
@@ -308,9 +309,10 @@ public class UsbService extends IUsbManager.Stub {
    }

    @Override
    public boolean hasDevicePermission(UsbDevice device) {
    public boolean hasDevicePermission(UsbDevice device, String packageName) {
        final int userId = UserHandle.getCallingUserId();
        return getSettingsForUser(userId).hasPermission(device);
        return getSettingsForUser(userId).hasPermission(device, packageName,
                Binder.getCallingUid());
    }

    @Override
@@ -322,7 +324,8 @@ public class UsbService extends IUsbManager.Stub {
    @Override
    public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
        final int userId = UserHandle.getCallingUserId();
        getSettingsForUser(userId).requestPermission(device, packageName, pi);
        getSettingsForUser(userId).requestPermission(device, packageName, pi,
                Binder.getCallingUid());
    }

    @Override
+80 −6
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbManager;
import android.os.Binder;
import android.os.Process;
@@ -95,10 +97,70 @@ class UsbUserSettingsManager {
        }
    }

    /**
     * Check whether a particular device or any of its interfaces
     * is of class VIDEO.
     *
     * @param device The device that needs to get scanned
     * @return True in case a VIDEO device or interface is present,
     *         False otherwise.
     */
    private boolean isCameraDevicePresent(UsbDevice device) {
        if (device.getDeviceClass() == UsbConstants.USB_CLASS_VIDEO) {
            return true;
        }

        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface iface = device.getInterface(i);
            if (iface.getInterfaceClass() == UsbConstants.USB_CLASS_VIDEO) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check for camera permission of the calling process.
     *
     * @param packageName Package name of the caller.
     * @param uid Linux uid of the calling process.
     *
     * @return True in case camera permission is available, False otherwise.
     */
    private boolean isCameraPermissionGranted(String packageName, int uid) {
        int targetSdkVersion = android.os.Build.VERSION_CODES.P;
        try {
            ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
            // compare uid with packageName to foil apps pretending to be someone else
            if (aInfo.uid != uid) {
                Slog.i(TAG, "Package " + packageName + " does not match caller's uid " + uid);
                return false;
            }
            targetSdkVersion = aInfo.targetSdkVersion;
        } catch (PackageManager.NameNotFoundException e) {
            Slog.i(TAG, "Package not found, likely due to invalid package name!");
            return false;
        }

        if (targetSdkVersion >= android.os.Build.VERSION_CODES.P) {
            int allowed = mUserContext.checkCallingPermission(android.Manifest.permission.CAMERA);
            if (android.content.pm.PackageManager.PERMISSION_DENIED == allowed) {
                Slog.i(TAG, "Camera permission required for USB video class devices");
                return false;
            }
        }

        return true;
    }

    public boolean hasPermission(UsbDevice device) {
    public boolean hasPermission(UsbDevice device, String packageName, int uid) {
        synchronized (mLock) {
            int uid = Binder.getCallingUid();
            if (isCameraDevicePresent(device)) {
                if (!isCameraPermissionGranted(packageName, uid)) {
                    return false;
                }
            }
            if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
                return true;
            }
@@ -124,8 +186,8 @@ class UsbUserSettingsManager {
        }
    }

    public void checkPermission(UsbDevice device) {
        if (!hasPermission(device)) {
    public void checkPermission(UsbDevice device, String packageName, int uid) {
        if (!hasPermission(device, packageName, uid)) {
            throw new SecurityException("User has not given permission to device " + device);
        }
    }
@@ -166,11 +228,11 @@ class UsbUserSettingsManager {
        }
    }

    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi) {
    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int uid) {
      Intent intent = new Intent();

        // respond immediately if permission has already been granted
      if (hasPermission(device)) {
      if (hasPermission(device, packageName, uid)) {
            intent.putExtra(UsbManager.EXTRA_DEVICE, device);
            intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
            try {
@@ -180,6 +242,18 @@ class UsbUserSettingsManager {
            }
            return;
        }
        if (isCameraDevicePresent(device)) {
            if (!isCameraPermissionGranted(packageName, uid)) {
                intent.putExtra(UsbManager.EXTRA_DEVICE, device);
                intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
                try {
                    pi.send(mUserContext, 0, intent);
                } catch (PendingIntent.CanceledException e) {
                    if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
                }
                return;
            }
        }

        // start UsbPermissionActivity so user can choose an activity
        intent.putExtra(UsbManager.EXTRA_DEVICE, device);