UsbDeviceManager.java revision 541295a9a53e38bde5fea4223ed2d63e3aacf93b
1/* 2 * Copyright (C) 2011 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 17package com.android.server.usb; 18 19import android.app.Notification; 20import android.app.NotificationManager; 21import android.app.PendingIntent; 22import android.content.BroadcastReceiver; 23import android.content.ComponentName; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.pm.PackageManager; 29import android.content.res.Resources; 30import android.database.ContentObserver; 31import android.hardware.usb.UsbAccessory; 32import android.hardware.usb.UsbManager; 33import android.hardware.usb.UsbPort; 34import android.hardware.usb.UsbPortStatus; 35import android.os.FileUtils; 36import android.os.Handler; 37import android.os.Looper; 38import android.os.Message; 39import android.os.ParcelFileDescriptor; 40import android.os.SystemClock; 41import android.os.SystemProperties; 42import android.os.UEventObserver; 43import android.os.UserHandle; 44import android.os.UserManager; 45import android.os.storage.StorageManager; 46import android.os.storage.StorageVolume; 47import android.provider.Settings; 48import android.util.Pair; 49import android.util.Slog; 50 51import com.android.internal.annotations.GuardedBy; 52import com.android.internal.os.SomeArgs; 53import com.android.internal.util.IndentingPrintWriter; 54import com.android.server.FgThread; 55 56import java.io.File; 57import java.io.FileNotFoundException; 58import java.io.IOException; 59import java.util.HashMap; 60import java.util.LinkedList; 61import java.util.List; 62import java.util.Locale; 63import java.util.Map; 64import java.util.Scanner; 65import java.util.Set; 66 67/** 68 * UsbDeviceManager manages USB state in device mode. 69 */ 70public class UsbDeviceManager { 71 72 private static final String TAG = "UsbDeviceManager"; 73 private static final boolean DEBUG = false; 74 75 /** 76 * The persistent property which stores whether adb is enabled or not. 77 * May also contain vendor-specific default functions for testing purposes. 78 */ 79 private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config"; 80 81 /** 82 * The non-persistent property which stores the current USB settings. 83 */ 84 private static final String USB_CONFIG_PROPERTY = "sys.usb.config"; 85 86 /** 87 * The non-persistent property which stores the current USB actual state. 88 */ 89 private static final String USB_STATE_PROPERTY = "sys.usb.state"; 90 91 private static final String USB_STATE_MATCH = 92 "DEVPATH=/devices/virtual/android_usb/android0"; 93 private static final String ACCESSORY_START_MATCH = 94 "DEVPATH=/devices/virtual/misc/usb_accessory"; 95 private static final String FUNCTIONS_PATH = 96 "/sys/class/android_usb/android0/functions"; 97 private static final String STATE_PATH = 98 "/sys/class/android_usb/android0/state"; 99 private static final String RNDIS_ETH_ADDR_PATH = 100 "/sys/class/android_usb/android0/f_rndis/ethaddr"; 101 private static final String AUDIO_SOURCE_PCM_PATH = 102 "/sys/class/android_usb/android0/f_audio_source/pcm"; 103 private static final String MIDI_ALSA_PATH = 104 "/sys/class/android_usb/android0/f_midi/alsa"; 105 106 private static final int MSG_UPDATE_STATE = 0; 107 private static final int MSG_ENABLE_ADB = 1; 108 private static final int MSG_SET_CURRENT_FUNCTIONS = 2; 109 private static final int MSG_SYSTEM_READY = 3; 110 private static final int MSG_BOOT_COMPLETED = 4; 111 private static final int MSG_USER_SWITCHED = 5; 112 private static final int MSG_SET_USB_DATA_UNLOCKED = 6; 113 private static final int MSG_UPDATE_USER_RESTRICTIONS = 7; 114 private static final int MSG_UPDATE_HOST_STATE = 8; 115 116 private static final int AUDIO_MODE_SOURCE = 1; 117 118 // Delay for debouncing USB disconnects. 119 // We often get rapid connect/disconnect events when enabling USB functions, 120 // which need debouncing. 121 private static final int UPDATE_DELAY = 1000; 122 123 // Time we received a request to enter USB accessory mode 124 private long mAccessoryModeRequestTime = 0; 125 126 // Timeout for entering USB request mode. 127 // Request is cancelled if host does not configure device within 10 seconds. 128 private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000; 129 130 private static final String BOOT_MODE_PROPERTY = "ro.bootmode"; 131 132 private UsbHandler mHandler; 133 private boolean mBootCompleted; 134 135 private final Object mLock = new Object(); 136 137 private final Context mContext; 138 private final ContentResolver mContentResolver; 139 @GuardedBy("mLock") 140 private UsbSettingsManager mCurrentSettings; 141 private NotificationManager mNotificationManager; 142 private final boolean mHasUsbAccessory; 143 private boolean mUseUsbNotification; 144 private boolean mAdbEnabled; 145 private boolean mAudioSourceEnabled; 146 private boolean mMidiEnabled; 147 private int mMidiCard; 148 private int mMidiDevice; 149 private Map<String, List<Pair<String, String>>> mOemModeMap; 150 private String[] mAccessoryStrings; 151 private UsbDebuggingManager mDebuggingManager; 152 private final UsbAlsaManager mUsbAlsaManager; 153 private Intent mBroadcastedIntent; 154 155 private class AdbSettingsObserver extends ContentObserver { 156 public AdbSettingsObserver() { 157 super(null); 158 } 159 @Override 160 public void onChange(boolean selfChange) { 161 boolean enable = (Settings.Global.getInt(mContentResolver, 162 Settings.Global.ADB_ENABLED, 0) > 0); 163 mHandler.sendMessage(MSG_ENABLE_ADB, enable); 164 } 165 } 166 167 /* 168 * Listens for uevent messages from the kernel to monitor the USB state 169 */ 170 private final UEventObserver mUEventObserver = new UEventObserver() { 171 @Override 172 public void onUEvent(UEventObserver.UEvent event) { 173 if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString()); 174 175 String state = event.get("USB_STATE"); 176 String accessory = event.get("ACCESSORY"); 177 if (state != null) { 178 mHandler.updateState(state); 179 } else if ("START".equals(accessory)) { 180 if (DEBUG) Slog.d(TAG, "got accessory start"); 181 startAccessoryMode(); 182 } 183 } 184 }; 185 186 private final BroadcastReceiver mHostReceiver = new BroadcastReceiver() { 187 @Override 188 public void onReceive(Context context, Intent intent) { 189 UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT); 190 UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS); 191 mHandler.updateHostState(port, status); 192 } 193 }; 194 195 public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) { 196 mContext = context; 197 mUsbAlsaManager = alsaManager; 198 mContentResolver = context.getContentResolver(); 199 PackageManager pm = mContext.getPackageManager(); 200 mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); 201 initRndisAddress(); 202 203 readOemUsbOverrideConfig(); 204 205 mHandler = new UsbHandler(FgThread.get().getLooper()); 206 207 if (nativeIsStartRequested()) { 208 if (DEBUG) Slog.d(TAG, "accessory attached at boot"); 209 startAccessoryMode(); 210 } 211 212 boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false); 213 boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt")); 214 if (secureAdbEnabled && !dataEncrypted) { 215 mDebuggingManager = new UsbDebuggingManager(context); 216 } 217 mContext.registerReceiver(mHostReceiver, 218 new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED)); 219 } 220 221 private UsbSettingsManager getCurrentSettings() { 222 synchronized (mLock) { 223 return mCurrentSettings; 224 } 225 } 226 227 public void systemReady() { 228 if (DEBUG) Slog.d(TAG, "systemReady"); 229 230 mNotificationManager = (NotificationManager) 231 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 232 233 // We do not show the USB notification if the primary volume supports mass storage. 234 // The legacy mass storage UI will be used instead. 235 boolean massStorageSupported = false; 236 final StorageManager storageManager = StorageManager.from(mContext); 237 final StorageVolume primary = storageManager.getPrimaryVolume(); 238 massStorageSupported = primary != null && primary.allowMassStorage(); 239 mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean( 240 com.android.internal.R.bool.config_usbChargingMessage); 241 242 // make sure the ADB_ENABLED setting value matches the current state 243 try { 244 Settings.Global.putInt(mContentResolver, 245 Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0); 246 } catch (SecurityException e) { 247 // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed. 248 Slog.d(TAG, "ADB_ENABLED is restricted."); 249 } 250 mHandler.sendEmptyMessage(MSG_SYSTEM_READY); 251 } 252 253 public void bootCompleted() { 254 if (DEBUG) Slog.d(TAG, "boot completed"); 255 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); 256 } 257 258 public void setCurrentUser(int userId, UsbSettingsManager settings) { 259 synchronized (mLock) { 260 mCurrentSettings = settings; 261 mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget(); 262 } 263 } 264 265 public void updateUserRestrictions() { 266 mHandler.sendEmptyMessage(MSG_UPDATE_USER_RESTRICTIONS); 267 } 268 269 private void startAccessoryMode() { 270 if (!mHasUsbAccessory) return; 271 272 mAccessoryStrings = nativeGetAccessoryStrings(); 273 boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE); 274 // don't start accessory mode if our mandatory strings have not been set 275 boolean enableAccessory = (mAccessoryStrings != null && 276 mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null && 277 mAccessoryStrings[UsbAccessory.MODEL_STRING] != null); 278 String functions = null; 279 280 if (enableAccessory && enableAudio) { 281 functions = UsbManager.USB_FUNCTION_ACCESSORY + "," 282 + UsbManager.USB_FUNCTION_AUDIO_SOURCE; 283 } else if (enableAccessory) { 284 functions = UsbManager.USB_FUNCTION_ACCESSORY; 285 } else if (enableAudio) { 286 functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE; 287 } 288 289 if (functions != null) { 290 mAccessoryModeRequestTime = SystemClock.elapsedRealtime(); 291 setCurrentFunctions(functions); 292 } 293 } 294 295 private static void initRndisAddress() { 296 // configure RNDIS ethernet address based on our serial number using the same algorithm 297 // we had been previously using in kernel board files 298 final int ETH_ALEN = 6; 299 int address[] = new int[ETH_ALEN]; 300 // first byte is 0x02 to signify a locally administered address 301 address[0] = 0x02; 302 303 String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF"); 304 int serialLength = serial.length(); 305 // XOR the USB serial across the remaining 5 bytes 306 for (int i = 0; i < serialLength; i++) { 307 address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i); 308 } 309 String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", 310 address[0], address[1], address[2], address[3], address[4], address[5]); 311 try { 312 FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString); 313 } catch (IOException e) { 314 Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH); 315 } 316 } 317 318 private final class UsbHandler extends Handler { 319 320 // current USB state 321 private boolean mConnected; 322 private boolean mHostConnected; 323 private boolean mSourcePower; 324 private boolean mSinkPower; 325 private boolean mConfigured; 326 private boolean mUsbDataUnlocked; 327 private String mCurrentFunctions; 328 private boolean mCurrentFunctionsApplied; 329 private UsbAccessory mCurrentAccessory; 330 private int mUsbNotificationId; 331 private boolean mAdbNotificationShown; 332 private int mCurrentUser = UserHandle.USER_NULL; 333 334 public UsbHandler(Looper looper) { 335 super(looper); 336 try { 337 // Restore default functions. 338 mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY, 339 UsbManager.USB_FUNCTION_NONE); 340 mCurrentFunctionsApplied = mCurrentFunctions.equals( 341 SystemProperties.get(USB_STATE_PROPERTY)); 342 mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(), 343 UsbManager.USB_FUNCTION_ADB); 344 345 setEnabledFunctions(null, false); 346 347 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); 348 updateState(state); 349 350 // register observer to listen for settings changes 351 mContentResolver.registerContentObserver( 352 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), 353 false, new AdbSettingsObserver()); 354 355 // Watch for USB configuration changes 356 mUEventObserver.startObserving(USB_STATE_MATCH); 357 mUEventObserver.startObserving(ACCESSORY_START_MATCH); 358 } catch (Exception e) { 359 Slog.e(TAG, "Error initializing UsbHandler", e); 360 } 361 } 362 363 public void sendMessage(int what, boolean arg) { 364 removeMessages(what); 365 Message m = Message.obtain(this, what); 366 m.arg1 = (arg ? 1 : 0); 367 sendMessage(m); 368 } 369 370 public void sendMessage(int what, Object arg) { 371 removeMessages(what); 372 Message m = Message.obtain(this, what); 373 m.obj = arg; 374 sendMessage(m); 375 } 376 377 public void updateState(String state) { 378 int connected, configured; 379 380 if ("DISCONNECTED".equals(state)) { 381 connected = 0; 382 configured = 0; 383 } else if ("CONNECTED".equals(state)) { 384 connected = 1; 385 configured = 0; 386 } else if ("CONFIGURED".equals(state)) { 387 connected = 1; 388 configured = 1; 389 } else { 390 Slog.e(TAG, "unknown state " + state); 391 return; 392 } 393 removeMessages(MSG_UPDATE_STATE); 394 Message msg = Message.obtain(this, MSG_UPDATE_STATE); 395 msg.arg1 = connected; 396 msg.arg2 = configured; 397 // debounce disconnects to avoid problems bringing up USB tethering 398 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); 399 } 400 401 public void updateHostState(UsbPort port, UsbPortStatus status) { 402 boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST; 403 boolean sourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE; 404 boolean sinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK; 405 406 if (DEBUG) { 407 Slog.i(TAG, "updateHostState " + port + " status=" + status); 408 } 409 410 SomeArgs args = SomeArgs.obtain(); 411 args.argi1 = hostConnected ? 1 :0; 412 args.argi2 = sourcePower ? 1 :0; 413 args.argi3 = sinkPower ? 1 :0; 414 415 obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget(); 416 } 417 418 private boolean waitForState(String state) { 419 // wait for the transition to complete. 420 // give up after 1 second. 421 String value = null; 422 for (int i = 0; i < 20; i++) { 423 // State transition is done when sys.usb.state is set to the new configuration 424 value = SystemProperties.get(USB_STATE_PROPERTY); 425 if (state.equals(value)) return true; 426 SystemClock.sleep(50); 427 } 428 Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value); 429 return false; 430 } 431 432 private boolean setUsbConfig(String config) { 433 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); 434 // set the new configuration 435 // we always set it due to b/23631400, where adbd was getting killed 436 // and not restarted due to property timeouts on some devices 437 SystemProperties.set(USB_CONFIG_PROPERTY, config); 438 return waitForState(config); 439 } 440 441 private void setUsbDataUnlocked(boolean enable) { 442 if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable); 443 mUsbDataUnlocked = enable; 444 updateUsbNotification(); 445 updateUsbStateBroadcastIfNeeded(); 446 setEnabledFunctions(mCurrentFunctions, true); 447 } 448 449 private void setAdbEnabled(boolean enable) { 450 if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable); 451 if (enable != mAdbEnabled) { 452 mAdbEnabled = enable; 453 String oldFunctions = mCurrentFunctions; 454 455 // Persist the adb setting 456 String newFunction = applyAdbFunction(SystemProperties.get( 457 USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE)); 458 SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunction); 459 460 // Changing the persistent config also changes the normal 461 // config. Wait for this to happen before changing again. 462 waitForState(newFunction); 463 464 // Remove mtp from the config if file transfer is not enabled 465 if (oldFunctions.equals(UsbManager.USB_FUNCTION_MTP) && 466 !mUsbDataUnlocked && enable) { 467 oldFunctions = UsbManager.USB_FUNCTION_NONE; 468 } 469 470 setEnabledFunctions(oldFunctions, false); 471 updateAdbNotification(); 472 } 473 474 if (mDebuggingManager != null) { 475 mDebuggingManager.setAdbEnabled(mAdbEnabled); 476 } 477 } 478 479 /** 480 * Evaluates USB function policies and applies the change accordingly. 481 */ 482 private void setEnabledFunctions(String functions, boolean forceRestart) { 483 if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " 484 + "forceRestart=" + forceRestart); 485 486 // Try to set the enabled functions. 487 final String oldFunctions = mCurrentFunctions; 488 final boolean oldFunctionsApplied = mCurrentFunctionsApplied; 489 if (trySetEnabledFunctions(functions, forceRestart)) { 490 return; 491 } 492 493 // Didn't work. Try to revert changes. 494 // We always reapply the policy in case certain constraints changed such as 495 // user restrictions independently of any other new functions we were 496 // trying to activate. 497 if (oldFunctionsApplied && !oldFunctions.equals(functions)) { 498 Slog.e(TAG, "Failsafe 1: Restoring previous USB functions."); 499 if (trySetEnabledFunctions(oldFunctions, false)) { 500 return; 501 } 502 } 503 504 // Still didn't work. Try to restore the default functions. 505 Slog.e(TAG, "Failsafe 2: Restoring default USB functions."); 506 if (trySetEnabledFunctions(null, false)) { 507 return; 508 } 509 510 // Now we're desperate. Ignore the default functions. 511 // Try to get ADB working if enabled. 512 Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled)."); 513 if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) { 514 return; 515 } 516 517 // Ouch. 518 Slog.e(TAG, "Unable to set any USB functions!"); 519 } 520 521 private boolean trySetEnabledFunctions(String functions, boolean forceRestart) { 522 if (functions == null || applyAdbFunction(functions) 523 .equals(UsbManager.USB_FUNCTION_NONE)) { 524 functions = getDefaultFunctions(); 525 } 526 functions = applyAdbFunction(functions); 527 functions = applyOemOverrideFunction(functions); 528 529 if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied 530 || forceRestart) { 531 Slog.i(TAG, "Setting USB config to " + functions); 532 mCurrentFunctions = functions; 533 mCurrentFunctionsApplied = false; 534 535 // Kick the USB stack to close existing connections. 536 setUsbConfig(UsbManager.USB_FUNCTION_NONE); 537 538 // Set the new USB configuration. 539 if (!setUsbConfig(functions)) { 540 Slog.e(TAG, "Failed to switch USB config to " + functions); 541 return false; 542 } 543 544 mCurrentFunctionsApplied = true; 545 } 546 return true; 547 } 548 549 private String applyAdbFunction(String functions) { 550 if (mAdbEnabled) { 551 functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB); 552 } else { 553 functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB); 554 } 555 return functions; 556 } 557 558 private boolean isUsbTransferAllowed() { 559 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 560 return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER); 561 } 562 563 private void updateCurrentAccessory() { 564 // We are entering accessory mode if we have received a request from the host 565 // and the request has not timed out yet. 566 boolean enteringAccessoryMode = 567 mAccessoryModeRequestTime > 0 && 568 SystemClock.elapsedRealtime() < 569 mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT; 570 571 if (mConfigured && enteringAccessoryMode) { 572 // successfully entered accessory mode 573 574 if (mAccessoryStrings != null) { 575 mCurrentAccessory = new UsbAccessory(mAccessoryStrings); 576 Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); 577 // defer accessoryAttached if system is not ready 578 if (mBootCompleted) { 579 getCurrentSettings().accessoryAttached(mCurrentAccessory); 580 } // else handle in boot completed 581 } else { 582 Slog.e(TAG, "nativeGetAccessoryStrings failed"); 583 } 584 } else if (!enteringAccessoryMode) { 585 // make sure accessory mode is off 586 // and restore default functions 587 Slog.d(TAG, "exited USB accessory mode"); 588 setEnabledFunctions(null, false); 589 590 if (mCurrentAccessory != null) { 591 if (mBootCompleted) { 592 getCurrentSettings().accessoryDetached(mCurrentAccessory); 593 } 594 mCurrentAccessory = null; 595 mAccessoryStrings = null; 596 } 597 } 598 } 599 600 private boolean isUsbStateChanged(Intent intent) { 601 final Set<String> keySet = intent.getExtras().keySet(); 602 if (mBroadcastedIntent == null) { 603 for (String key : keySet) { 604 if (intent.getBooleanExtra(key, false)) { 605 return true; 606 } 607 } 608 } else { 609 if (!keySet.equals(mBroadcastedIntent.getExtras().keySet())) { 610 return true; 611 } 612 for (String key : keySet) { 613 if (intent.getBooleanExtra(key, false) != 614 mBroadcastedIntent.getBooleanExtra(key, false)) { 615 return true; 616 } 617 } 618 } 619 return false; 620 } 621 622 private void updateUsbStateBroadcastIfNeeded() { 623 // send a sticky broadcast containing current USB state 624 Intent intent = new Intent(UsbManager.ACTION_USB_STATE); 625 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 626 | Intent.FLAG_RECEIVER_FOREGROUND); 627 intent.putExtra(UsbManager.USB_CONNECTED, mConnected); 628 intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected); 629 intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); 630 intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked); 631 632 if (mCurrentFunctions != null) { 633 String[] functions = mCurrentFunctions.split(","); 634 for (int i = 0; i < functions.length; i++) { 635 final String function = functions[i]; 636 if (UsbManager.USB_FUNCTION_NONE.equals(function)) { 637 continue; 638 } 639 intent.putExtra(function, true); 640 } 641 } 642 643 // send broadcast intent only if the USB state has changed 644 if (!isUsbStateChanged(intent)) { 645 if (DEBUG) { 646 Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras()); 647 } 648 return; 649 } 650 651 if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras()); 652 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 653 mBroadcastedIntent = intent; 654 } 655 656 private void updateUsbFunctions() { 657 updateAudioSourceFunction(); 658 updateMidiFunction(); 659 } 660 661 private void updateAudioSourceFunction() { 662 boolean enabled = UsbManager.containsFunction(mCurrentFunctions, 663 UsbManager.USB_FUNCTION_AUDIO_SOURCE); 664 if (enabled != mAudioSourceEnabled) { 665 int card = -1; 666 int device = -1; 667 668 if (enabled) { 669 Scanner scanner = null; 670 try { 671 scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH)); 672 card = scanner.nextInt(); 673 device = scanner.nextInt(); 674 } catch (FileNotFoundException e) { 675 Slog.e(TAG, "could not open audio source PCM file", e); 676 } finally { 677 if (scanner != null) { 678 scanner.close(); 679 } 680 } 681 } 682 mUsbAlsaManager.setAccessoryAudioState(enabled, card, device); 683 mAudioSourceEnabled = enabled; 684 } 685 } 686 687 private void updateMidiFunction() { 688 boolean enabled = UsbManager.containsFunction(mCurrentFunctions, 689 UsbManager.USB_FUNCTION_MIDI); 690 if (enabled != mMidiEnabled) { 691 if (enabled) { 692 Scanner scanner = null; 693 try { 694 scanner = new Scanner(new File(MIDI_ALSA_PATH)); 695 mMidiCard = scanner.nextInt(); 696 mMidiDevice = scanner.nextInt(); 697 } catch (FileNotFoundException e) { 698 Slog.e(TAG, "could not open MIDI PCM file", e); 699 enabled = false; 700 } finally { 701 if (scanner != null) { 702 scanner.close(); 703 } 704 } 705 } 706 mMidiEnabled = enabled; 707 } 708 mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice); 709 } 710 711 @Override 712 public void handleMessage(Message msg) { 713 switch (msg.what) { 714 case MSG_UPDATE_STATE: 715 mConnected = (msg.arg1 == 1); 716 mConfigured = (msg.arg2 == 1); 717 if (!mConnected) { 718 // When a disconnect occurs, relock access to sensitive user data 719 mUsbDataUnlocked = false; 720 } 721 updateUsbNotification(); 722 updateAdbNotification(); 723 if (UsbManager.containsFunction(mCurrentFunctions, 724 UsbManager.USB_FUNCTION_ACCESSORY)) { 725 updateCurrentAccessory(); 726 } else if (!mConnected) { 727 // restore defaults when USB is disconnected 728 setEnabledFunctions(null, false); 729 } 730 if (mBootCompleted) { 731 updateUsbStateBroadcastIfNeeded(); 732 updateUsbFunctions(); 733 } 734 break; 735 case MSG_UPDATE_HOST_STATE: 736 SomeArgs args = (SomeArgs) msg.obj; 737 mHostConnected = (args.argi1 == 1); 738 mSourcePower = (args.argi2 == 1); 739 mSinkPower = (args.argi3 == 1); 740 args.recycle(); 741 updateUsbNotification(); 742 if (mBootCompleted) { 743 updateUsbStateBroadcastIfNeeded(); 744 } 745 break; 746 case MSG_ENABLE_ADB: 747 setAdbEnabled(msg.arg1 == 1); 748 break; 749 case MSG_SET_CURRENT_FUNCTIONS: 750 String functions = (String)msg.obj; 751 setEnabledFunctions(functions, false); 752 break; 753 case MSG_UPDATE_USER_RESTRICTIONS: 754 setEnabledFunctions(mCurrentFunctions, false); 755 break; 756 case MSG_SET_USB_DATA_UNLOCKED: 757 setUsbDataUnlocked(msg.arg1 == 1); 758 break; 759 case MSG_SYSTEM_READY: 760 updateUsbNotification(); 761 updateAdbNotification(); 762 updateUsbStateBroadcastIfNeeded(); 763 updateUsbFunctions(); 764 break; 765 case MSG_BOOT_COMPLETED: 766 mBootCompleted = true; 767 if (mCurrentAccessory != null) { 768 getCurrentSettings().accessoryAttached(mCurrentAccessory); 769 } 770 if (mDebuggingManager != null) { 771 mDebuggingManager.setAdbEnabled(mAdbEnabled); 772 } 773 break; 774 case MSG_USER_SWITCHED: { 775 if (mCurrentUser != msg.arg1) { 776 // Restart the USB stack and re-apply user restrictions for MTP or PTP. 777 final boolean active = UsbManager.containsFunction(mCurrentFunctions, 778 UsbManager.USB_FUNCTION_MTP) 779 || UsbManager.containsFunction(mCurrentFunctions, 780 UsbManager.USB_FUNCTION_PTP); 781 if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) { 782 Slog.v(TAG, "Current user switched to " + mCurrentUser 783 + "; resetting USB host stack for MTP or PTP"); 784 // avoid leaking sensitive data from previous user 785 mUsbDataUnlocked = false; 786 setEnabledFunctions(mCurrentFunctions, true); 787 } 788 mCurrentUser = msg.arg1; 789 } 790 break; 791 } 792 } 793 } 794 795 public UsbAccessory getCurrentAccessory() { 796 return mCurrentAccessory; 797 } 798 799 private void updateUsbNotification() { 800 if (mNotificationManager == null || !mUseUsbNotification 801 || ("0".equals(SystemProperties.get("persist.charging.notify")))) return; 802 int id = 0; 803 Resources r = mContext.getResources(); 804 if (mConnected) { 805 if (!mUsbDataUnlocked) { 806 if (mSourcePower) { 807 id = com.android.internal.R.string.usb_supplying_notification_title; 808 } else { 809 id = com.android.internal.R.string.usb_charging_notification_title; 810 } 811 } else if (UsbManager.containsFunction(mCurrentFunctions, 812 UsbManager.USB_FUNCTION_MTP)) { 813 id = com.android.internal.R.string.usb_mtp_notification_title; 814 } else if (UsbManager.containsFunction(mCurrentFunctions, 815 UsbManager.USB_FUNCTION_PTP)) { 816 id = com.android.internal.R.string.usb_ptp_notification_title; 817 } else if (UsbManager.containsFunction(mCurrentFunctions, 818 UsbManager.USB_FUNCTION_MIDI)) { 819 id = com.android.internal.R.string.usb_midi_notification_title; 820 } else if (UsbManager.containsFunction(mCurrentFunctions, 821 UsbManager.USB_FUNCTION_ACCESSORY)) { 822 id = com.android.internal.R.string.usb_accessory_notification_title; 823 } else if (mSourcePower) { 824 id = com.android.internal.R.string.usb_supplying_notification_title; 825 } else { 826 id = com.android.internal.R.string.usb_charging_notification_title; 827 } 828 } else if (mSourcePower) { 829 id = com.android.internal.R.string.usb_supplying_notification_title; 830 } else if (mHostConnected && mSinkPower) { 831 id = com.android.internal.R.string.usb_charging_notification_title; 832 } 833 if (id != mUsbNotificationId) { 834 // clear notification if title needs changing 835 if (mUsbNotificationId != 0) { 836 mNotificationManager.cancelAsUser(null, mUsbNotificationId, 837 UserHandle.ALL); 838 mUsbNotificationId = 0; 839 } 840 if (id != 0) { 841 CharSequence message = r.getText( 842 com.android.internal.R.string.usb_notification_message); 843 CharSequence title = r.getText(id); 844 845 Intent intent = Intent.makeRestartActivityTask( 846 new ComponentName("com.android.settings", 847 "com.android.settings.deviceinfo.UsbModeChooserActivity")); 848 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 849 intent, 0, null, UserHandle.CURRENT); 850 851 Notification notification = new Notification.Builder(mContext) 852 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) 853 .setWhen(0) 854 .setOngoing(true) 855 .setTicker(title) 856 .setDefaults(0) // please be quiet 857 .setPriority(Notification.PRIORITY_MIN) 858 .setColor(mContext.getColor( 859 com.android.internal.R.color.system_notification_accent_color)) 860 .setContentTitle(title) 861 .setContentText(message) 862 .setContentIntent(pi) 863 .setVisibility(Notification.VISIBILITY_PUBLIC) 864 .build(); 865 mNotificationManager.notifyAsUser(null, id, notification, 866 UserHandle.ALL); 867 mUsbNotificationId = id; 868 } 869 } 870 } 871 872 private void updateAdbNotification() { 873 if (mNotificationManager == null) return; 874 final int id = com.android.internal.R.string.adb_active_notification_title; 875 if (mAdbEnabled && mConnected) { 876 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return; 877 878 if (!mAdbNotificationShown) { 879 Resources r = mContext.getResources(); 880 CharSequence title = r.getText(id); 881 CharSequence message = r.getText( 882 com.android.internal.R.string.adb_active_notification_message); 883 884 Intent intent = Intent.makeRestartActivityTask( 885 new ComponentName("com.android.settings", 886 "com.android.settings.DevelopmentSettings")); 887 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 888 intent, 0, null, UserHandle.CURRENT); 889 890 Notification notification = new Notification.Builder(mContext) 891 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) 892 .setWhen(0) 893 .setOngoing(true) 894 .setTicker(title) 895 .setDefaults(0) // please be quiet 896 .setPriority(Notification.PRIORITY_DEFAULT) 897 .setColor(mContext.getColor( 898 com.android.internal.R.color.system_notification_accent_color)) 899 .setContentTitle(title) 900 .setContentText(message) 901 .setContentIntent(pi) 902 .setVisibility(Notification.VISIBILITY_PUBLIC) 903 .build(); 904 mAdbNotificationShown = true; 905 mNotificationManager.notifyAsUser(null, id, notification, 906 UserHandle.ALL); 907 } 908 } else if (mAdbNotificationShown) { 909 mAdbNotificationShown = false; 910 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL); 911 } 912 } 913 914 private String getDefaultFunctions() { 915 String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, 916 UsbManager.USB_FUNCTION_NONE); 917 if (UsbManager.USB_FUNCTION_NONE.equals(func)) { 918 func = UsbManager.USB_FUNCTION_MTP; 919 } 920 return func; 921 } 922 923 public void dump(IndentingPrintWriter pw) { 924 pw.println("USB Device State:"); 925 pw.println(" mCurrentFunctions: " + mCurrentFunctions); 926 pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied); 927 pw.println(" mConnected: " + mConnected); 928 pw.println(" mConfigured: " + mConfigured); 929 pw.println(" mUsbDataUnlocked: " + mUsbDataUnlocked); 930 pw.println(" mCurrentAccessory: " + mCurrentAccessory); 931 pw.println(" mHostConnected: " + mHostConnected); 932 pw.println(" mSourcePower: " + mSourcePower); 933 pw.println(" mSinkPower: " + mSinkPower); 934 try { 935 pw.println(" Kernel state: " 936 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); 937 pw.println(" Kernel function list: " 938 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); 939 } catch (IOException e) { 940 pw.println("IOException: " + e); 941 } 942 } 943 } 944 945 /* returns the currently attached USB accessory */ 946 public UsbAccessory getCurrentAccessory() { 947 return mHandler.getCurrentAccessory(); 948 } 949 950 /* opens the currently attached USB accessory */ 951 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 952 UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); 953 if (currentAccessory == null) { 954 throw new IllegalArgumentException("no accessory attached"); 955 } 956 if (!currentAccessory.equals(accessory)) { 957 String error = accessory.toString() 958 + " does not match current accessory " 959 + currentAccessory; 960 throw new IllegalArgumentException(error); 961 } 962 getCurrentSettings().checkPermission(accessory); 963 return nativeOpenAccessory(); 964 } 965 966 public boolean isFunctionEnabled(String function) { 967 return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function); 968 } 969 970 public void setCurrentFunctions(String functions) { 971 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")"); 972 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions); 973 } 974 975 public void setUsbDataUnlocked(boolean unlocked) { 976 if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")"); 977 mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked); 978 } 979 980 private void readOemUsbOverrideConfig() { 981 String[] configList = mContext.getResources().getStringArray( 982 com.android.internal.R.array.config_oemUsbModeOverride); 983 984 if (configList != null) { 985 for (String config: configList) { 986 String[] items = config.split(":"); 987 if (items.length == 3) { 988 if (mOemModeMap == null) { 989 mOemModeMap = new HashMap<String, List<Pair<String, String>>>(); 990 } 991 List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]); 992 if (overrideList == null) { 993 overrideList = new LinkedList<Pair<String, String>>(); 994 mOemModeMap.put(items[0], overrideList); 995 } 996 overrideList.add(new Pair<String, String>(items[1], items[2])); 997 } 998 } 999 } 1000 } 1001 1002 private String applyOemOverrideFunction(String usbFunctions) { 1003 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions; 1004 1005 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); 1006 1007 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode); 1008 if (overrides != null) { 1009 for (Pair<String, String> pair: overrides) { 1010 if (pair.first.equals(usbFunctions)) { 1011 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second); 1012 return pair.second; 1013 } 1014 } 1015 } 1016 // return passed in functions as is. 1017 return usbFunctions; 1018 } 1019 1020 public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { 1021 if (mDebuggingManager != null) { 1022 mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey); 1023 } 1024 } 1025 1026 public void denyUsbDebugging() { 1027 if (mDebuggingManager != null) { 1028 mDebuggingManager.denyUsbDebugging(); 1029 } 1030 } 1031 1032 public void clearUsbDebuggingKeys() { 1033 if (mDebuggingManager != null) { 1034 mDebuggingManager.clearUsbDebuggingKeys(); 1035 } else { 1036 throw new RuntimeException("Cannot clear Usb Debugging keys, " 1037 + "UsbDebuggingManager not enabled"); 1038 } 1039 } 1040 1041 public void dump(IndentingPrintWriter pw) { 1042 if (mHandler != null) { 1043 mHandler.dump(pw); 1044 } 1045 if (mDebuggingManager != null) { 1046 mDebuggingManager.dump(pw); 1047 } 1048 } 1049 1050 private native String[] nativeGetAccessoryStrings(); 1051 private native ParcelFileDescriptor nativeOpenAccessory(); 1052 private native boolean nativeIsStartRequested(); 1053 private native int nativeGetAudioMode(); 1054} 1055