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