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 17 package com.android.server.usb; 18 19 import android.app.Notification; 20 import android.app.NotificationManager; 21 import android.app.PendingIntent; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.pm.PackageManager; 29 import android.content.res.Resources; 30 import android.database.ContentObserver; 31 import android.hardware.usb.UsbAccessory; 32 import android.hardware.usb.UsbManager; 33 import android.os.FileUtils; 34 import android.os.Handler; 35 import android.os.HandlerThread; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.ParcelFileDescriptor; 39 import android.os.Process; 40 import android.os.SystemClock; 41 import android.os.SystemProperties; 42 import android.os.UEventObserver; 43 import android.os.UserHandle; 44 import android.os.storage.StorageManager; 45 import android.os.storage.StorageVolume; 46 import android.provider.Settings; 47 import android.util.Pair; 48 import android.util.Slog; 49 50 import com.android.internal.annotations.GuardedBy; 51 52 import java.io.File; 53 import java.io.FileDescriptor; 54 import java.io.FileNotFoundException; 55 import java.io.IOException; 56 import java.io.PrintWriter; 57 import java.util.HashMap; 58 import java.util.LinkedList; 59 import java.util.List; 60 import java.util.Map; 61 import java.util.Scanner; 62 63 /** 64 * UsbDeviceManager manages USB state in device mode. 65 */ 66 public class UsbDeviceManager { 67 68 private static final String TAG = UsbDeviceManager.class.getSimpleName(); 69 private static final boolean DEBUG = false; 70 71 private static final String USB_STATE_MATCH = 72 "DEVPATH=/devices/virtual/android_usb/android0"; 73 private static final String ACCESSORY_START_MATCH = 74 "DEVPATH=/devices/virtual/misc/usb_accessory"; 75 private static final String FUNCTIONS_PATH = 76 "/sys/class/android_usb/android0/functions"; 77 private static final String STATE_PATH = 78 "/sys/class/android_usb/android0/state"; 79 private static final String MASS_STORAGE_FILE_PATH = 80 "/sys/class/android_usb/android0/f_mass_storage/lun/file"; 81 private static final String RNDIS_ETH_ADDR_PATH = 82 "/sys/class/android_usb/android0/f_rndis/ethaddr"; 83 private static final String AUDIO_SOURCE_PCM_PATH = 84 "/sys/class/android_usb/android0/f_audio_source/pcm"; 85 86 private static final int MSG_UPDATE_STATE = 0; 87 private static final int MSG_ENABLE_ADB = 1; 88 private static final int MSG_SET_CURRENT_FUNCTIONS = 2; 89 private static final int MSG_SYSTEM_READY = 3; 90 private static final int MSG_BOOT_COMPLETED = 4; 91 private static final int MSG_USER_SWITCHED = 5; 92 93 private static final int AUDIO_MODE_NONE = 0; 94 private static final int AUDIO_MODE_SOURCE = 1; 95 96 // Delay for debouncing USB disconnects. 97 // We often get rapid connect/disconnect events when enabling USB functions, 98 // which need debouncing. 99 private static final int UPDATE_DELAY = 1000; 100 101 private static final String BOOT_MODE_PROPERTY = "ro.bootmode"; 102 103 private UsbHandler mHandler; 104 private boolean mBootCompleted; 105 106 private final Object mLock = new Object(); 107 108 private final Context mContext; 109 private final ContentResolver mContentResolver; 110 @GuardedBy("mLock") 111 private UsbSettingsManager mCurrentSettings; 112 private NotificationManager mNotificationManager; 113 private final boolean mHasUsbAccessory; 114 private boolean mUseUsbNotification; 115 private boolean mAdbEnabled; 116 private boolean mAudioSourceEnabled; 117 private Map<String, List<Pair<String, String>>> mOemModeMap; 118 private String[] mAccessoryStrings; 119 private UsbDebuggingManager mDebuggingManager; 120 121 private class AdbSettingsObserver extends ContentObserver { 122 public AdbSettingsObserver() { 123 super(null); 124 } 125 @Override 126 public void onChange(boolean selfChange) { 127 boolean enable = (Settings.Global.getInt(mContentResolver, 128 Settings.Global.ADB_ENABLED, 0) > 0); 129 mHandler.sendMessage(MSG_ENABLE_ADB, enable); 130 } 131 } 132 133 /* 134 * Listens for uevent messages from the kernel to monitor the USB state 135 */ 136 private final UEventObserver mUEventObserver = new UEventObserver() { 137 @Override 138 public void onUEvent(UEventObserver.UEvent event) { 139 if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString()); 140 141 String state = event.get("USB_STATE"); 142 String accessory = event.get("ACCESSORY"); 143 if (state != null) { 144 mHandler.updateState(state); 145 } else if ("START".equals(accessory)) { 146 if (DEBUG) Slog.d(TAG, "got accessory start"); 147 startAccessoryMode(); 148 } 149 } 150 }; 151 152 public UsbDeviceManager(Context context) { 153 mContext = context; 154 mContentResolver = context.getContentResolver(); 155 PackageManager pm = mContext.getPackageManager(); 156 mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); 157 initRndisAddress(); 158 159 readOemUsbOverrideConfig(); 160 161 // create a thread for our Handler 162 HandlerThread thread = new HandlerThread("UsbDeviceManager", 163 Process.THREAD_PRIORITY_BACKGROUND); 164 thread.start(); 165 mHandler = new UsbHandler(thread.getLooper()); 166 167 if (nativeIsStartRequested()) { 168 if (DEBUG) Slog.d(TAG, "accessory attached at boot"); 169 startAccessoryMode(); 170 } 171 172 boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false); 173 boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt")); 174 if (secureAdbEnabled && !dataEncrypted) { 175 mDebuggingManager = new UsbDebuggingManager(context); 176 } 177 } 178 179 public void setCurrentSettings(UsbSettingsManager settings) { 180 synchronized (mLock) { 181 mCurrentSettings = settings; 182 } 183 } 184 185 private UsbSettingsManager getCurrentSettings() { 186 synchronized (mLock) { 187 return mCurrentSettings; 188 } 189 } 190 191 public void systemReady() { 192 if (DEBUG) Slog.d(TAG, "systemReady"); 193 194 mNotificationManager = (NotificationManager) 195 mContext.getSystemService(Context.NOTIFICATION_SERVICE); 196 197 // We do not show the USB notification if the primary volume supports mass storage. 198 // The legacy mass storage UI will be used instead. 199 boolean massStorageSupported = false; 200 final StorageManager storageManager = StorageManager.from(mContext); 201 final StorageVolume primary = storageManager.getPrimaryVolume(); 202 massStorageSupported = primary != null && primary.allowMassStorage(); 203 mUseUsbNotification = !massStorageSupported; 204 205 // make sure the ADB_ENABLED setting value matches the current state 206 Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0); 207 208 mHandler.sendEmptyMessage(MSG_SYSTEM_READY); 209 } 210 211 private void startAccessoryMode() { 212 mAccessoryStrings = nativeGetAccessoryStrings(); 213 boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE); 214 // don't start accessory mode if our mandatory strings have not been set 215 boolean enableAccessory = (mAccessoryStrings != null && 216 mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null && 217 mAccessoryStrings[UsbAccessory.MODEL_STRING] != null); 218 String functions = null; 219 220 if (enableAccessory && enableAudio) { 221 functions = UsbManager.USB_FUNCTION_ACCESSORY + "," 222 + UsbManager.USB_FUNCTION_AUDIO_SOURCE; 223 } else if (enableAccessory) { 224 functions = UsbManager.USB_FUNCTION_ACCESSORY; 225 } else if (enableAudio) { 226 functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE; 227 } 228 229 if (functions != null) { 230 setCurrentFunctions(functions, false); 231 } 232 } 233 234 private static void initRndisAddress() { 235 // configure RNDIS ethernet address based on our serial number using the same algorithm 236 // we had been previously using in kernel board files 237 final int ETH_ALEN = 6; 238 int address[] = new int[ETH_ALEN]; 239 // first byte is 0x02 to signify a locally administered address 240 address[0] = 0x02; 241 242 String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF"); 243 int serialLength = serial.length(); 244 // XOR the USB serial across the remaining 5 bytes 245 for (int i = 0; i < serialLength; i++) { 246 address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i); 247 } 248 String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X", 249 address[0], address[1], address[2], address[3], address[4], address[5]); 250 try { 251 FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString); 252 } catch (IOException e) { 253 Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH); 254 } 255 } 256 257 private static String addFunction(String functions, String function) { 258 if ("none".equals(functions)) { 259 return function; 260 } 261 if (!containsFunction(functions, function)) { 262 if (functions.length() > 0) { 263 functions += ","; 264 } 265 functions += function; 266 } 267 return functions; 268 } 269 270 private static String removeFunction(String functions, String function) { 271 String[] split = functions.split(","); 272 for (int i = 0; i < split.length; i++) { 273 if (function.equals(split[i])) { 274 split[i] = null; 275 } 276 } 277 if (split.length == 1 && split[0] == null) { 278 return "none"; 279 } 280 StringBuilder builder = new StringBuilder(); 281 for (int i = 0; i < split.length; i++) { 282 String s = split[i]; 283 if (s != null) { 284 if (builder.length() > 0) { 285 builder.append(","); 286 } 287 builder.append(s); 288 } 289 } 290 return builder.toString(); 291 } 292 293 private static boolean containsFunction(String functions, String function) { 294 int index = functions.indexOf(function); 295 if (index < 0) return false; 296 if (index > 0 && functions.charAt(index - 1) != ',') return false; 297 int charAfter = index + function.length(); 298 if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false; 299 return true; 300 } 301 302 private final class UsbHandler extends Handler { 303 304 // current USB state 305 private boolean mConnected; 306 private boolean mConfigured; 307 private String mCurrentFunctions; 308 private String mDefaultFunctions; 309 private UsbAccessory mCurrentAccessory; 310 private int mUsbNotificationId; 311 private boolean mAdbNotificationShown; 312 private int mCurrentUser = UserHandle.USER_NULL; 313 314 private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { 315 @Override 316 public void onReceive(Context context, Intent intent) { 317 if (DEBUG) Slog.d(TAG, "boot completed"); 318 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); 319 } 320 }; 321 322 private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() { 323 @Override 324 public void onReceive(Context context, Intent intent) { 325 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 326 mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget(); 327 } 328 }; 329 330 public UsbHandler(Looper looper) { 331 super(looper); 332 try { 333 // persist.sys.usb.config should never be unset. But if it is, set it to "adb" 334 // so we have a chance of debugging what happened. 335 mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb"); 336 337 // Check if USB mode needs to be overridden depending on OEM specific bootmode. 338 mDefaultFunctions = processOemUsbOverride(mDefaultFunctions); 339 340 // sanity check the sys.usb.config system property 341 // this may be necessary if we crashed while switching USB configurations 342 String config = SystemProperties.get("sys.usb.config", "none"); 343 if (!config.equals(mDefaultFunctions)) { 344 Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions); 345 SystemProperties.set("sys.usb.config", mDefaultFunctions); 346 } 347 348 mCurrentFunctions = mDefaultFunctions; 349 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim(); 350 updateState(state); 351 mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB); 352 353 // Upgrade step for previous versions that used persist.service.adb.enable 354 String value = SystemProperties.get("persist.service.adb.enable", ""); 355 if (value.length() > 0) { 356 char enable = value.charAt(0); 357 if (enable == '1') { 358 setAdbEnabled(true); 359 } else if (enable == '0') { 360 setAdbEnabled(false); 361 } 362 SystemProperties.set("persist.service.adb.enable", ""); 363 } 364 365 // register observer to listen for settings changes 366 mContentResolver.registerContentObserver( 367 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED), 368 false, new AdbSettingsObserver()); 369 370 // Watch for USB configuration changes 371 mUEventObserver.startObserving(USB_STATE_MATCH); 372 mUEventObserver.startObserving(ACCESSORY_START_MATCH); 373 374 mContext.registerReceiver( 375 mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); 376 mContext.registerReceiver( 377 mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED)); 378 } catch (Exception e) { 379 Slog.e(TAG, "Error initializing UsbHandler", e); 380 } 381 } 382 383 public void sendMessage(int what, boolean arg) { 384 removeMessages(what); 385 Message m = Message.obtain(this, what); 386 m.arg1 = (arg ? 1 : 0); 387 sendMessage(m); 388 } 389 390 public void sendMessage(int what, Object arg) { 391 removeMessages(what); 392 Message m = Message.obtain(this, what); 393 m.obj = arg; 394 sendMessage(m); 395 } 396 397 public void sendMessage(int what, Object arg0, boolean arg1) { 398 removeMessages(what); 399 Message m = Message.obtain(this, what); 400 m.obj = arg0; 401 m.arg1 = (arg1 ? 1 : 0); 402 sendMessage(m); 403 } 404 405 public void updateState(String state) { 406 int connected, configured; 407 408 if ("DISCONNECTED".equals(state)) { 409 connected = 0; 410 configured = 0; 411 } else if ("CONNECTED".equals(state)) { 412 connected = 1; 413 configured = 0; 414 } else if ("CONFIGURED".equals(state)) { 415 connected = 1; 416 configured = 1; 417 } else { 418 Slog.e(TAG, "unknown state " + state); 419 return; 420 } 421 removeMessages(MSG_UPDATE_STATE); 422 Message msg = Message.obtain(this, MSG_UPDATE_STATE); 423 msg.arg1 = connected; 424 msg.arg2 = configured; 425 // debounce disconnects to avoid problems bringing up USB tethering 426 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0); 427 } 428 429 private boolean waitForState(String state) { 430 // wait for the transition to complete. 431 // give up after 1 second. 432 for (int i = 0; i < 20; i++) { 433 // State transition is done when sys.usb.state is set to the new configuration 434 if (state.equals(SystemProperties.get("sys.usb.state"))) return true; 435 SystemClock.sleep(50); 436 } 437 Slog.e(TAG, "waitForState(" + state + ") FAILED"); 438 return false; 439 } 440 441 private boolean setUsbConfig(String config) { 442 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")"); 443 // set the new configuration 444 SystemProperties.set("sys.usb.config", config); 445 return waitForState(config); 446 } 447 448 private void setAdbEnabled(boolean enable) { 449 if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable); 450 if (enable != mAdbEnabled) { 451 mAdbEnabled = enable; 452 // Due to the persist.sys.usb.config property trigger, changing adb state requires 453 // switching to default function 454 setEnabledFunctions(mDefaultFunctions, true); 455 updateAdbNotification(); 456 } 457 if (mDebuggingManager != null) { 458 mDebuggingManager.setAdbEnabled(mAdbEnabled); 459 } 460 } 461 462 private void setEnabledFunctions(String functions, boolean makeDefault) { 463 464 // Do not update persystent.sys.usb.config if the device is booted up 465 // with OEM specific mode. 466 if (functions != null && makeDefault && !needsOemUsbOverride()) { 467 468 if (mAdbEnabled) { 469 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); 470 } else { 471 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); 472 } 473 if (!mDefaultFunctions.equals(functions)) { 474 if (!setUsbConfig("none")) { 475 Slog.e(TAG, "Failed to disable USB"); 476 // revert to previous configuration if we fail 477 setUsbConfig(mCurrentFunctions); 478 return; 479 } 480 // setting this property will also change the current USB state 481 // via a property trigger 482 SystemProperties.set("persist.sys.usb.config", functions); 483 if (waitForState(functions)) { 484 mCurrentFunctions = functions; 485 mDefaultFunctions = functions; 486 } else { 487 Slog.e(TAG, "Failed to switch persistent USB config to " + functions); 488 // revert to previous configuration if we fail 489 SystemProperties.set("persist.sys.usb.config", mDefaultFunctions); 490 } 491 } 492 } else { 493 if (functions == null) { 494 functions = mDefaultFunctions; 495 } 496 497 // Override with bootmode specific usb mode if needed 498 functions = processOemUsbOverride(functions); 499 500 if (mAdbEnabled) { 501 functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB); 502 } else { 503 functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB); 504 } 505 if (!mCurrentFunctions.equals(functions)) { 506 if (!setUsbConfig("none")) { 507 Slog.e(TAG, "Failed to disable USB"); 508 // revert to previous configuration if we fail 509 setUsbConfig(mCurrentFunctions); 510 return; 511 } 512 if (setUsbConfig(functions)) { 513 mCurrentFunctions = functions; 514 } else { 515 Slog.e(TAG, "Failed to switch USB config to " + functions); 516 // revert to previous configuration if we fail 517 setUsbConfig(mCurrentFunctions); 518 } 519 } 520 } 521 } 522 523 private void updateCurrentAccessory() { 524 if (!mHasUsbAccessory) return; 525 526 if (mConfigured) { 527 if (mAccessoryStrings != null) { 528 mCurrentAccessory = new UsbAccessory(mAccessoryStrings); 529 Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); 530 // defer accessoryAttached if system is not ready 531 if (mBootCompleted) { 532 getCurrentSettings().accessoryAttached(mCurrentAccessory); 533 } // else handle in mBootCompletedReceiver 534 } else { 535 Slog.e(TAG, "nativeGetAccessoryStrings failed"); 536 } 537 } else if (!mConnected) { 538 // make sure accessory mode is off 539 // and restore default functions 540 Slog.d(TAG, "exited USB accessory mode"); 541 setEnabledFunctions(mDefaultFunctions, false); 542 543 if (mCurrentAccessory != null) { 544 if (mBootCompleted) { 545 getCurrentSettings().accessoryDetached(mCurrentAccessory); 546 } 547 mCurrentAccessory = null; 548 mAccessoryStrings = null; 549 } 550 } 551 } 552 553 private void updateUsbState() { 554 // send a sticky broadcast containing current USB state 555 Intent intent = new Intent(UsbManager.ACTION_USB_STATE); 556 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 557 intent.putExtra(UsbManager.USB_CONNECTED, mConnected); 558 intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured); 559 560 if (mCurrentFunctions != null) { 561 String[] functions = mCurrentFunctions.split(","); 562 for (int i = 0; i < functions.length; i++) { 563 intent.putExtra(functions[i], true); 564 } 565 } 566 567 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 568 } 569 570 private void updateAudioSourceFunction() { 571 boolean enabled = containsFunction(mCurrentFunctions, 572 UsbManager.USB_FUNCTION_AUDIO_SOURCE); 573 if (enabled != mAudioSourceEnabled) { 574 // send a sticky broadcast containing current USB state 575 Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 576 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 577 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 578 intent.putExtra("state", (enabled ? 1 : 0)); 579 if (enabled) { 580 try { 581 Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH)); 582 int card = scanner.nextInt(); 583 int device = scanner.nextInt(); 584 intent.putExtra("card", card); 585 intent.putExtra("device", device); 586 } catch (FileNotFoundException e) { 587 Slog.e(TAG, "could not open audio source PCM file", e); 588 } 589 } 590 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 591 mAudioSourceEnabled = enabled; 592 } 593 } 594 595 @Override 596 public void handleMessage(Message msg) { 597 switch (msg.what) { 598 case MSG_UPDATE_STATE: 599 mConnected = (msg.arg1 == 1); 600 mConfigured = (msg.arg2 == 1); 601 updateUsbNotification(); 602 updateAdbNotification(); 603 if (containsFunction(mCurrentFunctions, 604 UsbManager.USB_FUNCTION_ACCESSORY)) { 605 updateCurrentAccessory(); 606 } 607 608 if (!mConnected) { 609 // restore defaults when USB is disconnected 610 setEnabledFunctions(mDefaultFunctions, false); 611 } 612 if (mBootCompleted) { 613 updateUsbState(); 614 updateAudioSourceFunction(); 615 } 616 break; 617 case MSG_ENABLE_ADB: 618 setAdbEnabled(msg.arg1 == 1); 619 break; 620 case MSG_SET_CURRENT_FUNCTIONS: 621 String functions = (String)msg.obj; 622 boolean makeDefault = (msg.arg1 == 1); 623 setEnabledFunctions(functions, makeDefault); 624 break; 625 case MSG_SYSTEM_READY: 626 updateUsbNotification(); 627 updateAdbNotification(); 628 updateUsbState(); 629 updateAudioSourceFunction(); 630 break; 631 case MSG_BOOT_COMPLETED: 632 mBootCompleted = true; 633 if (mCurrentAccessory != null) { 634 getCurrentSettings().accessoryAttached(mCurrentAccessory); 635 } 636 if (mDebuggingManager != null) { 637 mDebuggingManager.setAdbEnabled(mAdbEnabled); 638 } 639 break; 640 case MSG_USER_SWITCHED: { 641 final boolean mtpActive = 642 containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP) 643 || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP); 644 if (mtpActive && mCurrentUser != UserHandle.USER_NULL) { 645 Slog.v(TAG, "Current user switched; resetting USB host stack for MTP"); 646 setUsbConfig("none"); 647 setUsbConfig(mCurrentFunctions); 648 } 649 mCurrentUser = msg.arg1; 650 break; 651 } 652 } 653 } 654 655 public UsbAccessory getCurrentAccessory() { 656 return mCurrentAccessory; 657 } 658 659 private void updateUsbNotification() { 660 if (mNotificationManager == null || !mUseUsbNotification) return; 661 int id = 0; 662 Resources r = mContext.getResources(); 663 if (mConnected) { 664 if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) { 665 id = com.android.internal.R.string.usb_mtp_notification_title; 666 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) { 667 id = com.android.internal.R.string.usb_ptp_notification_title; 668 } else if (containsFunction(mCurrentFunctions, 669 UsbManager.USB_FUNCTION_MASS_STORAGE)) { 670 id = com.android.internal.R.string.usb_cd_installer_notification_title; 671 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { 672 id = com.android.internal.R.string.usb_accessory_notification_title; 673 } else { 674 // There is a different notification for USB tethering so we don't need one here 675 //if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) { 676 // Slog.e(TAG, "No known USB function in updateUsbNotification"); 677 //} 678 } 679 } 680 if (id != mUsbNotificationId) { 681 // clear notification if title needs changing 682 if (mUsbNotificationId != 0) { 683 mNotificationManager.cancelAsUser(null, mUsbNotificationId, 684 UserHandle.ALL); 685 mUsbNotificationId = 0; 686 } 687 if (id != 0) { 688 CharSequence message = r.getText( 689 com.android.internal.R.string.usb_notification_message); 690 CharSequence title = r.getText(id); 691 692 Notification notification = new Notification(); 693 notification.icon = com.android.internal.R.drawable.stat_sys_data_usb; 694 notification.when = 0; 695 notification.flags = Notification.FLAG_ONGOING_EVENT; 696 notification.tickerText = title; 697 notification.defaults = 0; // please be quiet 698 notification.sound = null; 699 notification.vibrate = null; 700 notification.priority = Notification.PRIORITY_MIN; 701 702 Intent intent = Intent.makeRestartActivityTask( 703 new ComponentName("com.android.settings", 704 "com.android.settings.UsbSettings")); 705 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 706 intent, 0, null, UserHandle.CURRENT); 707 notification.setLatestEventInfo(mContext, title, message, pi); 708 mNotificationManager.notifyAsUser(null, id, notification, 709 UserHandle.ALL); 710 mUsbNotificationId = id; 711 } 712 } 713 } 714 715 private void updateAdbNotification() { 716 if (mNotificationManager == null) return; 717 final int id = com.android.internal.R.string.adb_active_notification_title; 718 if (mAdbEnabled && mConnected) { 719 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return; 720 721 if (!mAdbNotificationShown) { 722 Resources r = mContext.getResources(); 723 CharSequence title = r.getText(id); 724 CharSequence message = r.getText( 725 com.android.internal.R.string.adb_active_notification_message); 726 727 Notification notification = new Notification(); 728 notification.icon = com.android.internal.R.drawable.stat_sys_adb; 729 notification.when = 0; 730 notification.flags = Notification.FLAG_ONGOING_EVENT; 731 notification.tickerText = title; 732 notification.defaults = 0; // please be quiet 733 notification.sound = null; 734 notification.vibrate = null; 735 notification.priority = Notification.PRIORITY_LOW; 736 737 Intent intent = Intent.makeRestartActivityTask( 738 new ComponentName("com.android.settings", 739 "com.android.settings.DevelopmentSettings")); 740 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0, 741 intent, 0, null, UserHandle.CURRENT); 742 notification.setLatestEventInfo(mContext, title, message, pi); 743 mAdbNotificationShown = true; 744 mNotificationManager.notifyAsUser(null, id, notification, 745 UserHandle.ALL); 746 } 747 } else if (mAdbNotificationShown) { 748 mAdbNotificationShown = false; 749 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL); 750 } 751 } 752 753 public void dump(FileDescriptor fd, PrintWriter pw) { 754 pw.println(" USB Device State:"); 755 pw.println(" Current Functions: " + mCurrentFunctions); 756 pw.println(" Default Functions: " + mDefaultFunctions); 757 pw.println(" mConnected: " + mConnected); 758 pw.println(" mConfigured: " + mConfigured); 759 pw.println(" mCurrentAccessory: " + mCurrentAccessory); 760 try { 761 pw.println(" Kernel state: " 762 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); 763 pw.println(" Kernel function list: " 764 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); 765 pw.println(" Mass storage backing file: " 766 + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim()); 767 } catch (IOException e) { 768 pw.println("IOException: " + e); 769 } 770 } 771 } 772 773 /* returns the currently attached USB accessory */ 774 public UsbAccessory getCurrentAccessory() { 775 return mHandler.getCurrentAccessory(); 776 } 777 778 /* opens the currently attached USB accessory */ 779 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { 780 UsbAccessory currentAccessory = mHandler.getCurrentAccessory(); 781 if (currentAccessory == null) { 782 throw new IllegalArgumentException("no accessory attached"); 783 } 784 if (!currentAccessory.equals(accessory)) { 785 String error = accessory.toString() 786 + " does not match current accessory " 787 + currentAccessory; 788 throw new IllegalArgumentException(error); 789 } 790 getCurrentSettings().checkPermission(accessory); 791 return nativeOpenAccessory(); 792 } 793 794 public void setCurrentFunctions(String functions, boolean makeDefault) { 795 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault); 796 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault); 797 } 798 799 public void setMassStorageBackingFile(String path) { 800 if (path == null) path = ""; 801 try { 802 FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path); 803 } catch (IOException e) { 804 Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH); 805 } 806 } 807 808 private void readOemUsbOverrideConfig() { 809 String[] configList = mContext.getResources().getStringArray( 810 com.android.internal.R.array.config_oemUsbModeOverride); 811 812 if (configList != null) { 813 for (String config: configList) { 814 String[] items = config.split(":"); 815 if (items.length == 3) { 816 if (mOemModeMap == null) { 817 mOemModeMap = new HashMap<String, List<Pair<String, String>>>(); 818 } 819 List overrideList = mOemModeMap.get(items[0]); 820 if (overrideList == null) { 821 overrideList = new LinkedList<Pair<String, String>>(); 822 mOemModeMap.put(items[0], overrideList); 823 } 824 overrideList.add(new Pair<String, String>(items[1], items[2])); 825 } 826 } 827 } 828 } 829 830 private boolean needsOemUsbOverride() { 831 if (mOemModeMap == null) return false; 832 833 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); 834 return (mOemModeMap.get(bootMode) != null) ? true : false; 835 } 836 837 private String processOemUsbOverride(String usbFunctions) { 838 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions; 839 840 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown"); 841 842 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode); 843 if (overrides != null) { 844 for (Pair<String, String> pair: overrides) { 845 if (pair.first.equals(usbFunctions)) { 846 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second); 847 return pair.second; 848 } 849 } 850 } 851 // return passed in functions as is. 852 return usbFunctions; 853 } 854 855 public void allowUsbDebugging(boolean alwaysAllow, String publicKey) { 856 if (mDebuggingManager != null) { 857 mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey); 858 } 859 } 860 861 public void denyUsbDebugging() { 862 if (mDebuggingManager != null) { 863 mDebuggingManager.denyUsbDebugging(); 864 } 865 } 866 867 public void clearUsbDebuggingKeys() { 868 if (mDebuggingManager != null) { 869 mDebuggingManager.clearUsbDebuggingKeys(); 870 } else { 871 throw new RuntimeException("Cannot clear Usb Debugging keys, " 872 + "UsbDebuggingManager not enabled"); 873 } 874 } 875 876 public void dump(FileDescriptor fd, PrintWriter pw) { 877 if (mHandler != null) { 878 mHandler.dump(fd, pw); 879 } 880 if (mDebuggingManager != null) { 881 mDebuggingManager.dump(fd, pw); 882 } 883 } 884 885 private native String[] nativeGetAccessoryStrings(); 886 private native ParcelFileDescriptor nativeOpenAccessory(); 887 private native boolean nativeIsStartRequested(); 888 private native int nativeGetAudioMode(); 889 } 890