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