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