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