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