UsbDeviceManager.java revision 7d6e325b6c2030fb0880bdf2cdecc67bbd2474e1
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 if (UsbManager.USB_FUNCTION_NONE.equals(mCurrentFunctions)) { 341 mCurrentFunctions = UsbManager.USB_FUNCTION_MTP; 342 } 343 mCurrentFunctionsApplied = mCurrentFunctions.equals( 344 SystemProperties.get(USB_STATE_PROPERTY)); 345 mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(), 346 UsbManager.USB_FUNCTION_ADB); 347 setEnabledFunctions(null, false); 348 349 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); 350 updateState(state); 351 352 // register observer to listen for settings changes 353 mContentResolver.registerContentObserver( 354 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), 355 false, new AdbSettingsObserver()); 356 357 // Watch for USB configuration changes 358 mUEventObserver.startObserving(USB_STATE_MATCH); 359 mUEventObserver.startObserving(ACCESSORY_START_MATCH); 360 } catch (Exception e) { 361 Slog.e(TAG, "Error initializing UsbHandler", e); 362 } 363 } 364 365 public void sendMessage(int what, boolean arg) { 366 removeMessages(what); 367 Message m = Message.obtain(this, what); 368 m.arg1 = (arg ? 1 : 0); 369 sendMessage(m); 370 } 371 372 public void sendMessage(int what, Object arg) { 373 removeMessages(what); 374 Message m = Message.obtain(this, what); 375 m.obj = arg; 376 sendMessage(m); 377 } 378 379 public void updateState(String state) { 380 int connected, configured; 381 382 if ("DISCONNECTED".equals(state)) { 383 connected = 0; 384 configured = 0; 385 } else if ("CONNECTED".equals(state)) { 386 connected = 1; 387 configured = 0; 388 } else if ("CONFIGURED".equals(state)) { 389 connected = 1; 390 configured = 1; 391 } else { 392 Slog.e(TAG, "unknown state " + state); 393 return; 394 } 395 removeMessages(MSG_UPDATE_STATE); 396 Message msg = Message.obtain(this, MSG_UPDATE_STATE); 397 msg.arg1 = connected; 398 msg.arg2 = configured; 399 // debounce disconnects to avoid problems bringing up USB tethering 400 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); 401 } 402 403 public void updateHostState(UsbPort port, UsbPortStatus status) { 404 boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST; 405 boolean sourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE; 406 boolean sinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK; 407 408 if (DEBUG) { 409 Slog.i(TAG, "updateHostState " + port + " status=" + status); 410 } 411 412 SomeArgs args = SomeArgs.obtain(); 413 args.argi1 = hostConnected ? 1 :0; 414 args.argi2 = sourcePower ? 1 :0; 415 args.argi3 = sinkPower ? 1 :0; 416 417 obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget(); 418 } 419 420 private boolean waitForState(String state) { 421 // wait for the transition to complete. 422 // give up after 1 second. 423 String value = null; 424 for (int i = 0; i < 20; i++) { 425 // State transition is done when sys.usb.state is set to the new configuration 426 value = SystemProperties.get(USB_STATE_PROPERTY); 427 if (state.equals(value)) return true; 428 SystemClock.sleep(50); 429 } 430 Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value); 431 return false; 432 } 433 434 private boolean setUsbConfig(String config) { 435 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); 436 // set the new configuration 437 // we always set it due to b/23631400, where adbd was getting killed 438 // and not restarted due to property timeouts on some devices 439 SystemProperties.set(USB_CONFIG_PROPERTY, config); 440 return waitForState(config); 441 } 442 443 private void setUsbDataUnlocked(boolean enable) { 444 if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable); 445 mUsbDataUnlocked = enable; 446 updateUsbNotification(); 447 updateUsbStateBroadcastIfNeeded(); 448 setEnabledFunctions(mCurrentFunctions, true); 449 } 450 451 private void setAdbEnabled(boolean enable) { 452 if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable); 453 if (enable != mAdbEnabled) { 454 mAdbEnabled = enable; 455 456 // Due to the persist.sys.usb.config property trigger, changing adb state requires 457 // persisting default function 458 String oldFunctions = getDefaultFunctions(); 459 String newFunctions = applyAdbFunction(oldFunctions); 460 if (!oldFunctions.equals(newFunctions)) { 461 SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions); 462 } 463 464 // After persisting them use the lock-down aware function set 465 setEnabledFunctions(mCurrentFunctions, false); 466 updateAdbNotification(); 467 } 468 469 if (mDebuggingManager != null) { 470 mDebuggingManager.setAdbEnabled(mAdbEnabled); 471 } 472 } 473 474 /** 475 * Evaluates USB function policies and applies the change accordingly. 476 */ 477 private void setEnabledFunctions(String functions, boolean forceRestart) { 478 if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", " 479 + "forceRestart=" + forceRestart); 480 481 // Try to set the enabled functions. 482 final String oldFunctions = mCurrentFunctions; 483 final boolean oldFunctionsApplied = mCurrentFunctionsApplied; 484 if (trySetEnabledFunctions(functions, forceRestart)) { 485 return; 486 } 487 488 // Didn't work. Try to revert changes. 489 // We always reapply the policy in case certain constraints changed such as 490 // user restrictions independently of any other new functions we were 491 // trying to activate. 492 if (oldFunctionsApplied && !oldFunctions.equals(functions)) { 493 Slog.e(TAG, "Failsafe 1: Restoring previous USB functions."); 494 if (trySetEnabledFunctions(oldFunctions, false)) { 495 return; 496 } 497 } 498 499 // Still didn't work. Try to restore the default functions. 500 Slog.e(TAG, "Failsafe 2: Restoring default USB functions."); 501 if (trySetEnabledFunctions(null, false)) { 502 return; 503 } 504 505 // Now we're desperate. Ignore the default functions. 506 // Try to get ADB working if enabled. 507 Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled)."); 508 if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) { 509 return; 510 } 511 512 // Ouch. 513 Slog.e(TAG, "Unable to set any USB functions!"); 514 } 515 516 private boolean trySetEnabledFunctions(String functions, boolean forceRestart) { 517 if (functions == null) { 518 functions = getDefaultFunctions(); 519 } 520 functions = applyAdbFunction(functions); 521 functions = applyOemOverrideFunction(functions); 522 523 if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied 524 || forceRestart) { 525 Slog.i(TAG, "Setting USB config to " + functions); 526 mCurrentFunctions = functions; 527 mCurrentFunctionsApplied = false; 528 529 // Kick the USB stack to close existing connections. 530 setUsbConfig(UsbManager.USB_FUNCTION_NONE); 531 532 // Set the new USB configuration. 533 if (!setUsbConfig(functions)) { 534 Slog.e(TAG, "Failed to switch USB config to " + functions); 535 return false; 536 } 537 538 mCurrentFunctionsApplied = true; 539 } 540 return true; 541 } 542 543 private String applyAdbFunction(String functions) { 544 if (mAdbEnabled) { 545 functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB); 546 } else { 547 functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB); 548 } 549 return functions; 550 } 551 552 private boolean isUsbTransferAllowed() { 553 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 554 return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER); 555 } 556 557 private void updateCurrentAccessory() { 558 // We are entering accessory mode if we have received a request from the host 559 // and the request has not timed out yet. 560 boolean enteringAccessoryMode = 561 mAccessoryModeRequestTime > 0 && 562 SystemClock.elapsedRealtime() < 563 mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT; 564 565 if (mConfigured && enteringAccessoryMode) { 566 // successfully entered accessory mode 567 568 if (mAccessoryStrings != null) { 569 mCurrentAccessory = new UsbAccessory(mAccessoryStrings); 570 Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); 571 // defer accessoryAttached if system is not ready 572 if (mBootCompleted) { 573 getCurrentSettings().accessoryAttached(mCurrentAccessory); 574 } // else handle in boot completed 575 } else { 576 Slog.e(TAG, "nativeGetAccessoryStrings failed"); 577 } 578 } else if (!enteringAccessoryMode) { 579 // make sure accessory mode is off 580 // and restore default functions 581 Slog.d(TAG, "exited USB accessory mode"); 582 setEnabledFunctions(null, false); 583 584 if (mCurrentAccessory != null) { 585 if (mBootCompleted) { 586 getCurrentSettings().accessoryDetached(mCurrentAccessory); 587 } 588 mCurrentAccessory = null; 589 mAccessoryStrings = null; 590 } 591 } 592 } 593 594 private boolean isUsbStateChanged(Intent intent) { 595 final Set<String> keySet = intent.getExtras().keySet(); 596 if (mBroadcastedIntent == null) { 597 for (String key : keySet) { 598 if (intent.getBooleanExtra(key, false)) { 599 // MTP function is enabled by default. 600 if (UsbManager.USB_FUNCTION_MTP.equals(key)) { 601 continue; 602 } 603 return true; 604 } 605 } 606 } else { 607 if (!keySet.equals(mBroadcastedIntent.getExtras().keySet())) { 608 return true; 609 } 610 for (String key : keySet) { 611 if (intent.getBooleanExtra(key, false) != 612 mBroadcastedIntent.getBooleanExtra(key, false)) { 613 return true; 614 } 615 } 616 } 617 return false; 618 } 619 620 private void updateUsbStateBroadcastIfNeeded() { 621 // send a sticky broadcast containing current USB state 622 Intent intent = new Intent(UsbManager.ACTION_USB_STATE); 623 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 624 | Intent.FLAG_RECEIVER_FOREGROUND); 625 intent.putExtra(UsbManager.USB_CONNECTED, mConnected); 626 intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected); 627 intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); 628 intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked); 629 630 if (mCurrentFunctions != null) { 631 String[] functions = mCurrentFunctions.split(","); 632 for (int i = 0; i < functions.length; i++) { 633 final String function = functions[i]; 634 if (UsbManager.USB_FUNCTION_NONE.equals(function)) { 635 continue; 636 } 637 intent.putExtra(function, true); 638 } 639 } 640 641 // send broadcast intent only if the USB state has changed 642 if (!isUsbStateChanged(intent)) { 643 if (DEBUG) { 644 Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras()); 645 } 646 return; 647 } 648 649 if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras()); 650 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 651 mBroadcastedIntent = intent; 652 } 653 654 private void updateUsbFunctions() { 655 updateAudioSourceFunction(); 656 updateMidiFunction(); 657 } 658 659 private void updateAudioSourceFunction() { 660 boolean enabled = UsbManager.containsFunction(mCurrentFunctions, 661 UsbManager.USB_FUNCTION_AUDIO_SOURCE); 662 if (enabled != mAudioSourceEnabled) { 663 int card = -1; 664 int device = -1; 665 666 if (enabled) { 667 Scanner scanner = null; 668 try { 669 scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH)); 670 card = scanner.nextInt(); 671 device = scanner.nextInt(); 672 } catch (FileNotFoundException e) { 673 Slog.e(TAG, "could not open audio source PCM file", e); 674 } finally { 675 if (scanner != null) { 676 scanner.close(); 677 } 678 } 679 } 680 mUsbAlsaManager.setAccessoryAudioState(enabled, card, device); 681 mAudioSourceEnabled = enabled; 682 } 683 } 684 685 private void updateMidiFunction() { 686 boolean enabled = UsbManager.containsFunction(mCurrentFunctions, 687 UsbManager.USB_FUNCTION_MIDI); 688 if (enabled != mMidiEnabled) { 689 if (enabled) { 690 Scanner scanner = null; 691 try { 692 scanner = new Scanner(new File(MIDI_ALSA_PATH)); 693 mMidiCard = scanner.nextInt(); 694 mMidiDevice = scanner.nextInt(); 695 } catch (FileNotFoundException e) { 696 Slog.e(TAG, "could not open MIDI PCM file", e); 697 enabled = false; 698 } finally { 699 if (scanner != null) { 700 scanner.close(); 701 } 702 } 703 } 704 mMidiEnabled = enabled; 705 } 706 mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice); 707 } 708 709 @Override 710 public void handleMessage(Message msg) { 711 switch (msg.what) { 712 case MSG_UPDATE_STATE: 713 mConnected = (msg.arg1 == 1); 714 mConfigured = (msg.arg2 == 1); 715 if (!mConnected) { 716 // When a disconnect occurs, relock access to sensitive user data 717 mUsbDataUnlocked = false; 718 } 719 updateUsbNotification(); 720 updateAdbNotification(); 721 if (UsbManager.containsFunction(mCurrentFunctions, 722 UsbManager.USB_FUNCTION_ACCESSORY)) { 723 updateCurrentAccessory(); 724 } else if (!mConnected) { 725 // restore defaults when USB is disconnected 726 setEnabledFunctions(null, false); 727 } 728 if (mBootCompleted) { 729 updateUsbStateBroadcastIfNeeded(); 730 updateUsbFunctions(); 731 } 732 break; 733 case MSG_UPDATE_HOST_STATE: 734 SomeArgs args = (SomeArgs) msg.obj; 735 mHostConnected = (args.argi1 == 1); 736 mSourcePower = (args.argi2 == 1); 737 mSinkPower = (args.argi3 == 1); 738 args.recycle(); 739 updateUsbNotification(); 740 if (mBootCompleted) { 741 updateUsbStateBroadcastIfNeeded(); 742 } 743 break; 744 case MSG_ENABLE_ADB: 745 setAdbEnabled(msg.arg1 == 1); 746 break; 747 case MSG_SET_CURRENT_FUNCTIONS: 748 String functions = (String)msg.obj; 749 setEnabledFunctions(functions, false); 750 break; 751 case MSG_UPDATE_USER_RESTRICTIONS: 752 setEnabledFunctions(mCurrentFunctions, false); 753 break; 754 case MSG_SET_USB_DATA_UNLOCKED: 755 setUsbDataUnlocked(msg.arg1 == 1); 756 break; 757 case MSG_SYSTEM_READY: 758 updateUsbNotification(); 759 updateAdbNotification(); 760 updateUsbStateBroadcastIfNeeded(); 761 updateUsbFunctions(); 762 break; 763 case MSG_BOOT_COMPLETED: 764 mBootCompleted = true; 765 if (mCurrentAccessory != null) { 766 getCurrentSettings().accessoryAttached(mCurrentAccessory); 767 } 768 if (mDebuggingManager != null) { 769 mDebuggingManager.setAdbEnabled(mAdbEnabled); 770 } 771 break; 772 case MSG_USER_SWITCHED: { 773 if (mCurrentUser != msg.arg1) { 774 // Restart the USB stack and re-apply user restrictions for MTP or PTP. 775 final boolean active = UsbManager.containsFunction(mCurrentFunctions, 776 UsbManager.USB_FUNCTION_MTP) 777 || UsbManager.containsFunction(mCurrentFunctions, 778 UsbManager.USB_FUNCTION_PTP); 779 if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) { 780 Slog.v(TAG, "Current user switched to " + mCurrentUser 781 + "; resetting USB host stack for MTP or PTP"); 782 // avoid leaking sensitive data from previous user 783 mUsbDataUnlocked = false; 784 setEnabledFunctions(mCurrentFunctions, true); 785 } 786 mCurrentUser = msg.arg1; 787 } 788 break; 789 } 790 } 791 } 792 793 public UsbAccessory getCurrentAccessory() { 794 return mCurrentAccessory; 795 } 796 797 private void updateUsbNotification() { 798 if (mNotificationManager == null || !mUseUsbNotification 799 || ("0".equals(SystemProperties.get("persist.charging.notify")))) return; 800 int id = 0; 801 Resources r = mContext.getResources(); 802 if (mConnected) { 803 if (!mUsbDataUnlocked) { 804 if (mSourcePower) { 805 id = com.android.internal.R.string.usb_supplying_notification_title; 806 } else { 807 id = com.android.internal.R.string.usb_charging_notification_title; 808 } 809 } else if (UsbManager.containsFunction(mCurrentFunctions, 810 UsbManager.USB_FUNCTION_MTP)) { 811 id = com.android.internal.R.string.usb_mtp_notification_title; 812 } else if (UsbManager.containsFunction(mCurrentFunctions, 813 UsbManager.USB_FUNCTION_PTP)) { 814 id = com.android.internal.R.string.usb_ptp_notification_title; 815 } else if (UsbManager.containsFunction(mCurrentFunctions, 816 UsbManager.USB_FUNCTION_MIDI)) { 817 id = com.android.internal.R.string.usb_midi_notification_title; 818 } else if (UsbManager.containsFunction(mCurrentFunctions, 819 UsbManager.USB_FUNCTION_ACCESSORY)) { 820 id = com.android.internal.R.string.usb_accessory_notification_title; 821 } else if (mSourcePower) { 822 id = com.android.internal.R.string.usb_supplying_notification_title; 823 } else { 824 id = com.android.internal.R.string.usb_charging_notification_title; 825 } 826 } else if (mSourcePower) { 827 id = com.android.internal.R.string.usb_supplying_notification_title; 828 } else if (mHostConnected && mSinkPower) { 829 id = com.android.internal.R.string.usb_charging_notification_title; 830 } 831 if (id != mUsbNotificationId) { 832 // clear notification if title needs changing 833 if (mUsbNotificationId != 0) { 834 mNotificationManager.cancelAsUser(null, mUsbNotificationId, 835 UserHandle.ALL); 836 mUsbNotificationId = 0; 837 } 838 if (id != 0) { 839 CharSequence message = r.getText( 840 com.android.internal.R.string.usb_notification_message); 841 CharSequence title = r.getText(id); 842 843 Intent intent = Intent.makeRestartActivityTask( 844 new ComponentName("com.android.settings", 845 "com.android.settings.deviceinfo.UsbModeChooserActivity")); 846 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 847 intent, 0, null, UserHandle.CURRENT); 848 849 Notification notification = new Notification.Builder(mContext) 850 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) 851 .setWhen(0) 852 .setOngoing(true) 853 .setTicker(title) 854 .setDefaults(0) // please be quiet 855 .setPriority(Notification.PRIORITY_MIN) 856 .setColor(mContext.getColor( 857 com.android.internal.R.color.system_notification_accent_color)) 858 .setContentTitle(title) 859 .setContentText(message) 860 .setContentIntent(pi) 861 .setVisibility(Notification.VISIBILITY_PUBLIC) 862 .build(); 863 mNotificationManager.notifyAsUser(null, id, notification, 864 UserHandle.ALL); 865 mUsbNotificationId = id; 866 } 867 } 868 } 869 870 private void updateAdbNotification() { 871 if (mNotificationManager == null) return; 872 final int id = com.android.internal.R.string.adb_active_notification_title; 873 if (mAdbEnabled && mConnected) { 874 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return; 875 876 if (!mAdbNotificationShown) { 877 Resources r = mContext.getResources(); 878 CharSequence title = r.getText(id); 879 CharSequence message = r.getText( 880 com.android.internal.R.string.adb_active_notification_message); 881 882 Intent intent = Intent.makeRestartActivityTask( 883 new ComponentName("com.android.settings", 884 "com.android.settings.DevelopmentSettings")); 885 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 886 intent, 0, null, UserHandle.CURRENT); 887 888 Notification notification = new Notification.Builder(mContext) 889 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) 890 .setWhen(0) 891 .setOngoing(true) 892 .setTicker(title) 893 .setDefaults(0) // please be quiet 894 .setPriority(Notification.PRIORITY_DEFAULT) 895 .setColor(mContext.getColor( 896 com.android.internal.R.color.system_notification_accent_color)) 897 .setContentTitle(title) 898 .setContentText(message) 899 .setContentIntent(pi) 900 .setVisibility(Notification.VISIBILITY_PUBLIC) 901 .build(); 902 mAdbNotificationShown = true; 903 mNotificationManager.notifyAsUser(null, id, notification, 904 UserHandle.ALL); 905 } 906 } else if (mAdbNotificationShown) { 907 mAdbNotificationShown = false; 908 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL); 909 } 910 } 911 912 private String getDefaultFunctions() { 913 String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, 914 UsbManager.USB_FUNCTION_NONE); 915 if (UsbManager.USB_FUNCTION_NONE.equals(func)) { 916 func = UsbManager.USB_FUNCTION_MTP; 917 } 918 return func; 919 } 920 921 public void dump(IndentingPrintWriter pw) { 922 pw.println("USB Device State:"); 923 pw.println(" mCurrentFunctions: " + mCurrentFunctions); 924 pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied); 925 pw.println(" mConnected: " + mConnected); 926 pw.println(" mConfigured: " + mConfigured); 927 pw.println(" mUsbDataUnlocked: " + mUsbDataUnlocked); 928 pw.println(" mCurrentAccessory: " + mCurrentAccessory); 929 pw.println(" mHostConnected: " + mHostConnected); 930 pw.println(" mSourcePower: " + mSourcePower); 931 pw.println(" mSinkPower: " + mSinkPower); 932 try { 933 pw.println(" Kernel state: " 934 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); 935 pw.println(" Kernel function list: " 936 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); 937 } catch (IOException e) { 938 pw.println("IOException: " + e); 939 } 940 } 941 } 942 943 /* returns the currently attached USB accessory */ 944 public UsbAccessory getCurrentAccessory() { 945 return mHandler.getCurrentAccessory(); 946 } 947 948 /* opens the currently attached USB accessory */ 949 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 950 UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); 951 if (currentAccessory == null) { 952 throw new IllegalArgumentException("no accessory attached"); 953 } 954 if (!currentAccessory.equals(accessory)) { 955 String error = accessory.toString() 956 + " does not match current accessory " 957 + currentAccessory; 958 throw new IllegalArgumentException(error); 959 } 960 getCurrentSettings().checkPermission(accessory); 961 return nativeOpenAccessory(); 962 } 963 964 public boolean isFunctionEnabled(String function) { 965 return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function); 966 } 967 968 public void setCurrentFunctions(String functions) { 969 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")"); 970 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions); 971 } 972 973 public void setUsbDataUnlocked(boolean unlocked) { 974 if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")"); 975 mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked); 976 } 977 978 private void readOemUsbOverrideConfig() { 979 String[] configList = mContext.getResources().getStringArray( 980 com.android.internal.R.array.config_oemUsbModeOverride); 981 982 if (configList != null) { 983 for (String config: configList) { 984 String[] items = config.split(":"); 985 if (items.length == 3) { 986 if (mOemModeMap == null) { 987 mOemModeMap = new HashMap<String, List<Pair<String, String>>>(); 988 } 989 List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]); 990 if (overrideList == null) { 991 overrideList = new LinkedList<Pair<String, String>>(); 992 mOemModeMap.put(items[0], overrideList); 993 } 994 overrideList.add(new Pair<String, String>(items[1], items[2])); 995 } 996 } 997 } 998 } 999 1000 private String applyOemOverrideFunction(String usbFunctions) { 1001 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions; 1002 1003 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); 1004 1005 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode); 1006 if (overrides != null) { 1007 for (Pair<String, String> pair: overrides) { 1008 if (pair.first.equals(usbFunctions)) { 1009 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second); 1010 return pair.second; 1011 } 1012 } 1013 } 1014 // return passed in functions as is. 1015 return usbFunctions; 1016 } 1017 1018 public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { 1019 if (mDebuggingManager != null) { 1020 mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey); 1021 } 1022 } 1023 1024 public void denyUsbDebugging() { 1025 if (mDebuggingManager != null) { 1026 mDebuggingManager.denyUsbDebugging(); 1027 } 1028 } 1029 1030 public void clearUsbDebuggingKeys() { 1031 if (mDebuggingManager != null) { 1032 mDebuggingManager.clearUsbDebuggingKeys(); 1033 } else { 1034 throw new RuntimeException("Cannot clear Usb Debugging keys, " 1035 + "UsbDebuggingManager not enabled"); 1036 } 1037 } 1038 1039 public void dump(IndentingPrintWriter pw) { 1040 if (mHandler != null) { 1041 mHandler.dump(pw); 1042 } 1043 if (mDebuggingManager != null) { 1044 mDebuggingManager.dump(pw); 1045 } 1046 } 1047 1048 private native String[] nativeGetAccessoryStrings(); 1049 private native ParcelFileDescriptor nativeOpenAccessory(); 1050 private native boolean nativeIsStartRequested(); 1051 private native int nativeGetAudioMode(); 1052} 1053