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