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