Home | History | Annotate | Download | only in usb
      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 
     62         public Lifecycle(Context context) {
     63             super(context);
     64         }
     65 
     66         @Override
     67         public void onStart() {
     68             mUsbService = new UsbService(getContext());
     69             publishBinderService(Context.USB_SERVICE, mUsbService);
     70         }
     71 
     72         @Override
     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
     82         public void onSwitchUser(int newUserId) {
     83             mUsbService.onSwitchUser(newUserId);
     84         }
     85 
     86         @Override
     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 
    113     private UsbUserSettingsManager getSettingsForUser(@UserIdInt int userIdInt) {
    114         return mSettingsManager.getSettingsForUser(userIdInt);
    115     }
    116 
    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      */
    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      */
    184     private void onStopUser(@NonNull UserHandle stoppedUser) {
    185         mSettingsManager.remove(stoppedUser);
    186     }
    187 
    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 
    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
    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      */
    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
    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
    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
    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
    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
    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
    311     public boolean hasDevicePermission(UsbDevice device) {
    312         final int userId = UserHandle.getCallingUserId();
    313         return getSettingsForUser(userId).hasPermission(device);
    314     }
    315 
    316     @Override
    317     public boolean hasAccessoryPermission(UsbAccessory accessory) {
    318         final int userId = UserHandle.getCallingUserId();
    319         return getSettingsForUser(userId).hasPermission(accessory);
    320     }
    321 
    322     @Override
    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
    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
    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
    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
    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
    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
    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
    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 
    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
    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
    415     public void denyUsbDebugging() {
    416         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
    417         mDeviceManager.denyUsbDebugging();
    418     }
    419 
    420     @Override
    421     public void clearUsbDebuggingKeys() {
    422         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
    423         mDeviceManager.clearUsbDebuggingKeys();
    424     }
    425 
    426     @Override
    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
    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
    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
    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
    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 
    684     private static final String removeLastChar(String value) {
    685         return value.substring(0, value.length() - 1);
    686     }
    687 }
    688