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