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