1 /* 2 * Copyright (C) 2010 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 an 14 * limitations under the License. 15 */ 16 17 package com.android.server.usb; 18 19 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; 20 import static android.hardware.usb.UsbPortStatus.DATA_ROLE_HOST; 21 import static android.hardware.usb.UsbPortStatus.MODE_DFP; 22 import static android.hardware.usb.UsbPortStatus.MODE_DUAL; 23 import static android.hardware.usb.UsbPortStatus.MODE_UFP; 24 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; 25 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE; 26 27 import android.annotation.NonNull; 28 import android.annotation.UserIdInt; 29 import android.app.PendingIntent; 30 import android.app.admin.DevicePolicyManager; 31 import android.content.BroadcastReceiver; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.pm.PackageManager; 37 import android.hardware.usb.IUsbManager; 38 import android.hardware.usb.ParcelableUsbPort; 39 import android.hardware.usb.UsbAccessory; 40 import android.hardware.usb.UsbDevice; 41 import android.hardware.usb.UsbManager; 42 import android.hardware.usb.UsbPort; 43 import android.hardware.usb.UsbPortStatus; 44 import android.os.Binder; 45 import android.os.Bundle; 46 import android.os.ParcelFileDescriptor; 47 import android.os.UserHandle; 48 import android.os.UserManager; 49 import android.service.usb.UsbServiceDumpProto; 50 import android.util.ArraySet; 51 import android.util.Slog; 52 import android.util.proto.ProtoOutputStream; 53 54 import com.android.internal.annotations.GuardedBy; 55 import com.android.internal.util.DumpUtils; 56 import com.android.internal.util.IndentingPrintWriter; 57 import com.android.internal.util.Preconditions; 58 import com.android.internal.util.dump.DualDumpOutputStream; 59 import com.android.server.SystemService; 60 61 import java.io.File; 62 import java.io.FileDescriptor; 63 import java.io.PrintWriter; 64 import java.util.ArrayList; 65 import java.util.Collections; 66 import java.util.List; 67 68 /** 69 * UsbService manages all USB related state, including both host and device support. 70 * Host related events and calls are delegated to UsbHostManager, and device related 71 * support is delegated to UsbDeviceManager. 72 */ 73 public class UsbService extends IUsbManager.Stub { 74 75 public static class Lifecycle extends SystemService { 76 private UsbService mUsbService; 77 Lifecycle(Context context)78 public Lifecycle(Context context) { 79 super(context); 80 } 81 82 @Override onStart()83 public void onStart() { 84 mUsbService = new UsbService(getContext()); 85 publishBinderService(Context.USB_SERVICE, mUsbService); 86 } 87 88 @Override onBootPhase(int phase)89 public void onBootPhase(int phase) { 90 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { 91 mUsbService.systemReady(); 92 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { 93 mUsbService.bootCompleted(); 94 } 95 } 96 97 @Override onSwitchUser(int newUserId)98 public void onSwitchUser(int newUserId) { 99 mUsbService.onSwitchUser(newUserId); 100 } 101 102 @Override onStopUser(int userHandle)103 public void onStopUser(int userHandle) { 104 mUsbService.onStopUser(UserHandle.of(userHandle)); 105 } 106 107 @Override onUnlockUser(int userHandle)108 public void onUnlockUser(int userHandle) { 109 mUsbService.onUnlockUser(userHandle); 110 } 111 } 112 113 private static final String TAG = "UsbService"; 114 115 private final Context mContext; 116 private final UserManager mUserManager; 117 118 private UsbDeviceManager mDeviceManager; 119 private UsbHostManager mHostManager; 120 private UsbPortManager mPortManager; 121 private final UsbAlsaManager mAlsaManager; 122 123 private final UsbSettingsManager mSettingsManager; 124 125 /** 126 * The user id of the current user. There might be several profiles (with separate user ids) 127 * per user. 128 */ 129 @GuardedBy("mLock") 130 private @UserIdInt int mCurrentUserId; 131 132 private final Object mLock = new Object(); 133 getSettingsForUser(@serIdInt int userIdInt)134 private UsbUserSettingsManager getSettingsForUser(@UserIdInt int userIdInt) { 135 return mSettingsManager.getSettingsForUser(userIdInt); 136 } 137 UsbService(Context context)138 public UsbService(Context context) { 139 mContext = context; 140 141 mUserManager = context.getSystemService(UserManager.class); 142 mSettingsManager = new UsbSettingsManager(context); 143 mAlsaManager = new UsbAlsaManager(context); 144 145 final PackageManager pm = mContext.getPackageManager(); 146 if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) { 147 mHostManager = new UsbHostManager(context, mAlsaManager, mSettingsManager); 148 } 149 if (new File("/sys/class/android_usb").exists()) { 150 mDeviceManager = new UsbDeviceManager(context, mAlsaManager, mSettingsManager); 151 } 152 if (mHostManager != null || mDeviceManager != null) { 153 mPortManager = new UsbPortManager(context); 154 } 155 156 onSwitchUser(UserHandle.USER_SYSTEM); 157 158 BroadcastReceiver receiver = new BroadcastReceiver() { 159 @Override 160 public void onReceive(Context context, Intent intent) { 161 final String action = intent.getAction(); 162 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED 163 .equals(action)) { 164 if (mDeviceManager != null) { 165 mDeviceManager.updateUserRestrictions(); 166 } 167 } 168 } 169 }; 170 171 final IntentFilter filter = new IntentFilter(); 172 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 173 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 174 mContext.registerReceiver(receiver, filter, null, null); 175 } 176 177 /** 178 * Set new {@link #mCurrentUserId} and propagate it to other modules. 179 * 180 * @param newUserId The user id of the new current user. 181 */ onSwitchUser(@serIdInt int newUserId)182 private void onSwitchUser(@UserIdInt int newUserId) { 183 synchronized (mLock) { 184 mCurrentUserId = newUserId; 185 186 // The following two modules need to know about the current profile group. If they need 187 // to distinguish by profile of the user, the id has to be passed in the call to the 188 // module. 189 UsbProfileGroupSettingsManager settings = 190 mSettingsManager.getSettingsForProfileGroup(UserHandle.of(newUserId)); 191 if (mHostManager != null) { 192 mHostManager.setCurrentUserSettings(settings); 193 } 194 if (mDeviceManager != null) { 195 mDeviceManager.setCurrentUser(newUserId, settings); 196 } 197 } 198 } 199 200 /** 201 * Execute operations when a user is stopped. 202 * 203 * @param stoppedUser The user that is stopped 204 */ onStopUser(@onNull UserHandle stoppedUser)205 private void onStopUser(@NonNull UserHandle stoppedUser) { 206 mSettingsManager.remove(stoppedUser); 207 } 208 systemReady()209 public void systemReady() { 210 mAlsaManager.systemReady(); 211 212 if (mDeviceManager != null) { 213 mDeviceManager.systemReady(); 214 } 215 if (mHostManager != null) { 216 mHostManager.systemReady(); 217 } 218 if (mPortManager != null) { 219 mPortManager.systemReady(); 220 } 221 } 222 bootCompleted()223 public void bootCompleted() { 224 if (mDeviceManager != null) { 225 mDeviceManager.bootCompleted(); 226 } 227 } 228 229 /** Called when a user is unlocked. */ onUnlockUser(int user)230 public void onUnlockUser(int user) { 231 if (mDeviceManager != null) { 232 mDeviceManager.onUnlockUser(user); 233 } 234 } 235 236 /* Returns a list of all currently attached USB devices (host mdoe) */ 237 @Override getDeviceList(Bundle devices)238 public void getDeviceList(Bundle devices) { 239 if (mHostManager != null) { 240 mHostManager.getDeviceList(devices); 241 } 242 } 243 244 /* Opens the specified USB device (host mode) */ 245 @Override openDevice(String deviceName, String packageName)246 public ParcelFileDescriptor openDevice(String deviceName, String packageName) { 247 ParcelFileDescriptor fd = null; 248 249 if (mHostManager != null) { 250 if (deviceName != null) { 251 int uid = Binder.getCallingUid(); 252 int user = UserHandle.getUserId(uid); 253 254 long ident = clearCallingIdentity(); 255 try { 256 synchronized (mLock) { 257 if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) { 258 fd = mHostManager.openDevice(deviceName, getSettingsForUser(user), 259 packageName, uid); 260 } else { 261 Slog.w(TAG, "Cannot open " + deviceName + " for user " + user 262 + " as user is not active."); 263 } 264 } 265 } finally { 266 restoreCallingIdentity(ident); 267 } 268 } 269 } 270 271 return fd; 272 } 273 274 /* returns the currently attached USB accessory (device mode) */ 275 @Override getCurrentAccessory()276 public UsbAccessory getCurrentAccessory() { 277 if (mDeviceManager != null) { 278 return mDeviceManager.getCurrentAccessory(); 279 } else { 280 return null; 281 } 282 } 283 284 /* opens the currently attached USB accessory (device mode) */ 285 @Override openAccessory(UsbAccessory accessory)286 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 287 if (mDeviceManager != null) { 288 int uid = Binder.getCallingUid(); 289 int user = UserHandle.getUserId(uid); 290 291 long ident = clearCallingIdentity(); 292 try { 293 synchronized (mLock) { 294 if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) { 295 return mDeviceManager.openAccessory(accessory, getSettingsForUser(user), 296 uid); 297 } else { 298 Slog.w(TAG, "Cannot open " + accessory + " for user " + user 299 + " as user is not active."); 300 } 301 } 302 } finally { 303 restoreCallingIdentity(ident); 304 } 305 } 306 307 return null; 308 } 309 310 /* Returns a dup of the control file descriptor for the given function. */ 311 @Override getControlFd(long function)312 public ParcelFileDescriptor getControlFd(long function) { 313 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_MTP, null); 314 return mDeviceManager.getControlFd(function); 315 } 316 317 @Override setDevicePackage(UsbDevice device, String packageName, int userId)318 public void setDevicePackage(UsbDevice device, String packageName, int userId) { 319 device = Preconditions.checkNotNull(device); 320 321 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 322 323 UserHandle user = UserHandle.of(userId); 324 final long token = Binder.clearCallingIdentity(); 325 try { 326 mSettingsManager.getSettingsForProfileGroup(user).setDevicePackage(device, packageName, 327 user); 328 } finally { 329 Binder.restoreCallingIdentity(token); 330 } 331 } 332 333 @Override setAccessoryPackage(UsbAccessory accessory, String packageName, int userId)334 public void setAccessoryPackage(UsbAccessory accessory, String packageName, int userId) { 335 accessory = Preconditions.checkNotNull(accessory); 336 337 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 338 339 UserHandle user = UserHandle.of(userId); 340 341 final long token = Binder.clearCallingIdentity(); 342 try { 343 mSettingsManager.getSettingsForProfileGroup(user).setAccessoryPackage(accessory, 344 packageName, user); 345 } finally { 346 Binder.restoreCallingIdentity(token); 347 } 348 } 349 350 @Override hasDevicePermission(UsbDevice device, String packageName)351 public boolean hasDevicePermission(UsbDevice device, String packageName) { 352 final int uid = Binder.getCallingUid(); 353 final int userId = UserHandle.getUserId(uid); 354 355 final long token = Binder.clearCallingIdentity(); 356 try { 357 return getSettingsForUser(userId).hasPermission(device, packageName, uid); 358 } finally { 359 Binder.restoreCallingIdentity(token); 360 } 361 } 362 363 @Override hasAccessoryPermission(UsbAccessory accessory)364 public boolean hasAccessoryPermission(UsbAccessory accessory) { 365 final int uid = Binder.getCallingUid(); 366 final int userId = UserHandle.getUserId(uid); 367 368 final long token = Binder.clearCallingIdentity(); 369 try { 370 return getSettingsForUser(userId).hasPermission(accessory, uid); 371 } finally { 372 Binder.restoreCallingIdentity(token); 373 } 374 } 375 376 @Override requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi)377 public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) { 378 final int uid = Binder.getCallingUid(); 379 final int userId = UserHandle.getUserId(uid); 380 381 final long token = Binder.clearCallingIdentity(); 382 try { 383 getSettingsForUser(userId).requestPermission(device, packageName, pi, uid); 384 } finally { 385 Binder.restoreCallingIdentity(token); 386 } 387 } 388 389 @Override requestAccessoryPermission( UsbAccessory accessory, String packageName, PendingIntent pi)390 public void requestAccessoryPermission( 391 UsbAccessory accessory, String packageName, PendingIntent pi) { 392 final int uid = Binder.getCallingUid(); 393 final int userId = UserHandle.getUserId(uid); 394 395 final long token = Binder.clearCallingIdentity(); 396 try { 397 getSettingsForUser(userId).requestPermission(accessory, packageName, pi, uid); 398 } finally { 399 Binder.restoreCallingIdentity(token); 400 } 401 } 402 403 @Override grantDevicePermission(UsbDevice device, int uid)404 public void grantDevicePermission(UsbDevice device, int uid) { 405 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 406 final int userId = UserHandle.getUserId(uid); 407 408 final long token = Binder.clearCallingIdentity(); 409 try { 410 getSettingsForUser(userId).grantDevicePermission(device, uid); 411 } finally { 412 Binder.restoreCallingIdentity(token); 413 } 414 } 415 416 @Override grantAccessoryPermission(UsbAccessory accessory, int uid)417 public void grantAccessoryPermission(UsbAccessory accessory, int uid) { 418 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 419 final int userId = UserHandle.getUserId(uid); 420 421 final long token = Binder.clearCallingIdentity(); 422 try { 423 getSettingsForUser(userId).grantAccessoryPermission(accessory, uid); 424 } finally { 425 Binder.restoreCallingIdentity(token); 426 } 427 } 428 429 @Override hasDefaults(String packageName, int userId)430 public boolean hasDefaults(String packageName, int userId) { 431 packageName = Preconditions.checkStringNotEmpty(packageName); 432 433 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 434 435 UserHandle user = UserHandle.of(userId); 436 437 final long token = Binder.clearCallingIdentity(); 438 try { 439 return mSettingsManager.getSettingsForProfileGroup(user).hasDefaults(packageName, user); 440 } finally { 441 Binder.restoreCallingIdentity(token); 442 } 443 } 444 445 @Override clearDefaults(String packageName, int userId)446 public void clearDefaults(String packageName, int userId) { 447 packageName = Preconditions.checkStringNotEmpty(packageName); 448 449 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 450 451 UserHandle user = UserHandle.of(userId); 452 453 final long token = Binder.clearCallingIdentity(); 454 try { 455 mSettingsManager.getSettingsForProfileGroup(user).clearDefaults(packageName, user); 456 } finally { 457 Binder.restoreCallingIdentity(token); 458 } 459 } 460 461 @Override setCurrentFunctions(long functions)462 public void setCurrentFunctions(long functions) { 463 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 464 Preconditions.checkArgument(UsbManager.areSettableFunctions(functions)); 465 Preconditions.checkState(mDeviceManager != null); 466 mDeviceManager.setCurrentFunctions(functions); 467 } 468 469 @Override setCurrentFunction(String functions, boolean usbDataUnlocked)470 public void setCurrentFunction(String functions, boolean usbDataUnlocked) { 471 setCurrentFunctions(UsbManager.usbFunctionsFromString(functions)); 472 } 473 474 @Override isFunctionEnabled(String function)475 public boolean isFunctionEnabled(String function) { 476 return (getCurrentFunctions() & UsbManager.usbFunctionsFromString(function)) != 0; 477 } 478 479 @Override getCurrentFunctions()480 public long getCurrentFunctions() { 481 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 482 Preconditions.checkState(mDeviceManager != null); 483 return mDeviceManager.getCurrentFunctions(); 484 } 485 486 @Override setScreenUnlockedFunctions(long functions)487 public void setScreenUnlockedFunctions(long functions) { 488 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 489 Preconditions.checkArgument(UsbManager.areSettableFunctions(functions)); 490 Preconditions.checkState(mDeviceManager != null); 491 492 mDeviceManager.setScreenUnlockedFunctions(functions); 493 } 494 495 @Override getScreenUnlockedFunctions()496 public long getScreenUnlockedFunctions() { 497 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 498 Preconditions.checkState(mDeviceManager != null); 499 return mDeviceManager.getScreenUnlockedFunctions(); 500 } 501 502 @Override getPorts()503 public List<ParcelableUsbPort> getPorts() { 504 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 505 506 final long ident = Binder.clearCallingIdentity(); 507 try { 508 if (mPortManager == null) { 509 return null; 510 } else { 511 final UsbPort[] ports = mPortManager.getPorts(); 512 513 final int numPorts = ports.length; 514 ArrayList<ParcelableUsbPort> parcelablePorts = new ArrayList<>(); 515 for (int i = 0; i < numPorts; i++) { 516 parcelablePorts.add(ParcelableUsbPort.of(ports[i])); 517 } 518 519 return parcelablePorts; 520 } 521 522 } finally { 523 Binder.restoreCallingIdentity(ident); 524 } 525 } 526 527 @Override getPortStatus(String portId)528 public UsbPortStatus getPortStatus(String portId) { 529 Preconditions.checkNotNull(portId, "portId must not be null"); 530 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 531 532 final long ident = Binder.clearCallingIdentity(); 533 try { 534 return mPortManager != null ? mPortManager.getPortStatus(portId) : null; 535 } finally { 536 Binder.restoreCallingIdentity(ident); 537 } 538 } 539 540 @Override setPortRoles(String portId, int powerRole, int dataRole)541 public void setPortRoles(String portId, int powerRole, int dataRole) { 542 Preconditions.checkNotNull(portId, "portId must not be null"); 543 UsbPort.checkRoles(powerRole, dataRole); 544 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 545 546 final long ident = Binder.clearCallingIdentity(); 547 try { 548 if (mPortManager != null) { 549 mPortManager.setPortRoles(portId, powerRole, dataRole, null); 550 } 551 } finally { 552 Binder.restoreCallingIdentity(ident); 553 } 554 } 555 556 @Override enableContaminantDetection(String portId, boolean enable)557 public void enableContaminantDetection(String portId, boolean enable) { 558 Preconditions.checkNotNull(portId, "portId must not be null"); 559 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 560 561 final long ident = Binder.clearCallingIdentity(); 562 try { 563 if (mPortManager != null) { 564 mPortManager.enableContaminantDetection(portId, enable, null); 565 } 566 } finally { 567 Binder.restoreCallingIdentity(ident); 568 } 569 } 570 571 @Override setUsbDeviceConnectionHandler(ComponentName usbDeviceConnectionHandler)572 public void setUsbDeviceConnectionHandler(ComponentName usbDeviceConnectionHandler) { 573 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); 574 synchronized (mLock) { 575 if (mCurrentUserId == UserHandle.getCallingUserId()) { 576 if (mHostManager != null) { 577 mHostManager.setUsbDeviceConnectionHandler(usbDeviceConnectionHandler); 578 } 579 } else { 580 throw new IllegalArgumentException("Only the current user can register a usb " + 581 "connection handler"); 582 } 583 } 584 } 585 586 @Override dump(FileDescriptor fd, PrintWriter writer, String[] args)587 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 588 if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return; 589 590 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 591 final long ident = Binder.clearCallingIdentity(); 592 try { 593 ArraySet<String> argsSet = new ArraySet<>(); 594 Collections.addAll(argsSet, args); 595 596 boolean dumpAsProto = false; 597 if (argsSet.contains("--proto")) { 598 dumpAsProto = true; 599 } 600 601 if (args == null || args.length == 0 || args[0].equals("-a") || dumpAsProto) { 602 DualDumpOutputStream dump; 603 if (dumpAsProto) { 604 dump = new DualDumpOutputStream(new ProtoOutputStream(fd)); 605 } else { 606 pw.println("USB MANAGER STATE (dumpsys usb):"); 607 608 dump = new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")); 609 } 610 611 if (mDeviceManager != null) { 612 mDeviceManager.dump(dump, "device_manager", UsbServiceDumpProto.DEVICE_MANAGER); 613 } 614 if (mHostManager != null) { 615 mHostManager.dump(dump, "host_manager", UsbServiceDumpProto.HOST_MANAGER); 616 } 617 if (mPortManager != null) { 618 mPortManager.dump(dump, "port_manager", UsbServiceDumpProto.PORT_MANAGER); 619 } 620 mAlsaManager.dump(dump, "alsa_manager", UsbServiceDumpProto.ALSA_MANAGER); 621 622 mSettingsManager.dump(dump, "settings_manager", 623 UsbServiceDumpProto.SETTINGS_MANAGER); 624 dump.flush(); 625 } else if ("set-port-roles".equals(args[0]) && args.length == 4) { 626 final String portId = args[1]; 627 final int powerRole; 628 switch (args[2]) { 629 case "source": 630 powerRole = POWER_ROLE_SOURCE; 631 break; 632 case "sink": 633 powerRole = POWER_ROLE_SINK; 634 break; 635 case "no-power": 636 powerRole = 0; 637 break; 638 default: 639 pw.println("Invalid power role: " + args[2]); 640 return; 641 } 642 final int dataRole; 643 switch (args[3]) { 644 case "host": 645 dataRole = DATA_ROLE_HOST; 646 break; 647 case "device": 648 dataRole = DATA_ROLE_DEVICE; 649 break; 650 case "no-data": 651 dataRole = 0; 652 break; 653 default: 654 pw.println("Invalid data role: " + args[3]); 655 return; 656 } 657 if (mPortManager != null) { 658 mPortManager.setPortRoles(portId, powerRole, dataRole, pw); 659 // Note: It might take some time for the side-effects of this operation 660 // to be fully applied by the kernel since the driver may need to 661 // renegotiate the USB port mode. If this proves to be an issue 662 // during debugging, it might be worth adding a sleep here before 663 // dumping the new state. 664 pw.println(); 665 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 666 "", 0); 667 } 668 } else if ("add-port".equals(args[0]) && args.length == 3) { 669 final String portId = args[1]; 670 final int supportedModes; 671 switch (args[2]) { 672 case "ufp": 673 supportedModes = MODE_UFP; 674 break; 675 case "dfp": 676 supportedModes = MODE_DFP; 677 break; 678 case "dual": 679 supportedModes = MODE_DUAL; 680 break; 681 case "none": 682 supportedModes = 0; 683 break; 684 default: 685 pw.println("Invalid mode: " + args[2]); 686 return; 687 } 688 if (mPortManager != null) { 689 mPortManager.addSimulatedPort(portId, supportedModes, pw); 690 pw.println(); 691 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 692 "", 0); 693 } 694 } else if ("connect-port".equals(args[0]) && args.length == 5) { 695 final String portId = args[1]; 696 final int mode; 697 final boolean canChangeMode = args[2].endsWith("?"); 698 switch (canChangeMode ? removeLastChar(args[2]) : args[2]) { 699 case "ufp": 700 mode = MODE_UFP; 701 break; 702 case "dfp": 703 mode = MODE_DFP; 704 break; 705 default: 706 pw.println("Invalid mode: " + args[2]); 707 return; 708 } 709 final int powerRole; 710 final boolean canChangePowerRole = args[3].endsWith("?"); 711 switch (canChangePowerRole ? removeLastChar(args[3]) : args[3]) { 712 case "source": 713 powerRole = POWER_ROLE_SOURCE; 714 break; 715 case "sink": 716 powerRole = POWER_ROLE_SINK; 717 break; 718 default: 719 pw.println("Invalid power role: " + args[3]); 720 return; 721 } 722 final int dataRole; 723 final boolean canChangeDataRole = args[4].endsWith("?"); 724 switch (canChangeDataRole ? removeLastChar(args[4]) : args[4]) { 725 case "host": 726 dataRole = DATA_ROLE_HOST; 727 break; 728 case "device": 729 dataRole = DATA_ROLE_DEVICE; 730 break; 731 default: 732 pw.println("Invalid data role: " + args[4]); 733 return; 734 } 735 if (mPortManager != null) { 736 mPortManager.connectSimulatedPort(portId, mode, canChangeMode, 737 powerRole, canChangePowerRole, dataRole, canChangeDataRole, pw); 738 pw.println(); 739 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 740 "", 0); 741 } 742 } else if ("disconnect-port".equals(args[0]) && args.length == 2) { 743 final String portId = args[1]; 744 if (mPortManager != null) { 745 mPortManager.disconnectSimulatedPort(portId, pw); 746 pw.println(); 747 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 748 "", 0); 749 } 750 } else if ("remove-port".equals(args[0]) && args.length == 2) { 751 final String portId = args[1]; 752 if (mPortManager != null) { 753 mPortManager.removeSimulatedPort(portId, pw); 754 pw.println(); 755 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 756 "", 0); 757 } 758 } else if ("reset".equals(args[0]) && args.length == 1) { 759 if (mPortManager != null) { 760 mPortManager.resetSimulation(pw); 761 pw.println(); 762 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 763 "", 0); 764 } 765 } else if ("set-contaminant-status".equals(args[0]) && args.length == 3) { 766 final String portId = args[1]; 767 final Boolean wet = Boolean.parseBoolean(args[2]); 768 if (mPortManager != null) { 769 mPortManager.simulateContaminantStatus(portId, wet, pw); 770 pw.println(); 771 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 772 "", 0); 773 } 774 } else if ("ports".equals(args[0]) && args.length == 1) { 775 if (mPortManager != null) { 776 mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, " ")), 777 "", 0); 778 } 779 } else if ("dump-descriptors".equals(args[0])) { 780 mHostManager.dumpDescriptors(pw, args); 781 } else { 782 pw.println("Dump current USB state or issue command:"); 783 pw.println(" ports"); 784 pw.println(" set-port-roles <id> <source|sink|no-power> <host|device|no-data>"); 785 pw.println(" add-port <id> <ufp|dfp|dual|none>"); 786 pw.println(" connect-port <id> <ufp|dfp><?> <source|sink><?> <host|device><?>"); 787 pw.println(" (add ? suffix if mode, power role, or data role can be changed)"); 788 pw.println(" disconnect-port <id>"); 789 pw.println(" remove-port <id>"); 790 pw.println(" reset"); 791 pw.println(); 792 pw.println("Example USB type C port role switch:"); 793 pw.println(" dumpsys usb set-port-roles \"default\" source device"); 794 pw.println(); 795 pw.println("Example USB type C port simulation with full capabilities:"); 796 pw.println(" dumpsys usb add-port \"matrix\" dual"); 797 pw.println(" dumpsys usb connect-port \"matrix\" ufp? sink? device?"); 798 pw.println(" dumpsys usb ports"); 799 pw.println(" dumpsys usb disconnect-port \"matrix\""); 800 pw.println(" dumpsys usb remove-port \"matrix\""); 801 pw.println(" dumpsys usb reset"); 802 pw.println(); 803 pw.println("Example USB type C port where only power role can be changed:"); 804 pw.println(" dumpsys usb add-port \"matrix\" dual"); 805 pw.println(" dumpsys usb connect-port \"matrix\" dfp source? host"); 806 pw.println(" dumpsys usb reset"); 807 pw.println(); 808 pw.println("Example USB OTG port where id pin determines function:"); 809 pw.println(" dumpsys usb add-port \"matrix\" dual"); 810 pw.println(" dumpsys usb connect-port \"matrix\" dfp source host"); 811 pw.println(" dumpsys usb reset"); 812 pw.println(); 813 pw.println("Example USB device-only port:"); 814 pw.println(" dumpsys usb add-port \"matrix\" ufp"); 815 pw.println(" dumpsys usb connect-port \"matrix\" ufp sink device"); 816 pw.println(" dumpsys usb reset"); 817 pw.println(); 818 pw.println("Example simulate contaminant status:"); 819 pw.println(" dumpsys usb add-port \"matrix\" ufp"); 820 pw.println(" dumpsys usb set-contaminant-status \"matrix\" true"); 821 pw.println(" dumpsys usb set-contaminant-status \"matrix\" false"); 822 pw.println(); 823 pw.println("Example USB device descriptors:"); 824 pw.println(" dumpsys usb dump-descriptors -dump-short"); 825 pw.println(" dumpsys usb dump-descriptors -dump-tree"); 826 pw.println(" dumpsys usb dump-descriptors -dump-list"); 827 pw.println(" dumpsys usb dump-descriptors -dump-raw"); 828 } 829 } finally { 830 Binder.restoreCallingIdentity(ident); 831 } 832 } 833 removeLastChar(String value)834 private static String removeLastChar(String value) { 835 return value.substring(0, value.length() - 1); 836 } 837 } 838