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