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