1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.usb; 18 19 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.app.ActivityManager; 24 import android.content.ActivityNotFoundException; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.pm.ActivityInfo; 29 import android.content.pm.ApplicationInfo; 30 import android.content.pm.PackageInfo; 31 import android.content.pm.PackageManager; 32 import android.content.pm.PackageManager.NameNotFoundException; 33 import android.content.pm.ResolveInfo; 34 import android.content.pm.UserInfo; 35 import android.content.res.XmlResourceParser; 36 import android.hardware.usb.AccessoryFilter; 37 import android.hardware.usb.DeviceFilter; 38 import android.hardware.usb.UsbAccessory; 39 import android.hardware.usb.UsbDevice; 40 import android.hardware.usb.UsbManager; 41 import android.os.AsyncTask; 42 import android.os.Environment; 43 import android.os.UserHandle; 44 import android.os.UserManager; 45 import android.service.usb.UsbProfileGroupSettingsManagerProto; 46 import android.service.usb.UsbSettingsAccessoryPreferenceProto; 47 import android.service.usb.UsbSettingsDevicePreferenceProto; 48 import android.service.usb.UserPackageProto; 49 import android.util.ArrayMap; 50 import android.util.ArraySet; 51 import android.util.AtomicFile; 52 import android.util.Log; 53 import android.util.Slog; 54 import android.util.SparseArray; 55 import android.util.SparseIntArray; 56 import android.util.TypedXmlPullParser; 57 import android.util.TypedXmlSerializer; 58 import android.util.Xml; 59 60 import com.android.internal.annotations.GuardedBy; 61 import com.android.internal.annotations.Immutable; 62 import com.android.internal.content.PackageMonitor; 63 import com.android.internal.util.FastXmlSerializer; 64 import com.android.internal.util.XmlUtils; 65 import com.android.internal.util.dump.DualDumpOutputStream; 66 67 import libcore.io.IoUtils; 68 69 import org.xmlpull.v1.XmlPullParser; 70 import org.xmlpull.v1.XmlPullParserException; 71 72 import java.io.File; 73 import java.io.FileInputStream; 74 import java.io.FileNotFoundException; 75 import java.io.FileOutputStream; 76 import java.io.IOException; 77 import java.net.ProtocolException; 78 import java.nio.charset.StandardCharsets; 79 import java.util.ArrayList; 80 import java.util.HashMap; 81 import java.util.Iterator; 82 import java.util.List; 83 import java.util.Map; 84 85 class UsbProfileGroupSettingsManager { 86 private static final String TAG = UsbProfileGroupSettingsManager.class.getSimpleName(); 87 private static final boolean DEBUG = false; 88 89 /** Legacy settings file, before multi-user */ 90 private static final File sSingleUserSettingsFile = new File( 91 "/data/system/usb_device_manager.xml"); 92 93 /** The parent user (main user of the profile group) */ 94 private final UserHandle mParentUser; 95 96 private final AtomicFile mSettingsFile; 97 private final boolean mDisablePermissionDialogs; 98 99 private final Context mContext; 100 101 private final PackageManager mPackageManager; 102 103 private final UserManager mUserManager; 104 private final @NonNull UsbSettingsManager mSettingsManager; 105 106 /** Maps DeviceFilter to user preferred application package */ 107 @GuardedBy("mLock") 108 private final HashMap<DeviceFilter, UserPackage> mDevicePreferenceMap = new HashMap<>(); 109 110 /** Maps DeviceFilter to set of UserPackages not to ask for launch preference anymore */ 111 @GuardedBy("mLock") 112 private final ArrayMap<DeviceFilter, ArraySet<UserPackage>> mDevicePreferenceDeniedMap = 113 new ArrayMap<>(); 114 115 /** Maps AccessoryFilter to user preferred application package */ 116 @GuardedBy("mLock") 117 private final HashMap<AccessoryFilter, UserPackage> mAccessoryPreferenceMap = new HashMap<>(); 118 119 /** Maps AccessoryFilter to set of UserPackages not to ask for launch preference anymore */ 120 @GuardedBy("mLock") 121 private final ArrayMap<AccessoryFilter, ArraySet<UserPackage>> mAccessoryPreferenceDeniedMap = 122 new ArrayMap<>(); 123 124 private final Object mLock = new Object(); 125 126 /** 127 * If a async task to persist the mDevicePreferenceMap and mAccessoryPreferenceMap is currently 128 * scheduled. 129 */ 130 @GuardedBy("mLock") 131 private boolean mIsWriteSettingsScheduled; 132 133 /** 134 * A package of a user. 135 */ 136 @Immutable 137 private static class UserPackage { 138 /** User */ 139 final @NonNull UserHandle user; 140 141 /** Package name */ 142 final @NonNull String packageName; 143 144 /** 145 * Create a description of a per user package. 146 * 147 * @param packageName The name of the package 148 * @param user The user 149 */ UserPackage(@onNull String packageName, @NonNull UserHandle user)150 private UserPackage(@NonNull String packageName, @NonNull UserHandle user) { 151 this.packageName = packageName; 152 this.user = user; 153 } 154 155 @Override equals(Object obj)156 public boolean equals(Object obj) { 157 if (!(obj instanceof UserPackage)) { 158 return false; 159 } else { 160 UserPackage other = (UserPackage)obj; 161 162 return user.equals(other.user) && packageName.equals(other.packageName); 163 } 164 } 165 166 @Override hashCode()167 public int hashCode() { 168 int result = user.hashCode(); 169 result = 31 * result + packageName.hashCode(); 170 return result; 171 } 172 173 @Override toString()174 public String toString() { 175 return user.getIdentifier() + "/" + packageName; 176 } 177 dump(DualDumpOutputStream dump, String idName, long id)178 public void dump(DualDumpOutputStream dump, String idName, long id) { 179 long token = dump.start(idName, id); 180 181 dump.write("user_id", UserPackageProto.USER_ID, user.getIdentifier()); 182 dump.write("package_name", UserPackageProto.PACKAGE_NAME, packageName); 183 184 dump.end(token); 185 } 186 } 187 188 private class MyPackageMonitor extends PackageMonitor { 189 @Override onPackageAdded(String packageName, int uid)190 public void onPackageAdded(String packageName, int uid) { 191 if (!mUserManager.isSameProfileGroup(mParentUser.getIdentifier(), 192 UserHandle.getUserId(uid))) { 193 return; 194 } 195 196 handlePackageAdded(new UserPackage(packageName, UserHandle.getUserHandleForUid(uid))); 197 } 198 199 @Override onPackageRemoved(String packageName, int uid)200 public void onPackageRemoved(String packageName, int uid) { 201 if (!mUserManager.isSameProfileGroup(mParentUser.getIdentifier(), 202 UserHandle.getUserId(uid))) { 203 return; 204 } 205 206 clearDefaults(packageName, UserHandle.getUserHandleForUid(uid)); 207 } 208 } 209 210 MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); 211 212 private final UsbHandlerManager mUsbHandlerManager; 213 214 private final MtpNotificationManager mMtpNotificationManager; 215 216 /** 217 * Create new settings manager for a profile group. 218 * 219 * @param context The context of the service 220 * @param user The parent profile 221 * @param settingsManager The settings manager of the service 222 * @param usbResolveActivityManager The resovle activity manager of the service 223 */ UsbProfileGroupSettingsManager(@onNull Context context, @NonNull UserHandle user, @NonNull UsbSettingsManager settingsManager, @NonNull UsbHandlerManager usbResolveActivityManager)224 UsbProfileGroupSettingsManager(@NonNull Context context, @NonNull UserHandle user, 225 @NonNull UsbSettingsManager settingsManager, 226 @NonNull UsbHandlerManager usbResolveActivityManager) { 227 if (DEBUG) Slog.v(TAG, "Creating settings for " + user); 228 229 Context parentUserContext; 230 try { 231 parentUserContext = context.createPackageContextAsUser("android", 0, user); 232 } catch (NameNotFoundException e) { 233 throw new RuntimeException("Missing android package"); 234 } 235 236 mContext = context; 237 mPackageManager = context.getPackageManager(); 238 mSettingsManager = settingsManager; 239 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 240 241 mParentUser = user; 242 mSettingsFile = new AtomicFile(new File( 243 Environment.getUserSystemDirectory(user.getIdentifier()), 244 "usb_device_manager.xml"), "usb-state"); 245 246 mDisablePermissionDialogs = context.getResources().getBoolean( 247 com.android.internal.R.bool.config_disableUsbPermissionDialogs); 248 249 synchronized (mLock) { 250 if (UserHandle.SYSTEM.equals(user)) { 251 upgradeSingleUserLocked(); 252 } 253 readSettingsLocked(); 254 } 255 256 mPackageMonitor.register(context, null, UserHandle.ALL, true); 257 mMtpNotificationManager = new MtpNotificationManager( 258 parentUserContext, 259 device -> resolveActivity(createDeviceAttachedIntent(device), 260 device, false /* showMtpNotification */)); 261 262 mUsbHandlerManager = usbResolveActivityManager; 263 } 264 265 /** 266 * Unregister all broadcast receivers. Must be called explicitly before 267 * object deletion. 268 */ unregisterReceivers()269 public void unregisterReceivers() { 270 mPackageMonitor.unregister(); 271 mMtpNotificationManager.unregister(); 272 } 273 274 /** 275 * Remove all defaults and denied packages for a user. 276 * 277 * @param userToRemove The user 278 */ removeUser(@onNull UserHandle userToRemove)279 void removeUser(@NonNull UserHandle userToRemove) { 280 synchronized (mLock) { 281 boolean needToPersist = false; 282 Iterator<Map.Entry<DeviceFilter, UserPackage>> devicePreferenceIt = mDevicePreferenceMap 283 .entrySet().iterator(); 284 while (devicePreferenceIt.hasNext()) { 285 Map.Entry<DeviceFilter, UserPackage> entry = devicePreferenceIt.next(); 286 287 if (entry.getValue().user.equals(userToRemove)) { 288 devicePreferenceIt.remove(); 289 needToPersist = true; 290 } 291 } 292 293 Iterator<Map.Entry<AccessoryFilter, UserPackage>> accessoryPreferenceIt = 294 mAccessoryPreferenceMap.entrySet().iterator(); 295 while (accessoryPreferenceIt.hasNext()) { 296 Map.Entry<AccessoryFilter, UserPackage> entry = accessoryPreferenceIt.next(); 297 298 if (entry.getValue().user.equals(userToRemove)) { 299 accessoryPreferenceIt.remove(); 300 needToPersist = true; 301 } 302 } 303 304 int numEntries = mDevicePreferenceDeniedMap.size(); 305 for (int i = 0; i < numEntries; i++) { 306 ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.valueAt(i); 307 for (int j = userPackages.size() - 1; j >= 0; j--) { 308 if (userPackages.valueAt(j).user.equals(userToRemove)) { 309 userPackages.removeAt(j); 310 needToPersist = true; 311 } 312 } 313 } 314 315 numEntries = mAccessoryPreferenceDeniedMap.size(); 316 for (int i = 0; i < numEntries; i++) { 317 ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.valueAt(i); 318 for (int j = userPackages.size() - 1; j >= 0; j--) { 319 if (userPackages.valueAt(j).user.equals(userToRemove)) { 320 userPackages.removeAt(j); 321 needToPersist = true; 322 } 323 } 324 } 325 326 if (needToPersist) { 327 scheduleWriteSettingsLocked(); 328 } 329 } 330 } 331 readPreference(XmlPullParser parser)332 private void readPreference(XmlPullParser parser) 333 throws IOException, XmlPullParserException { 334 String packageName = null; 335 336 // If not set, assume it to be the parent profile 337 UserHandle user = mParentUser; 338 339 int count = parser.getAttributeCount(); 340 for (int i = 0; i < count; i++) { 341 if ("package".equals(parser.getAttributeName(i))) { 342 packageName = parser.getAttributeValue(i); 343 } 344 if ("user".equals(parser.getAttributeName(i))) { 345 // Might return null if user is not known anymore 346 user = mUserManager 347 .getUserForSerialNumber(Integer.parseInt(parser.getAttributeValue(i))); 348 } 349 } 350 351 XmlUtils.nextElement(parser); 352 if ("usb-device".equals(parser.getName())) { 353 DeviceFilter filter = DeviceFilter.read(parser); 354 if (user != null) { 355 mDevicePreferenceMap.put(filter, new UserPackage(packageName, user)); 356 } 357 } else if ("usb-accessory".equals(parser.getName())) { 358 AccessoryFilter filter = AccessoryFilter.read(parser); 359 if (user != null) { 360 mAccessoryPreferenceMap.put(filter, new UserPackage(packageName, user)); 361 } 362 } 363 XmlUtils.nextElement(parser); 364 } 365 readPreferenceDeniedList(@onNull XmlPullParser parser)366 private void readPreferenceDeniedList(@NonNull XmlPullParser parser) 367 throws IOException, XmlPullParserException { 368 int outerDepth = parser.getDepth(); 369 if (!XmlUtils.nextElementWithin(parser, outerDepth)) { 370 return; 371 } 372 373 if ("usb-device".equals(parser.getName())) { 374 DeviceFilter filter = DeviceFilter.read(parser); 375 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 376 if ("user-package".equals(parser.getName())) { 377 try { 378 int userId = XmlUtils.readIntAttribute(parser, "user"); 379 380 String packageName = XmlUtils.readStringAttribute(parser, "package"); 381 if (packageName == null) { 382 Slog.e(TAG, "Unable to parse package name"); 383 } 384 385 ArraySet<UserPackage> set = mDevicePreferenceDeniedMap.get(filter); 386 if (set == null) { 387 set = new ArraySet<>(); 388 mDevicePreferenceDeniedMap.put(filter, set); 389 } 390 set.add(new UserPackage(packageName, UserHandle.of(userId))); 391 } catch (ProtocolException e) { 392 Slog.e(TAG, "Unable to parse user id", e); 393 } 394 } 395 } 396 } else if ("usb-accessory".equals(parser.getName())) { 397 AccessoryFilter filter = AccessoryFilter.read(parser); 398 399 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 400 if ("user-package".equals(parser.getName())) { 401 try { 402 int userId = XmlUtils.readIntAttribute(parser, "user"); 403 404 String packageName = XmlUtils.readStringAttribute(parser, "package"); 405 if (packageName == null) { 406 Slog.e(TAG, "Unable to parse package name"); 407 } 408 409 ArraySet<UserPackage> set = mAccessoryPreferenceDeniedMap.get(filter); 410 if (set == null) { 411 set = new ArraySet<>(); 412 mAccessoryPreferenceDeniedMap.put(filter, set); 413 } 414 set.add(new UserPackage(packageName, UserHandle.of(userId))); 415 } catch (ProtocolException e) { 416 Slog.e(TAG, "Unable to parse user id", e); 417 } 418 } 419 } 420 } 421 422 while (parser.getDepth() > outerDepth) { 423 parser.nextTag(); // ignore unknown tags 424 } 425 } 426 427 /** 428 * Upgrade any single-user settings from {@link #sSingleUserSettingsFile}. 429 * Should only be called by owner. 430 */ 431 @GuardedBy("mLock") upgradeSingleUserLocked()432 private void upgradeSingleUserLocked() { 433 if (sSingleUserSettingsFile.exists()) { 434 mDevicePreferenceMap.clear(); 435 mAccessoryPreferenceMap.clear(); 436 437 FileInputStream fis = null; 438 try { 439 fis = new FileInputStream(sSingleUserSettingsFile); 440 TypedXmlPullParser parser = Xml.resolvePullParser(fis); 441 442 XmlUtils.nextElement(parser); 443 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 444 final String tagName = parser.getName(); 445 if ("preference".equals(tagName)) { 446 readPreference(parser); 447 } else { 448 XmlUtils.nextElement(parser); 449 } 450 } 451 } catch (IOException | XmlPullParserException e) { 452 Log.wtf(TAG, "Failed to read single-user settings", e); 453 } finally { 454 IoUtils.closeQuietly(fis); 455 } 456 457 scheduleWriteSettingsLocked(); 458 459 // Success or failure, we delete single-user file 460 sSingleUserSettingsFile.delete(); 461 } 462 } 463 464 @GuardedBy("mLock") readSettingsLocked()465 private void readSettingsLocked() { 466 if (DEBUG) Slog.v(TAG, "readSettingsLocked()"); 467 468 mDevicePreferenceMap.clear(); 469 mAccessoryPreferenceMap.clear(); 470 471 FileInputStream stream = null; 472 try { 473 stream = mSettingsFile.openRead(); 474 TypedXmlPullParser parser = Xml.resolvePullParser(stream); 475 476 XmlUtils.nextElement(parser); 477 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 478 String tagName = parser.getName(); 479 if ("preference".equals(tagName)) { 480 readPreference(parser); 481 } else if ("preference-denied-list".equals(tagName)) { 482 readPreferenceDeniedList(parser); 483 } else { 484 XmlUtils.nextElement(parser); 485 } 486 } 487 } catch (FileNotFoundException e) { 488 if (DEBUG) Slog.d(TAG, "settings file not found"); 489 } catch (Exception e) { 490 Slog.e(TAG, "error reading settings file, deleting to start fresh", e); 491 mSettingsFile.delete(); 492 } finally { 493 IoUtils.closeQuietly(stream); 494 } 495 } 496 497 /** 498 * Schedule a async task to persist {@link #mDevicePreferenceMap} and 499 * {@link #mAccessoryPreferenceMap}. If a task is already scheduled but not completed, do 500 * nothing as the currently scheduled one will do the work. 501 * <p>Called with {@link #mLock} held.</p> 502 * <p>In the uncommon case that the system crashes in between the scheduling and the write the 503 * update is lost.</p> 504 */ 505 @GuardedBy("mLock") scheduleWriteSettingsLocked()506 private void scheduleWriteSettingsLocked() { 507 if (mIsWriteSettingsScheduled) { 508 return; 509 } else { 510 mIsWriteSettingsScheduled = true; 511 } 512 513 AsyncTask.execute(() -> { 514 synchronized (mLock) { 515 FileOutputStream fos = null; 516 try { 517 fos = mSettingsFile.startWrite(); 518 519 TypedXmlSerializer serializer = Xml.resolveSerializer(fos); 520 serializer.startDocument(null, true); 521 serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", 522 true); 523 serializer.startTag(null, "settings"); 524 525 for (DeviceFilter filter : mDevicePreferenceMap.keySet()) { 526 serializer.startTag(null, "preference"); 527 serializer.attribute(null, "package", 528 mDevicePreferenceMap.get(filter).packageName); 529 serializer.attribute(null, "user", 530 String.valueOf(getSerial(mDevicePreferenceMap.get(filter).user))); 531 filter.write(serializer); 532 serializer.endTag(null, "preference"); 533 } 534 535 for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) { 536 serializer.startTag(null, "preference"); 537 serializer.attribute(null, "package", 538 mAccessoryPreferenceMap.get(filter).packageName); 539 serializer.attribute(null, "user", String.valueOf( 540 getSerial(mAccessoryPreferenceMap.get(filter).user))); 541 filter.write(serializer); 542 serializer.endTag(null, "preference"); 543 } 544 545 int numEntries = mDevicePreferenceDeniedMap.size(); 546 for (int i = 0; i < numEntries; i++) { 547 DeviceFilter filter = mDevicePreferenceDeniedMap.keyAt(i); 548 ArraySet<UserPackage> userPackageSet = mDevicePreferenceDeniedMap 549 .valueAt(i); 550 serializer.startTag(null, "preference-denied-list"); 551 filter.write(serializer); 552 553 int numUserPackages = userPackageSet.size(); 554 for (int j = 0; j < numUserPackages; j++) { 555 UserPackage userPackage = userPackageSet.valueAt(j); 556 serializer.startTag(null, "user-package"); 557 serializer.attribute(null, "user", 558 String.valueOf(getSerial(userPackage.user))); 559 serializer.attribute(null, "package", userPackage.packageName); 560 serializer.endTag(null, "user-package"); 561 } 562 serializer.endTag(null, "preference-denied-list"); 563 } 564 565 numEntries = mAccessoryPreferenceDeniedMap.size(); 566 for (int i = 0; i < numEntries; i++) { 567 AccessoryFilter filter = mAccessoryPreferenceDeniedMap.keyAt(i); 568 ArraySet<UserPackage> userPackageSet = 569 mAccessoryPreferenceDeniedMap.valueAt(i); 570 serializer.startTag(null, "preference-denied-list"); 571 filter.write(serializer); 572 573 int numUserPackages = userPackageSet.size(); 574 for (int j = 0; j < numUserPackages; j++) { 575 UserPackage userPackage = userPackageSet.valueAt(j); 576 serializer.startTag(null, "user-package"); 577 serializer.attribute(null, "user", 578 String.valueOf(getSerial(userPackage.user))); 579 serializer.attribute(null, "package", userPackage.packageName); 580 serializer.endTag(null, "user-package"); 581 } 582 serializer.endTag(null, "preference-denied-list"); 583 } 584 585 serializer.endTag(null, "settings"); 586 serializer.endDocument(); 587 588 mSettingsFile.finishWrite(fos); 589 } catch (IOException e) { 590 Slog.e(TAG, "Failed to write settings", e); 591 if (fos != null) { 592 mSettingsFile.failWrite(fos); 593 } 594 } 595 596 mIsWriteSettingsScheduled = false; 597 } 598 }); 599 } 600 601 /** 602 * Get {@link DeviceFilter} for all devices an activity should be launched for. 603 * 604 * @param pm The package manager used to get the device filter files 605 * @param info The {@link ResolveInfo} for the activity that can handle usb device attached 606 * events 607 * 608 * @return The list of {@link DeviceFilter} the activity should be called for or {@code null} if 609 * none 610 */ 611 @Nullable getDeviceFilters(@onNull PackageManager pm, @NonNull ResolveInfo info)612 static ArrayList<DeviceFilter> getDeviceFilters(@NonNull PackageManager pm, 613 @NonNull ResolveInfo info) { 614 ArrayList<DeviceFilter> filters = null; 615 ActivityInfo ai = info.activityInfo; 616 617 XmlResourceParser parser = null; 618 try { 619 parser = ai.loadXmlMetaData(pm, UsbManager.ACTION_USB_DEVICE_ATTACHED); 620 if (parser == null) { 621 Slog.w(TAG, "no meta-data for " + info); 622 return null; 623 } 624 625 XmlUtils.nextElement(parser); 626 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 627 String tagName = parser.getName(); 628 if ("usb-device".equals(tagName)) { 629 if (filters == null) { 630 filters = new ArrayList<>(1); 631 } 632 filters.add(DeviceFilter.read(parser)); 633 } 634 XmlUtils.nextElement(parser); 635 } 636 } catch (Exception e) { 637 Slog.w(TAG, "Unable to load component info " + info.toString(), e); 638 } finally { 639 if (parser != null) parser.close(); 640 } 641 return filters; 642 } 643 644 /** 645 * Get {@link AccessoryFilter} for all accessories an activity should be launched for. 646 * 647 * @param pm The package manager used to get the accessory filter files 648 * @param info The {@link ResolveInfo} for the activity that can handle usb accessory attached 649 * events 650 * 651 * @return The list of {@link AccessoryFilter} the activity should be called for or {@code null} 652 * if none 653 */ getAccessoryFilters(@onNull PackageManager pm, @NonNull ResolveInfo info)654 static @Nullable ArrayList<AccessoryFilter> getAccessoryFilters(@NonNull PackageManager pm, 655 @NonNull ResolveInfo info) { 656 ArrayList<AccessoryFilter> filters = null; 657 ActivityInfo ai = info.activityInfo; 658 659 XmlResourceParser parser = null; 660 try { 661 parser = ai.loadXmlMetaData(pm, UsbManager.ACTION_USB_ACCESSORY_ATTACHED); 662 if (parser == null) { 663 Slog.w(TAG, "no meta-data for " + info); 664 return null; 665 } 666 667 XmlUtils.nextElement(parser); 668 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 669 String tagName = parser.getName(); 670 if ("usb-accessory".equals(tagName)) { 671 if (filters == null) { 672 filters = new ArrayList<>(1); 673 } 674 filters.add(AccessoryFilter.read(parser)); 675 } 676 XmlUtils.nextElement(parser); 677 } 678 } catch (Exception e) { 679 Slog.w(TAG, "Unable to load component info " + info.toString(), e); 680 } finally { 681 if (parser != null) parser.close(); 682 } 683 return filters; 684 } 685 686 // Checks to see if a package matches a device or accessory. 687 // Only one of device and accessory should be non-null. packageMatchesLocked(ResolveInfo info, UsbDevice device, UsbAccessory accessory)688 private boolean packageMatchesLocked(ResolveInfo info, UsbDevice device, 689 UsbAccessory accessory) { 690 if (isForwardMatch(info)) { 691 return true; 692 } 693 694 if (device != null) { 695 ArrayList<DeviceFilter> deviceFilters = getDeviceFilters(mPackageManager, info); 696 if (deviceFilters != null) { 697 int numDeviceFilters = deviceFilters.size(); 698 for (int i = 0; i < numDeviceFilters; i++) { 699 if (deviceFilters.get(i).matches(device)) { 700 return true; 701 } 702 } 703 } 704 } 705 706 if (accessory != null) { 707 ArrayList<AccessoryFilter> accessoryFilters = getAccessoryFilters(mPackageManager, 708 info); 709 if (accessoryFilters != null) { 710 int numAccessoryFilters = accessoryFilters.size(); 711 for (int i = 0; i < numAccessoryFilters; i++) { 712 if (accessoryFilters.get(i).matches(accessory)) { 713 return true; 714 } 715 } 716 } 717 } 718 719 return false; 720 } 721 722 /** 723 * Resolve all activities that match an intent for all profiles of this group. 724 * 725 * @param intent The intent to resolve 726 * 727 * @return The {@link ResolveInfo}s for all profiles of the group 728 */ queryIntentActivitiesForAllProfiles( @onNull Intent intent)729 private @NonNull ArrayList<ResolveInfo> queryIntentActivitiesForAllProfiles( 730 @NonNull Intent intent) { 731 List<UserInfo> profiles = mUserManager.getEnabledProfiles(mParentUser.getIdentifier()); 732 733 ArrayList<ResolveInfo> resolveInfos = new ArrayList<>(); 734 int numProfiles = profiles.size(); 735 for (int i = 0; i < numProfiles; i++) { 736 resolveInfos.addAll(mSettingsManager.getSettingsForUser(profiles.get(i).id) 737 .queryIntentActivities(intent)); 738 } 739 740 return resolveInfos; 741 } 742 743 /** 744 * If this match used to forward the intent to another profile? 745 * 746 * @param match The match 747 * 748 * @return {@code true} iff this is such a forward match 749 */ isForwardMatch(@onNull ResolveInfo match)750 private boolean isForwardMatch(@NonNull ResolveInfo match) { 751 return match.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE); 752 } 753 754 /** 755 * Only return those matches with the highest priority. 756 * 757 * @param matches All matches, some might have lower priority 758 * 759 * @return The matches with the highest priority 760 */ 761 @NonNull preferHighPriority(@onNull ArrayList<ResolveInfo> matches)762 private ArrayList<ResolveInfo> preferHighPriority(@NonNull ArrayList<ResolveInfo> matches) { 763 SparseArray<ArrayList<ResolveInfo>> highestPriorityMatchesByUserId = new SparseArray<>(); 764 SparseIntArray highestPriorityByUserId = new SparseIntArray(); 765 ArrayList<ResolveInfo> forwardMatches = new ArrayList<>(); 766 767 // Create list of highest priority matches per user in highestPriorityMatchesByUserId 768 int numMatches = matches.size(); 769 for (int matchNum = 0; matchNum < numMatches; matchNum++) { 770 ResolveInfo match = matches.get(matchNum); 771 772 // Unnecessary forward matches are filtered out later, hence collect them all to add 773 // them below 774 if (isForwardMatch(match)) { 775 forwardMatches.add(match); 776 continue; 777 } 778 779 // If this a previously unknown user? 780 if (highestPriorityByUserId.indexOfKey(match.targetUserId) < 0) { 781 highestPriorityByUserId.put(match.targetUserId, Integer.MIN_VALUE); 782 highestPriorityMatchesByUserId.put(match.targetUserId, new ArrayList<>()); 783 } 784 785 // Find current highest priority matches for the current user 786 int highestPriority = highestPriorityByUserId.get(match.targetUserId); 787 ArrayList<ResolveInfo> highestPriorityMatches = highestPriorityMatchesByUserId.get( 788 match.targetUserId); 789 790 if (match.priority == highestPriority) { 791 highestPriorityMatches.add(match); 792 } else if (match.priority > highestPriority) { 793 highestPriorityByUserId.put(match.targetUserId, match.priority); 794 795 highestPriorityMatches.clear(); 796 highestPriorityMatches.add(match); 797 } 798 } 799 800 // Combine all users (+ forward matches) back together. This means that all non-forward 801 // matches have the same priority for a user. Matches for different users might have 802 // different priority. 803 ArrayList<ResolveInfo> combinedMatches = new ArrayList<>(forwardMatches); 804 int numMatchArrays = highestPriorityMatchesByUserId.size(); 805 for (int matchArrayNum = 0; matchArrayNum < numMatchArrays; matchArrayNum++) { 806 combinedMatches.addAll(highestPriorityMatchesByUserId.valueAt(matchArrayNum)); 807 } 808 809 return combinedMatches; 810 } 811 812 /** 813 * If there are no matches for a profile, remove the forward intent to this profile. 814 * 815 * @param rawMatches The matches that contain all forward intents 816 * 817 * @return The matches with the unnecessary forward intents removed 818 */ removeForwardIntentIfNotNeeded( @onNull ArrayList<ResolveInfo> rawMatches)819 @NonNull private ArrayList<ResolveInfo> removeForwardIntentIfNotNeeded( 820 @NonNull ArrayList<ResolveInfo> rawMatches) { 821 final int numRawMatches = rawMatches.size(); 822 823 // The raw matches contain the activities that can be started but also the intents to 824 // forward the intent to the other profile 825 int numParentActivityMatches = 0; 826 int numNonParentActivityMatches = 0; 827 for (int i = 0; i < numRawMatches; i++) { 828 final ResolveInfo rawMatch = rawMatches.get(i); 829 if (!isForwardMatch(rawMatch)) { 830 if (UserHandle.getUserHandleForUid( 831 rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) { 832 numParentActivityMatches++; 833 } else { 834 numNonParentActivityMatches++; 835 } 836 } 837 } 838 839 // If only one profile has activity matches, we need to remove all switch intents 840 if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) { 841 ArrayList<ResolveInfo> matches = new ArrayList<>( 842 numParentActivityMatches + numNonParentActivityMatches); 843 844 for (int i = 0; i < numRawMatches; i++) { 845 ResolveInfo rawMatch = rawMatches.get(i); 846 if (!isForwardMatch(rawMatch)) { 847 matches.add(rawMatch); 848 } 849 } 850 return matches; 851 852 } else { 853 return rawMatches; 854 } 855 } 856 getDeviceMatchesLocked(UsbDevice device, Intent intent)857 private ArrayList<ResolveInfo> getDeviceMatchesLocked(UsbDevice device, Intent intent) { 858 ArrayList<ResolveInfo> matches = new ArrayList<>(); 859 List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent); 860 int count = resolveInfos.size(); 861 for (int i = 0; i < count; i++) { 862 ResolveInfo resolveInfo = resolveInfos.get(i); 863 if (packageMatchesLocked(resolveInfo, device, null)) { 864 matches.add(resolveInfo); 865 } 866 } 867 868 return removeForwardIntentIfNotNeeded(preferHighPriority(matches)); 869 } 870 getAccessoryMatchesLocked( UsbAccessory accessory, Intent intent)871 private ArrayList<ResolveInfo> getAccessoryMatchesLocked( 872 UsbAccessory accessory, Intent intent) { 873 ArrayList<ResolveInfo> matches = new ArrayList<>(); 874 List<ResolveInfo> resolveInfos = queryIntentActivitiesForAllProfiles(intent); 875 int count = resolveInfos.size(); 876 for (int i = 0; i < count; i++) { 877 ResolveInfo resolveInfo = resolveInfos.get(i); 878 if (packageMatchesLocked(resolveInfo, null, accessory)) { 879 matches.add(resolveInfo); 880 } 881 } 882 883 return removeForwardIntentIfNotNeeded(preferHighPriority(matches)); 884 } 885 deviceAttached(UsbDevice device)886 public void deviceAttached(UsbDevice device) { 887 final Intent intent = createDeviceAttachedIntent(device); 888 889 // Send broadcast to running activities with registered intent 890 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 891 892 resolveActivity(intent, device, true /* showMtpNotification */); 893 } 894 resolveActivity(Intent intent, UsbDevice device, boolean showMtpNotification)895 private void resolveActivity(Intent intent, UsbDevice device, boolean showMtpNotification) { 896 final ArrayList<ResolveInfo> matches; 897 final ActivityInfo defaultActivity; 898 synchronized (mLock) { 899 matches = getDeviceMatchesLocked(device, intent); 900 defaultActivity = getDefaultActivityLocked( 901 matches, mDevicePreferenceMap.get(new DeviceFilter(device))); 902 } 903 904 if (showMtpNotification && MtpNotificationManager.shouldShowNotification( 905 mPackageManager, device) && defaultActivity == null) { 906 // Show notification if the device is MTP storage. 907 mMtpNotificationManager.showNotification(device); 908 return; 909 } 910 911 // Start activity with registered intent 912 resolveActivity(intent, matches, defaultActivity, device, null); 913 } 914 deviceAttachedForFixedHandler(UsbDevice device, ComponentName component)915 public void deviceAttachedForFixedHandler(UsbDevice device, ComponentName component) { 916 final Intent intent = createDeviceAttachedIntent(device); 917 918 // Send broadcast to running activity with registered intent 919 mContext.sendBroadcastAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser())); 920 921 ApplicationInfo appInfo; 922 try { 923 // Fixed handlers are always for parent user 924 appInfo = mPackageManager.getApplicationInfoAsUser(component.getPackageName(), 0, 925 mParentUser.getIdentifier()); 926 } catch (NameNotFoundException e) { 927 Slog.e(TAG, "Default USB handling package (" + component.getPackageName() 928 + ") not found for user " + mParentUser); 929 return; 930 } 931 932 mSettingsManager.mUsbService.getPermissionsForUser(UserHandle.getUserId(appInfo.uid)) 933 .grantDevicePermission(device, appInfo.uid); 934 935 Intent activityIntent = new Intent(intent); 936 activityIntent.setComponent(component); 937 try { 938 mContext.startActivityAsUser(activityIntent, mParentUser); 939 } catch (ActivityNotFoundException e) { 940 Slog.e(TAG, "unable to start activity " + activityIntent); 941 } 942 } 943 944 /** 945 * Remove notifications for a usb device. 946 * 947 * @param device The device the notifications are for. 948 */ usbDeviceRemoved(@onNull UsbDevice device)949 void usbDeviceRemoved(@NonNull UsbDevice device) { 950 mMtpNotificationManager.hideNotification(device.getDeviceId()); 951 } 952 accessoryAttached(UsbAccessory accessory)953 public void accessoryAttached(UsbAccessory accessory) { 954 Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); 955 intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); 956 intent.addFlags( 957 Intent.FLAG_ACTIVITY_NEW_TASK | 958 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 959 960 final ArrayList<ResolveInfo> matches; 961 final ActivityInfo defaultActivity; 962 synchronized (mLock) { 963 matches = getAccessoryMatchesLocked(accessory, intent); 964 defaultActivity = getDefaultActivityLocked( 965 matches, mAccessoryPreferenceMap.get(new AccessoryFilter(accessory))); 966 } 967 968 resolveActivity(intent, matches, defaultActivity, null, accessory); 969 } 970 971 /** 972 * Start the appropriate package when an device/accessory got attached. 973 * 974 * @param intent The intent to start the package 975 * @param matches The available resolutions of the intent 976 * @param defaultActivity The default activity for the device (if set) 977 * @param device The device if a device was attached 978 * @param accessory The accessory if a device was attached 979 */ resolveActivity(@onNull Intent intent, @NonNull ArrayList<ResolveInfo> matches, @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device, @Nullable UsbAccessory accessory)980 private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList<ResolveInfo> matches, 981 @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device, 982 @Nullable UsbAccessory accessory) { 983 // Remove all matches which are on the denied list 984 ArraySet deniedPackages = null; 985 if (device != null) { 986 deniedPackages = mDevicePreferenceDeniedMap.get(new DeviceFilter(device)); 987 } else if (accessory != null) { 988 deniedPackages = mAccessoryPreferenceDeniedMap.get(new AccessoryFilter(accessory)); 989 } 990 if (deniedPackages != null) { 991 for (int i = matches.size() - 1; i >= 0; i--) { 992 ResolveInfo match = matches.get(i); 993 String packageName = match.activityInfo.packageName; 994 UserHandle user = UserHandle 995 .getUserHandleForUid(match.activityInfo.applicationInfo.uid); 996 if (deniedPackages.contains(new UserPackage(packageName, user))) { 997 matches.remove(i); 998 } 999 } 1000 } 1001 1002 // don't show the resolver activity if there are no choices available 1003 if (matches.size() == 0) { 1004 if (accessory != null) { 1005 mUsbHandlerManager.showUsbAccessoryUriActivity(accessory, mParentUser); 1006 } 1007 // do nothing 1008 return; 1009 } 1010 1011 if (defaultActivity != null) { 1012 UsbUserPermissionManager defaultRIUserPermissions = 1013 mSettingsManager.mUsbService.getPermissionsForUser( 1014 UserHandle.getUserId(defaultActivity.applicationInfo.uid)); 1015 // grant permission for default activity 1016 if (device != null) { 1017 defaultRIUserPermissions 1018 .grantDevicePermission(device, defaultActivity.applicationInfo.uid); 1019 } else if (accessory != null) { 1020 defaultRIUserPermissions.grantAccessoryPermission(accessory, 1021 defaultActivity.applicationInfo.uid); 1022 } 1023 1024 // start default activity directly 1025 try { 1026 intent.setComponent( 1027 new ComponentName(defaultActivity.packageName, defaultActivity.name)); 1028 1029 UserHandle user = UserHandle.getUserHandleForUid( 1030 defaultActivity.applicationInfo.uid); 1031 mContext.startActivityAsUser(intent, user); 1032 } catch (ActivityNotFoundException e) { 1033 Slog.e(TAG, "startActivity failed", e); 1034 } 1035 } else { 1036 if (matches.size() == 1) { 1037 mUsbHandlerManager.confirmUsbHandler(matches.get(0), device, accessory); 1038 } else { 1039 mUsbHandlerManager.selectUsbHandler(matches, mParentUser, intent); 1040 } 1041 } 1042 } 1043 1044 /** 1045 * Returns a default activity for matched ResolveInfo. 1046 * @param matches Resolved activities matched with connected device/accesary. 1047 * @param userPackage Default activity choosed by a user before. Should be null if no activity 1048 * is choosed by a user. 1049 * @return Default activity 1050 */ getDefaultActivityLocked( @onNull ArrayList<ResolveInfo> matches, @Nullable UserPackage userPackage)1051 private @Nullable ActivityInfo getDefaultActivityLocked( 1052 @NonNull ArrayList<ResolveInfo> matches, 1053 @Nullable UserPackage userPackage) { 1054 if (userPackage != null) { 1055 // look for default activity 1056 for (final ResolveInfo info : matches) { 1057 if (info.activityInfo != null && userPackage.equals( 1058 new UserPackage(info.activityInfo.packageName, 1059 UserHandle.getUserHandleForUid( 1060 info.activityInfo.applicationInfo.uid)))) { 1061 return info.activityInfo; 1062 } 1063 } 1064 } 1065 1066 if (matches.size() == 1) { 1067 final ActivityInfo activityInfo = matches.get(0).activityInfo; 1068 if (activityInfo != null) { 1069 if (mDisablePermissionDialogs) { 1070 return activityInfo; 1071 } 1072 // System apps are considered default unless there are other matches 1073 if (activityInfo.applicationInfo != null 1074 && (activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 1075 != 0) { 1076 return activityInfo; 1077 } 1078 } 1079 } 1080 1081 return null; 1082 } 1083 1084 @GuardedBy("mLock") clearCompatibleMatchesLocked(@onNull UserPackage userPackage, @NonNull DeviceFilter filter)1085 private boolean clearCompatibleMatchesLocked(@NonNull UserPackage userPackage, 1086 @NonNull DeviceFilter filter) { 1087 ArrayList<DeviceFilter> keysToRemove = new ArrayList<>(); 1088 1089 // The keys in mDevicePreferenceMap are filters that match devices very narrowly 1090 for (DeviceFilter device : mDevicePreferenceMap.keySet()) { 1091 if (filter.contains(device)) { 1092 UserPackage currentMatch = mDevicePreferenceMap.get(device); 1093 if (!currentMatch.equals(userPackage)) { 1094 keysToRemove.add(device); 1095 } 1096 } 1097 } 1098 1099 if (!keysToRemove.isEmpty()) { 1100 for (DeviceFilter keyToRemove : keysToRemove) { 1101 mDevicePreferenceMap.remove(keyToRemove); 1102 } 1103 } 1104 1105 return !keysToRemove.isEmpty(); 1106 } 1107 1108 @GuardedBy("mLock") clearCompatibleMatchesLocked(@onNull UserPackage userPackage, @NonNull AccessoryFilter filter)1109 private boolean clearCompatibleMatchesLocked(@NonNull UserPackage userPackage, 1110 @NonNull AccessoryFilter filter) { 1111 ArrayList<AccessoryFilter> keysToRemove = new ArrayList<>(); 1112 1113 // The keys in mAccessoryPreferenceMap are filters that match accessories very narrowly 1114 for (AccessoryFilter accessory : mAccessoryPreferenceMap.keySet()) { 1115 if (filter.contains(accessory)) { 1116 UserPackage currentMatch = mAccessoryPreferenceMap.get(accessory); 1117 if (!currentMatch.equals(userPackage)) { 1118 keysToRemove.add(accessory); 1119 } 1120 } 1121 } 1122 1123 if (!keysToRemove.isEmpty()) { 1124 for (AccessoryFilter keyToRemove : keysToRemove) { 1125 mAccessoryPreferenceMap.remove(keyToRemove); 1126 } 1127 } 1128 1129 return !keysToRemove.isEmpty(); 1130 } 1131 1132 @GuardedBy("mLock") handlePackageAddedLocked(UserPackage userPackage, ActivityInfo aInfo, String metaDataName)1133 private boolean handlePackageAddedLocked(UserPackage userPackage, ActivityInfo aInfo, 1134 String metaDataName) { 1135 XmlResourceParser parser = null; 1136 boolean changed = false; 1137 1138 try { 1139 parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName); 1140 if (parser == null) return false; 1141 1142 XmlUtils.nextElement(parser); 1143 while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { 1144 String tagName = parser.getName(); 1145 if ("usb-device".equals(tagName)) { 1146 DeviceFilter filter = DeviceFilter.read(parser); 1147 if (clearCompatibleMatchesLocked(userPackage, filter)) { 1148 changed = true; 1149 } 1150 } 1151 else if ("usb-accessory".equals(tagName)) { 1152 AccessoryFilter filter = AccessoryFilter.read(parser); 1153 if (clearCompatibleMatchesLocked(userPackage, filter)) { 1154 changed = true; 1155 } 1156 } 1157 XmlUtils.nextElement(parser); 1158 } 1159 } catch (Exception e) { 1160 Slog.w(TAG, "Unable to load component info " + aInfo.toString(), e); 1161 } finally { 1162 if (parser != null) parser.close(); 1163 } 1164 return changed; 1165 } 1166 1167 // Check to see if the package supports any USB devices or accessories. 1168 // If so, clear any preferences for matching devices/accessories. handlePackageAdded(@onNull UserPackage userPackage)1169 private void handlePackageAdded(@NonNull UserPackage userPackage) { 1170 synchronized (mLock) { 1171 PackageInfo info; 1172 boolean changed = false; 1173 1174 try { 1175 info = mPackageManager.getPackageInfoAsUser(userPackage.packageName, 1176 PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA, 1177 userPackage.user.getIdentifier()); 1178 } catch (NameNotFoundException e) { 1179 Slog.e(TAG, "handlePackageUpdate could not find package " + userPackage, e); 1180 return; 1181 } 1182 1183 ActivityInfo[] activities = info.activities; 1184 if (activities == null) return; 1185 for (int i = 0; i < activities.length; i++) { 1186 // check for meta-data, both for devices and accessories 1187 if (handlePackageAddedLocked(userPackage, activities[i], 1188 UsbManager.ACTION_USB_DEVICE_ATTACHED)) { 1189 changed = true; 1190 } 1191 1192 if (handlePackageAddedLocked(userPackage, activities[i], 1193 UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) { 1194 changed = true; 1195 } 1196 } 1197 1198 if (changed) { 1199 scheduleWriteSettingsLocked(); 1200 } 1201 } 1202 } 1203 1204 /** 1205 * Get the serial number for a user handle. 1206 * 1207 * @param user The user handle 1208 * 1209 * @return The serial number 1210 */ getSerial(@onNull UserHandle user)1211 private int getSerial(@NonNull UserHandle user) { 1212 return mUserManager.getUserSerialNumber(user.getIdentifier()); 1213 } 1214 1215 /** 1216 * Set a package as default handler for a device. 1217 * 1218 * @param device The device that should be handled by default 1219 * @param packageName The default handler package 1220 * @param user The user the package belongs to 1221 */ setDevicePackage(@onNull UsbDevice device, @Nullable String packageName, @NonNull UserHandle user)1222 void setDevicePackage(@NonNull UsbDevice device, @Nullable String packageName, 1223 @NonNull UserHandle user) { 1224 DeviceFilter filter = new DeviceFilter(device); 1225 boolean changed; 1226 synchronized (mLock) { 1227 if (packageName == null) { 1228 changed = (mDevicePreferenceMap.remove(filter) != null); 1229 } else { 1230 UserPackage userPackage = new UserPackage(packageName, user); 1231 1232 changed = !userPackage.equals(mDevicePreferenceMap.get(filter)); 1233 if (changed) { 1234 mDevicePreferenceMap.put(filter, userPackage); 1235 } 1236 } 1237 if (changed) { 1238 scheduleWriteSettingsLocked(); 1239 } 1240 } 1241 } 1242 1243 /** 1244 * Add package to the denied for handling a device 1245 * 1246 * @param device the device to add to the denied 1247 * @param packageNames the packages to not become handler 1248 * @param user the user 1249 */ addDevicePackagesToDenied(@onNull UsbDevice device, @NonNull String[] packageNames, @NonNull UserHandle user)1250 void addDevicePackagesToDenied(@NonNull UsbDevice device, @NonNull String[] packageNames, 1251 @NonNull UserHandle user) { 1252 if (packageNames.length == 0) { 1253 return; 1254 } 1255 DeviceFilter filter = new DeviceFilter(device); 1256 1257 synchronized (mLock) { 1258 ArraySet<UserPackage> userPackages; 1259 if (mDevicePreferenceDeniedMap.containsKey(filter)) { 1260 userPackages = mDevicePreferenceDeniedMap.get(filter); 1261 } else { 1262 userPackages = new ArraySet<>(); 1263 mDevicePreferenceDeniedMap.put(filter, userPackages); 1264 } 1265 1266 boolean shouldWrite = false; 1267 for (String packageName : packageNames) { 1268 UserPackage userPackage = new UserPackage(packageName, user); 1269 if (!userPackages.contains(userPackage)) { 1270 userPackages.add(userPackage); 1271 shouldWrite = true; 1272 } 1273 } 1274 1275 if (shouldWrite) { 1276 scheduleWriteSettingsLocked(); 1277 } 1278 } 1279 } 1280 1281 /** 1282 * Add package to the denied for handling a accessory 1283 * 1284 * @param accessory the accessory to add to the denied 1285 * @param packageNames the packages to not become handler 1286 * @param user the user 1287 */ addAccessoryPackagesToDenied(@onNull UsbAccessory accessory, @NonNull String[] packageNames, @NonNull UserHandle user)1288 void addAccessoryPackagesToDenied(@NonNull UsbAccessory accessory, 1289 @NonNull String[] packageNames, @NonNull UserHandle user) { 1290 if (packageNames.length == 0) { 1291 return; 1292 } 1293 AccessoryFilter filter = new AccessoryFilter(accessory); 1294 1295 synchronized (mLock) { 1296 ArraySet<UserPackage> userPackages; 1297 if (mAccessoryPreferenceDeniedMap.containsKey(filter)) { 1298 userPackages = mAccessoryPreferenceDeniedMap.get(filter); 1299 } else { 1300 userPackages = new ArraySet<>(); 1301 mAccessoryPreferenceDeniedMap.put(filter, userPackages); 1302 } 1303 1304 boolean shouldWrite = false; 1305 for (String packageName : packageNames) { 1306 UserPackage userPackage = new UserPackage(packageName, user); 1307 if (!userPackages.contains(userPackage)) { 1308 userPackages.add(userPackage); 1309 shouldWrite = true; 1310 } 1311 } 1312 1313 if (shouldWrite) { 1314 scheduleWriteSettingsLocked(); 1315 } 1316 } 1317 } 1318 1319 /** 1320 * Remove UserPackage from the denied for handling a device 1321 * 1322 * @param device the device to remove denied packages from 1323 * @param packageName the packages to remove 1324 * @param user the user 1325 */ removeDevicePackagesFromDenied(@onNull UsbDevice device, @NonNull String[] packageNames, @NonNull UserHandle user)1326 void removeDevicePackagesFromDenied(@NonNull UsbDevice device, @NonNull String[] packageNames, 1327 @NonNull UserHandle user) { 1328 DeviceFilter filter = new DeviceFilter(device); 1329 1330 synchronized (mLock) { 1331 ArraySet<UserPackage> userPackages = mDevicePreferenceDeniedMap.get(filter); 1332 1333 if (userPackages != null) { 1334 boolean shouldWrite = false; 1335 for (String packageName : packageNames) { 1336 UserPackage userPackage = new UserPackage(packageName, user); 1337 1338 if (userPackages.contains(userPackage)) { 1339 userPackages.remove(userPackage); 1340 shouldWrite = true; 1341 1342 if (userPackages.size() == 0) { 1343 mDevicePreferenceDeniedMap.remove(filter); 1344 break; 1345 } 1346 } 1347 } 1348 1349 if (shouldWrite) { 1350 scheduleWriteSettingsLocked(); 1351 } 1352 } 1353 } 1354 } 1355 1356 /** 1357 * Remove UserPackage from the denied for handling a accessory 1358 * 1359 * @param accessory the accessory to remove denied packages from 1360 * @param packageName the packages to remove 1361 * @param user the user 1362 */ removeAccessoryPackagesFromDenied(@onNull UsbAccessory accessory, @NonNull String[] packageNames, @NonNull UserHandle user)1363 void removeAccessoryPackagesFromDenied(@NonNull UsbAccessory accessory, 1364 @NonNull String[] packageNames, @NonNull UserHandle user) { 1365 AccessoryFilter filter = new AccessoryFilter(accessory); 1366 1367 synchronized (mLock) { 1368 ArraySet<UserPackage> userPackages = mAccessoryPreferenceDeniedMap.get(filter); 1369 1370 if (userPackages != null) { 1371 boolean shouldWrite = false; 1372 for (String packageName : packageNames) { 1373 UserPackage userPackage = new UserPackage(packageName, user); 1374 1375 if (userPackages.contains(userPackage)) { 1376 userPackages.remove(userPackage); 1377 shouldWrite = true; 1378 1379 if (userPackages.size() == 0) { 1380 mAccessoryPreferenceDeniedMap.remove(filter); 1381 break; 1382 } 1383 } 1384 } 1385 1386 if (shouldWrite) { 1387 scheduleWriteSettingsLocked(); 1388 } 1389 } 1390 } 1391 } 1392 1393 /** 1394 * Set a package as default handler for a accessory. 1395 * 1396 * @param accessory The accessory that should be handled by default 1397 * @param packageName The default handler package 1398 * @param user The user the package belongs to 1399 */ setAccessoryPackage(@onNull UsbAccessory accessory, @Nullable String packageName, @NonNull UserHandle user)1400 void setAccessoryPackage(@NonNull UsbAccessory accessory, @Nullable String packageName, 1401 @NonNull UserHandle user) { 1402 AccessoryFilter filter = new AccessoryFilter(accessory); 1403 boolean changed; 1404 synchronized (mLock) { 1405 if (packageName == null) { 1406 changed = (mAccessoryPreferenceMap.remove(filter) != null); 1407 } else { 1408 UserPackage userPackage = new UserPackage(packageName, user); 1409 1410 changed = !userPackage.equals(mAccessoryPreferenceMap.get(filter)); 1411 if (changed) { 1412 mAccessoryPreferenceMap.put(filter, userPackage); 1413 } 1414 } 1415 if (changed) { 1416 scheduleWriteSettingsLocked(); 1417 } 1418 } 1419 } 1420 1421 /** 1422 * Check if a package has is the default handler for any usb device or accessory. 1423 * 1424 * @param packageName The package name 1425 * @param user The user the package belongs to 1426 * 1427 * @return {@code true} iff the package is default for any usb device or accessory 1428 */ hasDefaults(@onNull String packageName, @NonNull UserHandle user)1429 boolean hasDefaults(@NonNull String packageName, @NonNull UserHandle user) { 1430 UserPackage userPackage = new UserPackage(packageName, user); 1431 synchronized (mLock) { 1432 if (mDevicePreferenceMap.values().contains(userPackage)) return true; 1433 return mAccessoryPreferenceMap.values().contains(userPackage); 1434 } 1435 } 1436 1437 /** 1438 * Clear defaults for a package from any preference. 1439 * 1440 * @param packageName The package to remove 1441 * @param user The user the package belongs to 1442 */ clearDefaults(@onNull String packageName, @NonNull UserHandle user)1443 void clearDefaults(@NonNull String packageName, @NonNull UserHandle user) { 1444 UserPackage userPackage = new UserPackage(packageName, user); 1445 1446 synchronized (mLock) { 1447 if (clearPackageDefaultsLocked(userPackage)) { 1448 scheduleWriteSettingsLocked(); 1449 } 1450 } 1451 } 1452 1453 /** 1454 * Clear defaults for a package from any preference (does not persist). 1455 * 1456 * @param userPackage The package to remove 1457 * 1458 * @return {@code true} iff at least one preference was cleared 1459 */ clearPackageDefaultsLocked(@onNull UserPackage userPackage)1460 private boolean clearPackageDefaultsLocked(@NonNull UserPackage userPackage) { 1461 boolean cleared = false; 1462 synchronized (mLock) { 1463 if (mDevicePreferenceMap.containsValue(userPackage)) { 1464 // make a copy of the key set to avoid ConcurrentModificationException 1465 DeviceFilter[] keys = mDevicePreferenceMap.keySet().toArray(new DeviceFilter[0]); 1466 for (int i = 0; i < keys.length; i++) { 1467 DeviceFilter key = keys[i]; 1468 if (userPackage.equals(mDevicePreferenceMap.get(key))) { 1469 mDevicePreferenceMap.remove(key); 1470 cleared = true; 1471 } 1472 } 1473 } 1474 if (mAccessoryPreferenceMap.containsValue(userPackage)) { 1475 // make a copy of the key set to avoid ConcurrentModificationException 1476 AccessoryFilter[] keys = 1477 mAccessoryPreferenceMap.keySet().toArray(new AccessoryFilter[0]); 1478 for (int i = 0; i < keys.length; i++) { 1479 AccessoryFilter key = keys[i]; 1480 if (userPackage.equals(mAccessoryPreferenceMap.get(key))) { 1481 mAccessoryPreferenceMap.remove(key); 1482 cleared = true; 1483 } 1484 } 1485 } 1486 return cleared; 1487 } 1488 } 1489 dump(@onNull DualDumpOutputStream dump, @NonNull String idName, long id)1490 public void dump(@NonNull DualDumpOutputStream dump, @NonNull String idName, long id) { 1491 long token = dump.start(idName, id); 1492 1493 synchronized (mLock) { 1494 dump.write("parent_user_id", UsbProfileGroupSettingsManagerProto.PARENT_USER_ID, 1495 mParentUser.getIdentifier()); 1496 1497 for (DeviceFilter filter : mDevicePreferenceMap.keySet()) { 1498 long devicePrefToken = dump.start("device_preferences", 1499 UsbProfileGroupSettingsManagerProto.DEVICE_PREFERENCES); 1500 1501 filter.dump(dump, "filter", UsbSettingsDevicePreferenceProto.FILTER); 1502 1503 mDevicePreferenceMap.get(filter).dump(dump, "user_package", 1504 UsbSettingsDevicePreferenceProto.USER_PACKAGE); 1505 1506 dump.end(devicePrefToken); 1507 } 1508 for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) { 1509 long accessoryPrefToken = dump.start("accessory_preferences", 1510 UsbProfileGroupSettingsManagerProto.ACCESSORY_PREFERENCES); 1511 1512 filter.dump(dump, "filter", UsbSettingsAccessoryPreferenceProto.FILTER); 1513 1514 mAccessoryPreferenceMap.get(filter).dump(dump, "user_package", 1515 UsbSettingsAccessoryPreferenceProto.USER_PACKAGE); 1516 1517 dump.end(accessoryPrefToken); 1518 } 1519 } 1520 1521 dump.end(token); 1522 } 1523 createDeviceAttachedIntent(UsbDevice device)1524 private static Intent createDeviceAttachedIntent(UsbDevice device) { 1525 Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED); 1526 intent.putExtra(UsbManager.EXTRA_DEVICE, device); 1527 intent.addFlags( 1528 Intent.FLAG_ACTIVITY_NEW_TASK | 1529 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1530 return intent; 1531 } 1532 } 1533