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