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