Merge "Disallow usb access to camera and mic devices if global privacy toggle is active" into sc-dev am: c20398b8d1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15462072

Change-Id: I6c1c7f1305fc9c15cbed757b229bafbfb3a929ba
This commit is contained in:
Philip Junker
2021-08-13 14:00:57 +00:00
committed by Automerger Merge Worker

View File

@@ -25,12 +25,12 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.hardware.SensorPrivacyManager.Sensors;
import android.hardware.SensorPrivacyManagerInternal;
import android.hardware.usb.AccessoryFilter; import android.hardware.usb.AccessoryFilter;
import android.hardware.usb.DeviceFilter; import android.hardware.usb.DeviceFilter;
import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Binder; import android.os.Binder;
@@ -52,9 +52,9 @@ import android.util.TypedXmlSerializer;
import android.util.Xml; import android.util.Xml;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils; import com.android.internal.util.XmlUtils;
import com.android.internal.util.dump.DualDumpOutputStream; import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.LocalServices;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
@@ -64,7 +64,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
/** /**
* UsbUserPermissionManager manages usb device or accessory access permissions. * UsbUserPermissionManager manages usb device or accessory access permissions.
@@ -110,19 +109,20 @@ class UsbUserPermissionManager {
*/ */
@GuardedBy("mLock") @GuardedBy("mLock")
private boolean mIsCopyPermissionsScheduled; private boolean mIsCopyPermissionsScheduled;
private final SensorPrivacyManagerInternal mSensorPrivacyMgrInternal;
UsbUserPermissionManager(@NonNull Context context, UsbUserPermissionManager(@NonNull Context context,
@NonNull UsbUserSettingsManager usbUserSettingsManager) { @NonNull UsbUserSettingsManager usbUserSettingsManager) {
mContext = context; mContext = context;
mUser = context.getUser(); mUser = context.getUser();
mUsbUserSettingsManager = usbUserSettingsManager; mUsbUserSettingsManager = usbUserSettingsManager;
mSensorPrivacyMgrInternal = LocalServices.getService(SensorPrivacyManagerInternal.class);
mDisablePermissionDialogs = context.getResources().getBoolean( mDisablePermissionDialogs = context.getResources().getBoolean(
com.android.internal.R.bool.config_disableUsbPermissionDialogs); com.android.internal.R.bool.config_disableUsbPermissionDialogs);
mPermissionsFile = new AtomicFile(new File( mPermissionsFile = new AtomicFile(new File(
Environment.getUserSystemDirectory(mUser.getIdentifier()), Environment.getUserSystemDirectory(mUser.getIdentifier()),
"usb_permissions.xml"), "usb-permissions"); "usb_permissions.xml"), "usb-permissions");
synchronized (mLock) { synchronized (mLock) {
readPermissionsLocked(); readPermissionsLocked();
} }
@@ -195,11 +195,27 @@ class UsbUserPermissionManager {
*/ */
boolean hasPermission(@NonNull UsbDevice device, @NonNull String packageName, int pid, boolean hasPermission(@NonNull UsbDevice device, @NonNull String packageName, int pid,
int uid) { int uid) {
if (isCameraDevicePresent(device)) { if (device.getHasVideoCapture()) {
if (!isCameraPermissionGranted(packageName, pid, uid)) { boolean isCameraPrivacyEnabled = mSensorPrivacyMgrInternal.isSensorPrivacyEnabled(
UserHandle.getUserId(uid), Sensors.CAMERA);
if (DEBUG) {
Slog.d(TAG, "isCameraPrivacyEnabled: " + isCameraPrivacyEnabled);
}
if (isCameraPrivacyEnabled || !isCameraPermissionGranted(packageName, pid, uid)) {
return false; return false;
} }
} }
// Only check for microphone privacy and not RECORD_AUDIO permission, because access to usb
// camera device with audio recording capabilities may still be granted with a warning
if (device.getHasAudioCapture() && mSensorPrivacyMgrInternal.isSensorPrivacyEnabled(
UserHandle.getUserId(uid), Sensors.MICROPHONE)) {
if (DEBUG) {
Slog.d(TAG,
"Access to device with audio recording capabilities denied because "
+ "microphone privacy is enabled.");
}
return false;
}
synchronized (mLock) { synchronized (mLock) {
if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) {
return true; return true;
@@ -698,7 +714,10 @@ class UsbUserPermissionManager {
} }
return; return;
} }
if (isCameraDevicePresent(device)) { // If the app doesn't have camera permission do not request permission to the USB device.
// Note that if the USB camera also has a microphone, a warning will be shown to the user if
// the app doesn't have RECORD_AUDIO permission.
if (device.getHasVideoCapture()) {
if (!isCameraPermissionGranted(packageName, pid, uid)) { if (!isCameraPermissionGranted(packageName, pid, uid)) {
intent.putExtra(UsbManager.EXTRA_DEVICE, device); intent.putExtra(UsbManager.EXTRA_DEVICE, device);
intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false); intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
@@ -733,27 +752,4 @@ class UsbUserPermissionManager {
requestPermissionDialog(null, accessory, requestPermissionDialog(null, accessory,
mUsbUserSettingsManager.canBeDefault(accessory, packageName), packageName, pi, uid); mUsbUserSettingsManager.canBeDefault(accessory, packageName), packageName, pi, uid);
} }
/**
* 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;
}
} }