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