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