UsbDeviceManager.java revision 8338ed00ae44635d099b530b3360e6d1f7041827
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; 237 238 // make sure the ADB_ENABLED setting value matches the current state 239 try { 240 Settings.Global.putInt(mContentResolver, 241 Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0); 242 } catch (SecurityException e) { 243 // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed. 244 Slog.d(TAG, "ADB_ENABLED is restricted."); 245 } 246 mHandler.sendEmptyMessage(MSG_SYSTEM_READY); 247 } 248 249 public void bootCompleted() { 250 if (DEBUG) Slog.d(TAG, "boot completed"); 251 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); 252 } 253 254 public void setCurrentUser(int userId, UsbSettingsManager settings) { 255 synchronized (mLock) { 256 mCurrentSettings = settings; 257 mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget(); 258 } 259 } 260 261 public void updateUserRestrictions() { 262 mHandler.sendEmptyMessage(MSG_UPDATE_USER_RESTRICTIONS); 263 } 264 265 private void startAccessoryMode() { 266 if (!mHasUsbAccessory) return; 267 268 mAccessoryStrings = nativeGetAccessoryStrings(); 269 boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE); 270 // don't start accessory mode if our mandatory strings have not been set 271 boolean enableAccessory = (mAccessoryStrings != null && 272 mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null && 273 mAccessoryStrings[UsbAccessory.MODEL_STRING] != null); 274 String functions = null; 275 276 if (enableAccessory && enableAudio) { 277 functions = UsbManager.USB_FUNCTION_ACCESSORY + "," 278 + UsbManager.USB_FUNCTION_AUDIO_SOURCE; 279 } else if (enableAccessory) { 280 functions = UsbManager.USB_FUNCTION_ACCESSORY; 281 } else if (enableAudio) { 282 functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE; 283 } 284 285 if (functions != null) { 286 mAccessoryModeRequestTime = SystemClock.elapsedRealtime(); 287 setCurrentFunctions(functions); 288 } 289 } 290 291 private static void initRndisAddress() { 292 // configure RNDIS ethernet address based on our serial number using the same algorithm 293 // we had been previously using in kernel board files 294 final int ETH_ALEN = 6; 295 int address[] = new int[ETH_ALEN]; 296 // first byte is 0x02 to signify a locally administered address 297 address[0] = 0x02; 298 299 String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF"); 300 int serialLength = serial.length(); 301 // XOR the USB serial across the remaining 5 bytes 302 for (int i = 0; i < serialLength; i++) { 303 address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i); 304 } 305 String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", 306 address[0], address[1], address[2], address[3], address[4], address[5]); 307 try { 308 FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString); 309 } catch (IOException e) { 310 Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH); 311 } 312 } 313 314 private final class UsbHandler extends Handler { 315 316 // current USB state 317 private boolean mConnected; 318 private boolean mHostConnected; 319 private boolean mConfigured; 320 private boolean mUsbDataUnlocked; 321 private String mCurrentFunctions; 322 private boolean mCurrentFunctionsApplied; 323 private UsbAccessory mCurrentAccessory; 324 private int mUsbNotificationId; 325 private boolean mAdbNotificationShown; 326 private int mCurrentUser = UserHandle.USER_NULL; 327 328 public UsbHandler(Looper looper) { 329 super(looper); 330 try { 331 // Restore default functions. 332 mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY, 333 UsbManager.USB_FUNCTION_NONE); 334 if (UsbManager.USB_FUNCTION_NONE.equals(mCurrentFunctions)) { 335 mCurrentFunctions = UsbManager.USB_FUNCTION_MTP; 336 } 337 mCurrentFunctionsApplied = mCurrentFunctions.equals( 338 SystemProperties.get(USB_STATE_PROPERTY)); 339 mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(), 340 UsbManager.USB_FUNCTION_ADB); 341 setEnabledFunctions(null, false); 342 343 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); 344 updateState(state); 345 346 // register observer to listen for settings changes 347 mContentResolver.registerContentObserver( 348 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), 349 false, new AdbSettingsObserver()); 350 351 // Watch for USB configuration changes 352 mUEventObserver.startObserving(USB_STATE_MATCH); 353 mUEventObserver.startObserving(ACCESSORY_START_MATCH); 354 } catch (Exception e) { 355 Slog.e(TAG, "Error initializing UsbHandler", e); 356 } 357 } 358 359 public void sendMessage(int what, boolean arg) { 360 removeMessages(what); 361 Message m = Message.obtain(this, what); 362 m.arg1 = (arg ? 1 : 0); 363 sendMessage(m); 364 } 365 366 public void sendMessage(int what, Object arg) { 367 removeMessages(what); 368 Message m = Message.obtain(this, what); 369 m.obj = arg; 370 sendMessage(m); 371 } 372 373 public void updateState(String state) { 374 int connected, configured; 375 376 if ("DISCONNECTED".equals(state)) { 377 connected = 0; 378 configured = 0; 379 } else if ("CONNECTED".equals(state)) { 380 connected = 1; 381 configured = 0; 382 } else if ("CONFIGURED".equals(state)) { 383 connected = 1; 384 configured = 1; 385 } else { 386 Slog.e(TAG, "unknown state " + state); 387 return; 388 } 389 removeMessages(MSG_UPDATE_STATE); 390 Message msg = Message.obtain(this, MSG_UPDATE_STATE); 391 msg.arg1 = connected; 392 msg.arg2 = configured; 393 // debounce disconnects to avoid problems bringing up USB tethering 394 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); 395 } 396 397 public void updateHostState(UsbPort port, UsbPortStatus status) { 398 boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST; 399 obtainMessage(MSG_UPDATE_HOST_STATE, hostConnected ? 1 :0, 0).sendToTarget(); 400 } 401 402 private boolean waitForState(String state) { 403 // wait for the transition to complete. 404 // give up after 1 second. 405 String value = null; 406 for (int i = 0; i < 20; i++) { 407 // State transition is done when sys.usb.state is set to the new configuration 408 value = SystemProperties.get(USB_STATE_PROPERTY); 409 if (state.equals(value)) return true; 410 SystemClock.sleep(50); 411 } 412 Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value); 413 return false; 414 } 415 416 private boolean setUsbConfig(String config) { 417 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); 418 // set the new configuration 419 String oldConfig = SystemProperties.get(USB_CONFIG_PROPERTY); 420 if (!config.equals(oldConfig)) { 421 SystemProperties.set(USB_CONFIG_PROPERTY, config); 422 } 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 setEnabledFunctions(mCurrentFunctions, true); 720 } 721 mCurrentUser = msg.arg1; 722 } 723 break; 724 } 725 } 726 } 727 728 public UsbAccessory getCurrentAccessory() { 729 return mCurrentAccessory; 730 } 731 732 private void updateUsbNotification() { 733 if (mNotificationManager == null || !mUseUsbNotification) return; 734 int id = 0; 735 Resources r = mContext.getResources(); 736 if (mConnected || mHostConnected) { 737 if (!mUsbDataUnlocked) { 738 id = com.android.internal.R.string.usb_charging_notification_title; 739 } else if (UsbManager.containsFunction(mCurrentFunctions, 740 UsbManager.USB_FUNCTION_MTP)) { 741 id = com.android.internal.R.string.usb_mtp_notification_title; 742 } else if (UsbManager.containsFunction(mCurrentFunctions, 743 UsbManager.USB_FUNCTION_PTP)) { 744 id = com.android.internal.R.string.usb_ptp_notification_title; 745 } else if (UsbManager.containsFunction(mCurrentFunctions, 746 UsbManager.USB_FUNCTION_MIDI)) { 747 id = com.android.internal.R.string.usb_midi_notification_title; 748 } else if (UsbManager.containsFunction(mCurrentFunctions, 749 UsbManager.USB_FUNCTION_ACCESSORY)) { 750 id = com.android.internal.R.string.usb_accessory_notification_title; 751 } else { 752 id = com.android.internal.R.string.usb_charging_notification_title; 753 } 754 } 755 if (id != mUsbNotificationId) { 756 // clear notification if title needs changing 757 if (mUsbNotificationId != 0) { 758 mNotificationManager.cancelAsUser(null, mUsbNotificationId, 759 UserHandle.ALL); 760 mUsbNotificationId = 0; 761 } 762 if (id != 0) { 763 CharSequence message = r.getText( 764 com.android.internal.R.string.usb_notification_message); 765 CharSequence title = r.getText(id); 766 767 Intent intent = Intent.makeRestartActivityTask( 768 new ComponentName("com.android.settings", 769 "com.android.settings.deviceinfo.UsbModeChooserActivity")); 770 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 771 intent, 0, null, UserHandle.CURRENT); 772 773 Notification notification = new Notification.Builder(mContext) 774 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) 775 .setWhen(0) 776 .setOngoing(true) 777 .setTicker(title) 778 .setDefaults(0) // please be quiet 779 .setPriority(Notification.PRIORITY_MIN) 780 .setColor(mContext.getColor( 781 com.android.internal.R.color.system_notification_accent_color)) 782 .setContentTitle(title) 783 .setContentText(message) 784 .setContentIntent(pi) 785 .setVisibility(Notification.VISIBILITY_PUBLIC) 786 .build(); 787 mNotificationManager.notifyAsUser(null, id, notification, 788 UserHandle.ALL); 789 mUsbNotificationId = id; 790 } 791 } 792 } 793 794 private void updateAdbNotification() { 795 if (mNotificationManager == null) return; 796 final int id = com.android.internal.R.string.adb_active_notification_title; 797 if (mAdbEnabled && mConnected) { 798 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return; 799 800 if (!mAdbNotificationShown) { 801 Resources r = mContext.getResources(); 802 CharSequence title = r.getText(id); 803 CharSequence message = r.getText( 804 com.android.internal.R.string.adb_active_notification_message); 805 806 Intent intent = Intent.makeRestartActivityTask( 807 new ComponentName("com.android.settings", 808 "com.android.settings.DevelopmentSettings")); 809 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 810 intent, 0, null, UserHandle.CURRENT); 811 812 Notification notification = new Notification.Builder(mContext) 813 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) 814 .setWhen(0) 815 .setOngoing(true) 816 .setTicker(title) 817 .setDefaults(0) // please be quiet 818 .setPriority(Notification.PRIORITY_LOW) 819 .setColor(mContext.getColor( 820 com.android.internal.R.color.system_notification_accent_color)) 821 .setContentTitle(title) 822 .setContentText(message) 823 .setContentIntent(pi) 824 .setVisibility(Notification.VISIBILITY_PUBLIC) 825 .build(); 826 mAdbNotificationShown = true; 827 mNotificationManager.notifyAsUser(null, id, notification, 828 UserHandle.ALL); 829 } 830 } else if (mAdbNotificationShown) { 831 mAdbNotificationShown = false; 832 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL); 833 } 834 } 835 836 private String getDefaultFunctions() { 837 String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, 838 UsbManager.USB_FUNCTION_NONE); 839 if (UsbManager.USB_FUNCTION_NONE.equals(func)) { 840 func = UsbManager.USB_FUNCTION_MTP; 841 } 842 return func; 843 } 844 845 public void dump(IndentingPrintWriter pw) { 846 pw.println("USB Device State:"); 847 pw.println(" mCurrentFunctions: " + mCurrentFunctions); 848 pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied); 849 pw.println(" mConnected: " + mConnected); 850 pw.println(" mConfigured: " + mConfigured); 851 pw.println(" mUsbDataUnlocked: " + mUsbDataUnlocked); 852 pw.println(" mCurrentAccessory: " + mCurrentAccessory); 853 try { 854 pw.println(" Kernel state: " 855 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); 856 pw.println(" Kernel function list: " 857 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); 858 } catch (IOException e) { 859 pw.println("IOException: " + e); 860 } 861 } 862 } 863 864 /* returns the currently attached USB accessory */ 865 public UsbAccessory getCurrentAccessory() { 866 return mHandler.getCurrentAccessory(); 867 } 868 869 /* opens the currently attached USB accessory */ 870 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 871 UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); 872 if (currentAccessory == null) { 873 throw new IllegalArgumentException("no accessory attached"); 874 } 875 if (!currentAccessory.equals(accessory)) { 876 String error = accessory.toString() 877 + " does not match current accessory " 878 + currentAccessory; 879 throw new IllegalArgumentException(error); 880 } 881 getCurrentSettings().checkPermission(accessory); 882 return nativeOpenAccessory(); 883 } 884 885 public boolean isFunctionEnabled(String function) { 886 return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function); 887 } 888 889 public void setCurrentFunctions(String functions) { 890 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")"); 891 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions); 892 } 893 894 public void setUsbDataUnlocked(boolean unlocked) { 895 if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")"); 896 mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked); 897 } 898 899 private void readOemUsbOverrideConfig() { 900 String[] configList = mContext.getResources().getStringArray( 901 com.android.internal.R.array.config_oemUsbModeOverride); 902 903 if (configList != null) { 904 for (String config: configList) { 905 String[] items = config.split(":"); 906 if (items.length == 3) { 907 if (mOemModeMap == null) { 908 mOemModeMap = new HashMap<String, List<Pair<String, String>>>(); 909 } 910 List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]); 911 if (overrideList == null) { 912 overrideList = new LinkedList<Pair<String, String>>(); 913 mOemModeMap.put(items[0], overrideList); 914 } 915 overrideList.add(new Pair<String, String>(items[1], items[2])); 916 } 917 } 918 } 919 } 920 921 private String applyOemOverrideFunction(String usbFunctions) { 922 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions; 923 924 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); 925 926 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode); 927 if (overrides != null) { 928 for (Pair<String, String> pair: overrides) { 929 if (pair.first.equals(usbFunctions)) { 930 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second); 931 return pair.second; 932 } 933 } 934 } 935 // return passed in functions as is. 936 return usbFunctions; 937 } 938 939 public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { 940 if (mDebuggingManager != null) { 941 mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey); 942 } 943 } 944 945 public void denyUsbDebugging() { 946 if (mDebuggingManager != null) { 947 mDebuggingManager.denyUsbDebugging(); 948 } 949 } 950 951 public void clearUsbDebuggingKeys() { 952 if (mDebuggingManager != null) { 953 mDebuggingManager.clearUsbDebuggingKeys(); 954 } else { 955 throw new RuntimeException("Cannot clear Usb Debugging keys, " 956 + "UsbDebuggingManager not enabled"); 957 } 958 } 959 960 public void dump(IndentingPrintWriter pw) { 961 if (mHandler != null) { 962 mHandler.dump(pw); 963 } 964 if (mDebuggingManager != null) { 965 mDebuggingManager.dump(pw); 966 } 967 } 968 969 private native String[] nativeGetAccessoryStrings(); 970 private native ParcelFileDescriptor nativeOpenAccessory(); 971 private native boolean nativeIsStartRequested(); 972 private native int nativeGetAudioMode(); 973} 974