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