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