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