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