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