Usb launch preference denial able to be remembered
When a device is connected the user might be prompted with
a dialog to launch an application. This change creates the
api that the system UI will use to give the user a
"deny [for this device+package] and remember" option.
Test: Manual:
Edit usb_device_manager.xml and observe correct behavior
Call new methods and observe correct changes in xml file
Bug: 136496922
Change-Id: I20e377d601ec11b8d42c79e4c726b9a4cb68c8b0
This commit is contained in:
@@ -55,6 +55,18 @@ interface IUsbManager
|
||||
*/
|
||||
void setAccessoryPackage(in UsbAccessory accessory, String packageName, int userId);
|
||||
|
||||
/* Adds packages to the set of "denied and don't ask again" launch preferences for a device */
|
||||
void addDevicePackagesToPreferenceDenied(in UsbDevice device, in String[] packageNames, in UserHandle user);
|
||||
|
||||
/* Adds packages to the set of "denied and don't ask again" launch preferences for an accessory */
|
||||
void addAccessoryPackagesToPreferenceDenied(in UsbAccessory accessory, in String[] packageNames, in UserHandle user);
|
||||
|
||||
/* Removes packages from the set of "denied and don't ask again" launch preferences for a device */
|
||||
void removeDevicePackagesFromPreferenceDenied(in UsbDevice device, in String[] packageNames, in UserHandle user);
|
||||
|
||||
/* Removes packages from the set of "denied and don't ask again" launch preferences for an accessory */
|
||||
void removeAccessoryPackagesFromPreferenceDenied(in UsbAccessory device, in String[] packageNames, in UserHandle user);
|
||||
|
||||
/* Sets the persistent permission granted state for USB device
|
||||
*/
|
||||
void setDevicePersistentPermission(in UsbDevice device, int uid, in UserHandle user, boolean shouldBeGranted);
|
||||
|
||||
@@ -46,6 +46,8 @@ import android.service.usb.UsbProfileGroupSettingsManagerProto;
|
||||
import android.service.usb.UsbSettingsAccessoryPreferenceProto;
|
||||
import android.service.usb.UsbSettingsDevicePreferenceProto;
|
||||
import android.service.usb.UserPackageProto;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
@@ -70,6 +72,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ProtocolException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -102,10 +105,20 @@ class UsbProfileGroupSettingsManager {
|
||||
@GuardedBy("mLock")
|
||||
private final HashMap<DeviceFilter, UserPackage> mDevicePreferenceMap = new HashMap<>();
|
||||
|
||||
/** Maps DeviceFilter to set of UserPackages not to ask for launch preference anymore */
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayMap<DeviceFilter, ArraySet<UserPackage>> mDevicePreferenceDeniedMap =
|
||||
new ArrayMap<>();
|
||||
|
||||
/** Maps AccessoryFilter to user preferred application package */
|
||||
@GuardedBy("mLock")
|
||||
private final HashMap<AccessoryFilter, UserPackage> mAccessoryPreferenceMap = new HashMap<>();
|
||||
|
||||
/** Maps AccessoryFilter to set of UserPackages not to ask for launch preference anymore */
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayMap<AccessoryFilter, ArraySet<UserPackage>> mAccessoryPreferenceDeniedMap =
|
||||
new ArrayMap<>();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
/**
|
||||
@@ -248,11 +261,11 @@ class UsbProfileGroupSettingsManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all defaults for a user.
|
||||
* Remove all defaults and denied packages for a user.
|
||||
*
|
||||
* @param userToRemove The user the defaults belong to.
|
||||
* @param userToRemove The user
|
||||
*/
|
||||
void removeAllDefaultsForUser(@NonNull UserHandle userToRemove) {
|
||||
void removeUser(@NonNull UserHandle userToRemove) {
|
||||
synchronized (mLock) {
|
||||
boolean needToPersist = false;
|
||||
Iterator<Map.Entry<DeviceFilter, UserPackage>> devicePreferenceIt = mDevicePreferenceMap
|
||||
@@ -277,6 +290,28 @@ class UsbProfileGroupSettingsManager {
|
||||
}
|
||||
}
|
||||
|
||||
int numEntries = mDevicePreferenceDeniedMap.size();
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.valueAt(i);
|
||||
for (int j = userPackages.size() - 1; j >= 0; j--) {
|
||||
if (userPackages.valueAt(j).user.equals(userToRemove)) {
|
||||
userPackages.removeAt(j);
|
||||
needToPersist = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numEntries = mAccessoryPreferenceDeniedMap.size();
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.valueAt(i);
|
||||
for (int j = userPackages.size() - 1; j >= 0; j--) {
|
||||
if (userPackages.valueAt(j).user.equals(userToRemove)) {
|
||||
userPackages.removeAt(j);
|
||||
needToPersist = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needToPersist) {
|
||||
scheduleWriteSettingsLocked();
|
||||
}
|
||||
@@ -284,7 +319,7 @@ class UsbProfileGroupSettingsManager {
|
||||
}
|
||||
|
||||
private void readPreference(XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
throws IOException, XmlPullParserException {
|
||||
String packageName = null;
|
||||
|
||||
// If not set, assume it to be the parent profile
|
||||
@@ -317,6 +352,67 @@ class UsbProfileGroupSettingsManager {
|
||||
XmlUtils.nextElement(parser);
|
||||
}
|
||||
|
||||
private void readPreferenceDeniedList(@NonNull XmlPullParser parser)
|
||||
throws IOException, XmlPullParserException {
|
||||
int outerDepth = parser.getDepth();
|
||||
if (!XmlUtils.nextElementWithin(parser, outerDepth)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ("usb-device".equals(parser.getName())) {
|
||||
DeviceFilter filter = DeviceFilter.read(parser);
|
||||
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
|
||||
if ("user-package".equals(parser.getName())) {
|
||||
try {
|
||||
int userId = XmlUtils.readIntAttribute(parser, "user");
|
||||
|
||||
String packageName = XmlUtils.readStringAttribute(parser, "package");
|
||||
if (packageName == null) {
|
||||
Slog.e(TAG, "Unable to parse package name");
|
||||
}
|
||||
|
||||
ArraySet<UserPackage> set = mDevicePreferenceDeniedMap.get(filter);
|
||||
if (set == null) {
|
||||
set = new ArraySet<>();
|
||||
mDevicePreferenceDeniedMap.put(filter, set);
|
||||
}
|
||||
set.add(new UserPackage(packageName, UserHandle.of(userId)));
|
||||
} catch (ProtocolException e) {
|
||||
Slog.e(TAG, "Unable to parse user id", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ("usb-accessory".equals(parser.getName())) {
|
||||
AccessoryFilter filter = AccessoryFilter.read(parser);
|
||||
|
||||
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
|
||||
if ("user-package".equals(parser.getName())) {
|
||||
try {
|
||||
int userId = XmlUtils.readIntAttribute(parser, "user");
|
||||
|
||||
String packageName = XmlUtils.readStringAttribute(parser, "package");
|
||||
if (packageName == null) {
|
||||
Slog.e(TAG, "Unable to parse package name");
|
||||
}
|
||||
|
||||
ArraySet<UserPackage> set = mAccessoryPreferenceDeniedMap.get(filter);
|
||||
if (set == null) {
|
||||
set = new ArraySet<>();
|
||||
mAccessoryPreferenceDeniedMap.put(filter, set);
|
||||
}
|
||||
set.add(new UserPackage(packageName, UserHandle.of(userId)));
|
||||
} catch (ProtocolException e) {
|
||||
Slog.e(TAG, "Unable to parse user id", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (parser.getDepth() > outerDepth) {
|
||||
parser.nextTag(); // ignore unknown tags
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade any single-user settings from {@link #sSingleUserSettingsFile}.
|
||||
* Should only be called by owner.
|
||||
@@ -373,6 +469,8 @@ class UsbProfileGroupSettingsManager {
|
||||
String tagName = parser.getName();
|
||||
if ("preference".equals(tagName)) {
|
||||
readPreference(parser);
|
||||
} else if ("preference-denied-list".equals(tagName)) {
|
||||
readPreferenceDeniedList(parser);
|
||||
} else {
|
||||
XmlUtils.nextElement(parser);
|
||||
}
|
||||
@@ -436,6 +534,46 @@ class UsbProfileGroupSettingsManager {
|
||||
serializer.endTag(null, "preference");
|
||||
}
|
||||
|
||||
int numEntries = mDevicePreferenceDeniedMap.size();
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
DeviceFilter filter = mDevicePreferenceDeniedMap.keyAt(i);
|
||||
ArraySet<UserPackage> userPackageSet = mDevicePreferenceDeniedMap
|
||||
.valueAt(i);
|
||||
serializer.startTag(null, "preference-denied-list");
|
||||
filter.write(serializer);
|
||||
|
||||
int numUserPackages = userPackageSet.size();
|
||||
for (int j = 0; j < numUserPackages; j++) {
|
||||
UserPackage userPackage = userPackageSet.valueAt(j);
|
||||
serializer.startTag(null, "user-package");
|
||||
serializer.attribute(null, "user",
|
||||
String.valueOf(getSerial(userPackage.user)));
|
||||
serializer.attribute(null, "package", userPackage.packageName);
|
||||
serializer.endTag(null, "user-package");
|
||||
}
|
||||
serializer.endTag(null, "preference-denied-list");
|
||||
}
|
||||
|
||||
numEntries = mAccessoryPreferenceDeniedMap.size();
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
AccessoryFilter filter = mAccessoryPreferenceDeniedMap.keyAt(i);
|
||||
ArraySet<UserPackage> userPackageSet =
|
||||
mAccessoryPreferenceDeniedMap.valueAt(i);
|
||||
serializer.startTag(null, "preference-denied-list");
|
||||
filter.write(serializer);
|
||||
|
||||
int numUserPackages = userPackageSet.size();
|
||||
for (int j = 0; j < numUserPackages; j++) {
|
||||
UserPackage userPackage = userPackageSet.valueAt(j);
|
||||
serializer.startTag(null, "user-package");
|
||||
serializer.attribute(null, "user",
|
||||
String.valueOf(getSerial(userPackage.user)));
|
||||
serializer.attribute(null, "package", userPackage.packageName);
|
||||
serializer.endTag(null, "user-package");
|
||||
}
|
||||
serializer.endTag(null, "preference-denied-list");
|
||||
}
|
||||
|
||||
serializer.endTag(null, "settings");
|
||||
serializer.endDocument();
|
||||
|
||||
@@ -834,6 +972,25 @@ class UsbProfileGroupSettingsManager {
|
||||
private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches,
|
||||
@Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device,
|
||||
@Nullable UsbAccessory accessory) {
|
||||
// Remove all matches which are on the denied list
|
||||
ArraySet deniedPackages = null;
|
||||
if (device != null) {
|
||||
deniedPackages = mDevicePreferenceDeniedMap.get(new DeviceFilter(device));
|
||||
} else if (accessory != null) {
|
||||
deniedPackages = mAccessoryPreferenceDeniedMap.get(new AccessoryFilter(accessory));
|
||||
}
|
||||
if (deniedPackages != null) {
|
||||
for (int i = matches.size() - 1; i >= 0; i--) {
|
||||
ResolveInfo match = matches.get(i);
|
||||
String packageName = match.activityInfo.packageName;
|
||||
UserHandle user = UserHandle
|
||||
.getUserHandleForUid(match.activityInfo.applicationInfo.uid);
|
||||
if (deniedPackages.contains(new UserPackage(packageName, user))) {
|
||||
matches.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't show the resolver activity if there are no choices available
|
||||
if (matches.size() == 0) {
|
||||
if (accessory != null) {
|
||||
@@ -1075,6 +1232,156 @@ class UsbProfileGroupSettingsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add package to the denied for handling a device
|
||||
*
|
||||
* @param device the device to add to the denied
|
||||
* @param packageNames the packages to not become handler
|
||||
* @param user the user
|
||||
*/
|
||||
void addDevicePackagesToDenied(@NonNull UsbDevice device, @NonNull String[] packageNames,
|
||||
@NonNull UserHandle user) {
|
||||
if (packageNames.length == 0) {
|
||||
return;
|
||||
}
|
||||
DeviceFilter filter = new DeviceFilter(device);
|
||||
|
||||
synchronized (mLock) {
|
||||
ArraySet<UserPackage> userPackages;
|
||||
if (mDevicePreferenceDeniedMap.containsKey(filter)) {
|
||||
userPackages = mDevicePreferenceDeniedMap.get(filter);
|
||||
} else {
|
||||
userPackages = new ArraySet<>();
|
||||
mDevicePreferenceDeniedMap.put(filter, userPackages);
|
||||
}
|
||||
|
||||
boolean shouldWrite = false;
|
||||
for (String packageName : packageNames) {
|
||||
UserPackage userPackage = new UserPackage(packageName, user);
|
||||
if (!userPackages.contains(userPackage)) {
|
||||
userPackages.add(userPackage);
|
||||
shouldWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldWrite) {
|
||||
scheduleWriteSettingsLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add package to the denied for handling a accessory
|
||||
*
|
||||
* @param accessory the accessory to add to the denied
|
||||
* @param packageNames the packages to not become handler
|
||||
* @param user the user
|
||||
*/
|
||||
void addAccessoryPackagesToDenied(@NonNull UsbAccessory accessory,
|
||||
@NonNull String[] packageNames, @NonNull UserHandle user) {
|
||||
if (packageNames.length == 0) {
|
||||
return;
|
||||
}
|
||||
AccessoryFilter filter = new AccessoryFilter(accessory);
|
||||
|
||||
synchronized (mLock) {
|
||||
ArraySet<UserPackage> userPackages;
|
||||
if (mAccessoryPreferenceDeniedMap.containsKey(filter)) {
|
||||
userPackages = mAccessoryPreferenceDeniedMap.get(filter);
|
||||
} else {
|
||||
userPackages = new ArraySet<>();
|
||||
mAccessoryPreferenceDeniedMap.put(filter, userPackages);
|
||||
}
|
||||
|
||||
boolean shouldWrite = false;
|
||||
for (String packageName : packageNames) {
|
||||
UserPackage userPackage = new UserPackage(packageName, user);
|
||||
if (!userPackages.contains(userPackage)) {
|
||||
userPackages.add(userPackage);
|
||||
shouldWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldWrite) {
|
||||
scheduleWriteSettingsLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove UserPackage from the denied for handling a device
|
||||
*
|
||||
* @param device the device to remove denied packages from
|
||||
* @param packageName the packages to remove
|
||||
* @param user the user
|
||||
*/
|
||||
void removeDevicePackagesFromDenied(@NonNull UsbDevice device, @NonNull String[] packageNames,
|
||||
@NonNull UserHandle user) {
|
||||
DeviceFilter filter = new DeviceFilter(device);
|
||||
|
||||
synchronized (mLock) {
|
||||
ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.get(filter);
|
||||
|
||||
if (userPackages != null) {
|
||||
boolean shouldWrite = false;
|
||||
for (String packageName : packageNames) {
|
||||
UserPackage userPackage = new UserPackage(packageName, user);
|
||||
|
||||
if (userPackages.contains(userPackage)) {
|
||||
userPackages.remove(userPackage);
|
||||
shouldWrite = true;
|
||||
|
||||
if (userPackages.size() == 0) {
|
||||
mDevicePreferenceDeniedMap.remove(filter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldWrite) {
|
||||
scheduleWriteSettingsLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove UserPackage from the denied for handling a accessory
|
||||
*
|
||||
* @param accessory the accessory to remove denied packages from
|
||||
* @param packageName the packages to remove
|
||||
* @param user the user
|
||||
*/
|
||||
void removeAccessoryPackagesFromDenied(@NonNull UsbAccessory accessory,
|
||||
@NonNull String[] packageNames, @NonNull UserHandle user) {
|
||||
AccessoryFilter filter = new AccessoryFilter(accessory);
|
||||
|
||||
synchronized (mLock) {
|
||||
ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.get(filter);
|
||||
|
||||
if (userPackages != null) {
|
||||
boolean shouldWrite = false;
|
||||
for (String packageName : packageNames) {
|
||||
UserPackage userPackage = new UserPackage(packageName, user);
|
||||
|
||||
if (userPackages.contains(userPackage)) {
|
||||
userPackages.remove(userPackage);
|
||||
shouldWrite = true;
|
||||
|
||||
if (userPackages.size() == 0) {
|
||||
mAccessoryPreferenceDeniedMap.remove(filter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldWrite) {
|
||||
scheduleWriteSettingsLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a package as default handler for a accessory.
|
||||
*
|
||||
|
||||
@@ -360,6 +360,78 @@ public class UsbService extends IUsbManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDevicePackagesToPreferenceDenied(UsbDevice device, String[] packageNames,
|
||||
UserHandle user) {
|
||||
device = Preconditions.checkNotNull(device);
|
||||
packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
|
||||
user = Preconditions.checkNotNull(user);
|
||||
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mSettingsManager.getSettingsForProfileGroup(user)
|
||||
.addDevicePackagesToDenied(device, packageNames, user);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAccessoryPackagesToPreferenceDenied(UsbAccessory accessory,
|
||||
String[] packageNames, UserHandle user) {
|
||||
accessory = Preconditions.checkNotNull(accessory);
|
||||
packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
|
||||
user = Preconditions.checkNotNull(user);
|
||||
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mSettingsManager.getSettingsForProfileGroup(user)
|
||||
.addAccessoryPackagesToDenied(accessory, packageNames, user);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDevicePackagesFromPreferenceDenied(UsbDevice device, String[] packageNames,
|
||||
UserHandle user) {
|
||||
device = Preconditions.checkNotNull(device);
|
||||
packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
|
||||
user = Preconditions.checkNotNull(user);
|
||||
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mSettingsManager.getSettingsForProfileGroup(user)
|
||||
.removeDevicePackagesFromDenied(device, packageNames, user);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAccessoryPackagesFromPreferenceDenied(UsbAccessory accessory,
|
||||
String[] packageNames, UserHandle user) {
|
||||
accessory = Preconditions.checkNotNull(accessory);
|
||||
packageNames = Preconditions.checkArrayElementsNotNull(packageNames, "packageNames");
|
||||
user = Preconditions.checkNotNull(user);
|
||||
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mSettingsManager.getSettingsForProfileGroup(user)
|
||||
.removeAccessoryPackagesFromDenied(accessory, packageNames, user);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDevicePersistentPermission(UsbDevice device, int uid, UserHandle user,
|
||||
boolean shouldBeGranted) {
|
||||
|
||||
@@ -130,7 +130,7 @@ class UsbSettingsManager {
|
||||
// it from all profile groups.
|
||||
int numProfileGroups = mSettingsByProfileGroup.size();
|
||||
for (int i = 0; i < numProfileGroups; i++) {
|
||||
mSettingsByProfileGroup.valueAt(i).removeAllDefaultsForUser(userToRemove);
|
||||
mSettingsByProfileGroup.valueAt(i).removeUser(userToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user