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