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