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