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