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