2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.usb;
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.hardware.usb.UsbPort;
34 import android.hardware.usb.UsbPortStatus;
35 import android.os.FileUtils;
36 import android.os.Handler;
37 import android.os.Looper;
38 import android.os.Message;
39 import android.os.ParcelFileDescriptor;
40 import android.os.SystemClock;
41 import android.os.SystemProperties;
42 import android.os.UEventObserver;
43 import android.os.UserHandle;
44 import android.os.UserManager;
45 import android.os.storage.StorageManager;
46 import android.os.storage.StorageVolume;
47 import android.provider.Settings;
48 import android.util.Pair;
49 import android.util.Slog;
51 import com.android.internal.annotations.GuardedBy;
52 import com.android.internal.os.SomeArgs;
53 import com.android.internal.util.IndentingPrintWriter;
54 import com.android.server.FgThread;
57 import java.io.FileNotFoundException;
58 import java.io.IOException;
59 import java.util.HashMap;
60 import java.util.LinkedList;
61 import java.util.List;
62 import java.util.Locale;
64 import java.util.Scanner;
68 * UsbDeviceManager manages USB state in device mode.
70 public class UsbDeviceManager {
72 private static final String TAG = "UsbDeviceManager";
73 private static final boolean DEBUG = false;
76 * The persistent property which stores whether adb is enabled or not.
77 * May also contain vendor-specific default functions for testing purposes.
79 private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
82 * The non-persistent property which stores the current USB settings.
84 private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
87 * The non-persistent property which stores the current USB actual state.
89 private static final String USB_STATE_PROPERTY = "sys.usb.state";
91 private static final String USB_STATE_MATCH =
92 "DEVPATH=/devices/virtual/android_usb/android0";
93 private static final String ACCESSORY_START_MATCH =
94 "DEVPATH=/devices/virtual/misc/usb_accessory";
95 private static final String FUNCTIONS_PATH =
96 "/sys/class/android_usb/android0/functions";
97 private static final String STATE_PATH =
98 "/sys/class/android_usb/android0/state";
99 private static final String RNDIS_ETH_ADDR_PATH =
100 "/sys/class/android_usb/android0/f_rndis/ethaddr";
101 private static final String AUDIO_SOURCE_PCM_PATH =
102 "/sys/class/android_usb/android0/f_audio_source/pcm";
103 private static final String MIDI_ALSA_PATH =
104 "/sys/class/android_usb/android0/f_midi/alsa";
106 private static final int MSG_UPDATE_STATE = 0;
107 private static final int MSG_ENABLE_ADB = 1;
108 private static final int MSG_SET_CURRENT_FUNCTIONS = 2;
109 private static final int MSG_SYSTEM_READY = 3;
110 private static final int MSG_BOOT_COMPLETED = 4;
111 private static final int MSG_USER_SWITCHED = 5;
112 private static final int MSG_SET_USB_DATA_UNLOCKED = 6;
113 private static final int MSG_UPDATE_USER_RESTRICTIONS = 7;
114 private static final int MSG_UPDATE_HOST_STATE = 8;
116 private static final int AUDIO_MODE_SOURCE = 1;
118 // Delay for debouncing USB disconnects.
119 // We often get rapid connect/disconnect events when enabling USB functions,
120 // which need debouncing.
121 private static final int UPDATE_DELAY = 1000;
123 // Time we received a request to enter USB accessory mode
124 private long mAccessoryModeRequestTime = 0;
126 // Timeout for entering USB request mode.
127 // Request is cancelled if host does not configure device within 10 seconds.
128 private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
130 private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
132 private UsbHandler mHandler;
133 private boolean mBootCompleted;
135 private final Object mLock = new Object();
137 private final Context mContext;
138 private final ContentResolver mContentResolver;
140 private UsbSettingsManager mCurrentSettings;
141 private NotificationManager mNotificationManager;
142 private final boolean mHasUsbAccessory;
143 private boolean mUseUsbNotification;
144 private boolean mAdbEnabled;
145 private boolean mAudioSourceEnabled;
146 private boolean mMidiEnabled;
147 private int mMidiCard;
148 private int mMidiDevice;
149 private Map<String, List<Pair<String, String>>> mOemModeMap;
150 private String[] mAccessoryStrings;
151 private UsbDebuggingManager mDebuggingManager;
152 private final UsbAlsaManager mUsbAlsaManager;
153 private Intent mBroadcastedIntent;
155 private class AdbSettingsObserver extends ContentObserver {
156 public AdbSettingsObserver() {
160 public void onChange(boolean selfChange) {
161 boolean enable = (Settings.Global.getInt(mContentResolver,
162 Settings.Global.ADB_ENABLED, 0) > 0);
163 mHandler.sendMessage(MSG_ENABLE_ADB, enable);
168 * Listens for uevent messages from the kernel to monitor the USB state
170 private final UEventObserver mUEventObserver = new UEventObserver() {
172 public void onUEvent(UEventObserver.UEvent event) {
173 if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
175 String state = event.get("USB_STATE");
176 String accessory = event.get("ACCESSORY");
178 mHandler.updateState(state);
179 } else if ("START".equals(accessory)) {
180 if (DEBUG) Slog.d(TAG, "got accessory start");
181 startAccessoryMode();
186 private final BroadcastReceiver mHostReceiver = new BroadcastReceiver() {
188 public void onReceive(Context context, Intent intent) {
189 UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
190 UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS);
191 mHandler.updateHostState(port, status);
195 public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
197 mUsbAlsaManager = alsaManager;
198 mContentResolver = context.getContentResolver();
199 PackageManager pm = mContext.getPackageManager();
200 mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
203 readOemUsbOverrideConfig();
205 mHandler = new UsbHandler(FgThread.get().getLooper());
207 if (nativeIsStartRequested()) {
208 if (DEBUG) Slog.d(TAG, "accessory attached at boot");
209 startAccessoryMode();
212 boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
213 boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
214 if (secureAdbEnabled && !dataEncrypted) {
215 mDebuggingManager = new UsbDebuggingManager(context);
217 mContext.registerReceiver(mHostReceiver,
218 new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
221 private UsbSettingsManager getCurrentSettings() {
222 synchronized (mLock) {
223 return mCurrentSettings;
227 public void systemReady() {
228 if (DEBUG) Slog.d(TAG, "systemReady");
230 mNotificationManager = (NotificationManager)
231 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
233 // We do not show the USB notification if the primary volume supports mass storage.
234 // The legacy mass storage UI will be used instead.
235 boolean massStorageSupported = false;
236 final StorageManager storageManager = StorageManager.from(mContext);
237 final StorageVolume primary = storageManager.getPrimaryVolume();
238 massStorageSupported = primary != null && primary.allowMassStorage();
239 mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
240 com.android.internal.R.bool.config_usbChargingMessage);
242 // make sure the ADB_ENABLED setting value matches the current state
244 Settings.Global.putInt(mContentResolver,
245 Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
246 } catch (SecurityException e) {
247 // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
248 Slog.d(TAG, "ADB_ENABLED is restricted.");
250 mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
253 public void bootCompleted() {
254 if (DEBUG) Slog.d(TAG, "boot completed");
255 mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
258 public void setCurrentUser(int userId, UsbSettingsManager settings) {
259 synchronized (mLock) {
260 mCurrentSettings = settings;
261 mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
265 public void updateUserRestrictions() {
266 mHandler.sendEmptyMessage(MSG_UPDATE_USER_RESTRICTIONS);
269 private void startAccessoryMode() {
270 if (!mHasUsbAccessory) return;
272 mAccessoryStrings = nativeGetAccessoryStrings();
273 boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
274 // don't start accessory mode if our mandatory strings have not been set
275 boolean enableAccessory = (mAccessoryStrings != null &&
276 mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
277 mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
278 String functions = null;
280 if (enableAccessory && enableAudio) {
281 functions = UsbManager.USB_FUNCTION_ACCESSORY + ","
282 + UsbManager.USB_FUNCTION_AUDIO_SOURCE;
283 } else if (enableAccessory) {
284 functions = UsbManager.USB_FUNCTION_ACCESSORY;
285 } else if (enableAudio) {
286 functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
289 if (functions != null) {
290 mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
291 setCurrentFunctions(functions);
295 private static void initRndisAddress() {
296 // configure RNDIS ethernet address based on our serial number using the same algorithm
297 // we had been previously using in kernel board files
298 final int ETH_ALEN = 6;
299 int address[] = new int[ETH_ALEN];
300 // first byte is 0x02 to signify a locally administered address
303 String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
304 int serialLength = serial.length();
305 // XOR the USB serial across the remaining 5 bytes
306 for (int i = 0; i < serialLength; i++) {
307 address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
309 String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
310 address[0], address[1], address[2], address[3], address[4], address[5]);
312 FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
313 } catch (IOException e) {
314 Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
318 private final class UsbHandler extends Handler {
321 private boolean mConnected;
322 private boolean mHostConnected;
323 private boolean mSourcePower;
324 private boolean mSinkPower;
325 private boolean mConfigured;
326 private boolean mUsbDataUnlocked;
327 private String mCurrentFunctions;
328 private boolean mCurrentFunctionsApplied;
329 private UsbAccessory mCurrentAccessory;
330 private int mUsbNotificationId;
331 private boolean mAdbNotificationShown;
332 private int mCurrentUser = UserHandle.USER_NULL;
334 public UsbHandler(Looper looper) {
337 // Restore default functions.
338 mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
339 UsbManager.USB_FUNCTION_NONE);
340 if (UsbManager.USB_FUNCTION_NONE.equals(mCurrentFunctions)) {
341 mCurrentFunctions = UsbManager.USB_FUNCTION_MTP;
343 mCurrentFunctionsApplied = mCurrentFunctions.equals(
344 SystemProperties.get(USB_STATE_PROPERTY));
345 mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),
346 UsbManager.USB_FUNCTION_ADB);
347 setEnabledFunctions(null, false);
349 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
352 // register observer to listen for settings changes
353 mContentResolver.registerContentObserver(
354 Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
355 false, new AdbSettingsObserver());
357 // Watch for USB configuration changes
358 mUEventObserver.startObserving(USB_STATE_MATCH);
359 mUEventObserver.startObserving(ACCESSORY_START_MATCH);
360 } catch (Exception e) {
361 Slog.e(TAG, "Error initializing UsbHandler", e);
365 public void sendMessage(int what, boolean arg) {
366 removeMessages(what);
367 Message m = Message.obtain(this, what);
368 m.arg1 = (arg ? 1 : 0);
372 public void sendMessage(int what, Object arg) {
373 removeMessages(what);
374 Message m = Message.obtain(this, what);
379 public void updateState(String state) {
380 int connected, configured;
382 if ("DISCONNECTED".equals(state)) {
385 } else if ("CONNECTED".equals(state)) {
388 } else if ("CONFIGURED".equals(state)) {
392 Slog.e(TAG, "unknown state " + state);
395 removeMessages(MSG_UPDATE_STATE);
396 Message msg = Message.obtain(this, MSG_UPDATE_STATE);
397 msg.arg1 = connected;
398 msg.arg2 = configured;
399 // debounce disconnects to avoid problems bringing up USB tethering
400 sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
403 public void updateHostState(UsbPort port, UsbPortStatus status) {
404 boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
405 boolean sourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE;
406 boolean sinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK;
409 Slog.i(TAG, "updateHostState " + port + " status=" + status);
412 SomeArgs args = SomeArgs.obtain();
413 args.argi1 = hostConnected ? 1 :0;
414 args.argi2 = sourcePower ? 1 :0;
415 args.argi3 = sinkPower ? 1 :0;
417 obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget();
420 private boolean waitForState(String state) {
421 // wait for the transition to complete.
422 // give up after 1 second.
424 for (int i = 0; i < 20; i++) {
425 // State transition is done when sys.usb.state is set to the new configuration
426 value = SystemProperties.get(USB_STATE_PROPERTY);
427 if (state.equals(value)) return true;
428 SystemClock.sleep(50);
430 Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
434 private boolean setUsbConfig(String config) {
435 if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
436 // set the new configuration
437 // we always set it due to b/23631400, where adbd was getting killed
438 // and not restarted due to property timeouts on some devices
439 SystemProperties.set(USB_CONFIG_PROPERTY, config);
440 return waitForState(config);
443 private void setUsbDataUnlocked(boolean enable) {
444 if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable);
445 mUsbDataUnlocked = enable;
446 updateUsbNotification();
447 updateUsbStateBroadcastIfNeeded();
448 setEnabledFunctions(mCurrentFunctions, true);
451 private void setAdbEnabled(boolean enable) {
452 if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
453 if (enable != mAdbEnabled) {
454 mAdbEnabled = enable;
456 // Due to the persist.sys.usb.config property trigger, changing adb state requires
457 // persisting default function
458 String oldFunctions = getDefaultFunctions();
459 String newFunctions = applyAdbFunction(oldFunctions);
460 if (!oldFunctions.equals(newFunctions)) {
461 SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions);
464 // After persisting them use the lock-down aware function set
465 setEnabledFunctions(mCurrentFunctions, false);
466 updateAdbNotification();
469 if (mDebuggingManager != null) {
470 mDebuggingManager.setAdbEnabled(mAdbEnabled);
475 * Evaluates USB function policies and applies the change accordingly.
477 private void setEnabledFunctions(String functions, boolean forceRestart) {
478 if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
479 + "forceRestart=" + forceRestart);
481 // Try to set the enabled functions.
482 final String oldFunctions = mCurrentFunctions;
483 final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
484 if (trySetEnabledFunctions(functions, forceRestart)) {
488 // Didn't work. Try to revert changes.
489 // We always reapply the policy in case certain constraints changed such as
490 // user restrictions independently of any other new functions we were
491 // trying to activate.
492 if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
493 Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
494 if (trySetEnabledFunctions(oldFunctions, false)) {
499 // Still didn't work. Try to restore the default functions.
500 Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
501 if (trySetEnabledFunctions(null, false)) {
505 // Now we're desperate. Ignore the default functions.
506 // Try to get ADB working if enabled.
507 Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
508 if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
513 Slog.e(TAG, "Unable to set any USB functions!");
516 private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
517 if (functions == null) {
518 functions = getDefaultFunctions();
520 functions = applyAdbFunction(functions);
521 functions = applyOemOverrideFunction(functions);
523 if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied
525 Slog.i(TAG, "Setting USB config to " + functions);
526 mCurrentFunctions = functions;
527 mCurrentFunctionsApplied = false;
529 // Kick the USB stack to close existing connections.
530 setUsbConfig(UsbManager.USB_FUNCTION_NONE);
532 // Set the new USB configuration.
533 if (!setUsbConfig(functions)) {
534 Slog.e(TAG, "Failed to switch USB config to " + functions);
538 mCurrentFunctionsApplied = true;
543 private String applyAdbFunction(String functions) {
545 functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB);
547 functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
552 private boolean isUsbTransferAllowed() {
553 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
554 return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
557 private void updateCurrentAccessory() {
558 // We are entering accessory mode if we have received a request from the host
559 // and the request has not timed out yet.
560 boolean enteringAccessoryMode =
561 mAccessoryModeRequestTime > 0 &&
562 SystemClock.elapsedRealtime() <
563 mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
565 if (mConfigured && enteringAccessoryMode) {
566 // successfully entered accessory mode
568 if (mAccessoryStrings != null) {
569 mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
570 Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
571 // defer accessoryAttached if system is not ready
572 if (mBootCompleted) {
573 getCurrentSettings().accessoryAttached(mCurrentAccessory);
574 } // else handle in boot completed
576 Slog.e(TAG, "nativeGetAccessoryStrings failed");
578 } else if (!enteringAccessoryMode) {
579 // make sure accessory mode is off
580 // and restore default functions
581 Slog.d(TAG, "exited USB accessory mode");
582 setEnabledFunctions(null, false);
584 if (mCurrentAccessory != null) {
585 if (mBootCompleted) {
586 getCurrentSettings().accessoryDetached(mCurrentAccessory);
588 mCurrentAccessory = null;
589 mAccessoryStrings = null;
594 private boolean isUsbStateChanged(Intent intent) {
595 final Set<String> keySet = intent.getExtras().keySet();
596 if (mBroadcastedIntent == null) {
597 for (String key : keySet) {
598 if (intent.getBooleanExtra(key, false)) {
599 // MTP function is enabled by default.
600 if (UsbManager.USB_FUNCTION_MTP.equals(key)) {
607 if (!keySet.equals(mBroadcastedIntent.getExtras().keySet())) {
610 for (String key : keySet) {
611 if (intent.getBooleanExtra(key, false) !=
612 mBroadcastedIntent.getBooleanExtra(key, false)) {
620 private void updateUsbStateBroadcastIfNeeded() {
621 // send a sticky broadcast containing current USB state
622 Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
623 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
624 | Intent.FLAG_RECEIVER_FOREGROUND);
625 intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
626 intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
627 intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
628 intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked);
630 if (mCurrentFunctions != null) {
631 String[] functions = mCurrentFunctions.split(",");
632 for (int i = 0; i < functions.length; i++) {
633 final String function = functions[i];
634 if (UsbManager.USB_FUNCTION_NONE.equals(function)) {
637 intent.putExtra(function, true);
641 // send broadcast intent only if the USB state has changed
642 if (!isUsbStateChanged(intent)) {
644 Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
649 if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
650 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
651 mBroadcastedIntent = intent;
654 private void updateUsbFunctions() {
655 updateAudioSourceFunction();
656 updateMidiFunction();
659 private void updateAudioSourceFunction() {
660 boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
661 UsbManager.USB_FUNCTION_AUDIO_SOURCE);
662 if (enabled != mAudioSourceEnabled) {
667 Scanner scanner = null;
669 scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
670 card = scanner.nextInt();
671 device = scanner.nextInt();
672 } catch (FileNotFoundException e) {
673 Slog.e(TAG, "could not open audio source PCM file", e);
675 if (scanner != null) {
680 mUsbAlsaManager.setAccessoryAudioState(enabled, card, device);
681 mAudioSourceEnabled = enabled;
685 private void updateMidiFunction() {
686 boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
687 UsbManager.USB_FUNCTION_MIDI);
688 if (enabled != mMidiEnabled) {
690 Scanner scanner = null;
692 scanner = new Scanner(new File(MIDI_ALSA_PATH));
693 mMidiCard = scanner.nextInt();
694 mMidiDevice = scanner.nextInt();
695 } catch (FileNotFoundException e) {
696 Slog.e(TAG, "could not open MIDI PCM file", e);
699 if (scanner != null) {
704 mMidiEnabled = enabled;
706 mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
710 public void handleMessage(Message msg) {
712 case MSG_UPDATE_STATE:
713 mConnected = (msg.arg1 == 1);
714 mConfigured = (msg.arg2 == 1);
716 // When a disconnect occurs, relock access to sensitive user data
717 mUsbDataUnlocked = false;
719 updateUsbNotification();
720 updateAdbNotification();
721 if (UsbManager.containsFunction(mCurrentFunctions,
722 UsbManager.USB_FUNCTION_ACCESSORY)) {
723 updateCurrentAccessory();
724 } else if (!mConnected) {
725 // restore defaults when USB is disconnected
726 setEnabledFunctions(null, false);
728 if (mBootCompleted) {
729 updateUsbStateBroadcastIfNeeded();
730 updateUsbFunctions();
733 case MSG_UPDATE_HOST_STATE:
734 SomeArgs args = (SomeArgs) msg.obj;
735 mHostConnected = (args.argi1 == 1);
736 mSourcePower = (args.argi2 == 1);
737 mSinkPower = (args.argi3 == 1);
739 updateUsbNotification();
740 if (mBootCompleted) {
741 updateUsbStateBroadcastIfNeeded();
745 setAdbEnabled(msg.arg1 == 1);
747 case MSG_SET_CURRENT_FUNCTIONS:
748 String functions = (String)msg.obj;
749 setEnabledFunctions(functions, false);
751 case MSG_UPDATE_USER_RESTRICTIONS:
752 setEnabledFunctions(mCurrentFunctions, false);
754 case MSG_SET_USB_DATA_UNLOCKED:
755 setUsbDataUnlocked(msg.arg1 == 1);
757 case MSG_SYSTEM_READY:
758 updateUsbNotification();
759 updateAdbNotification();
760 updateUsbStateBroadcastIfNeeded();
761 updateUsbFunctions();
763 case MSG_BOOT_COMPLETED:
764 mBootCompleted = true;
765 if (mCurrentAccessory != null) {
766 getCurrentSettings().accessoryAttached(mCurrentAccessory);
768 if (mDebuggingManager != null) {
769 mDebuggingManager.setAdbEnabled(mAdbEnabled);
772 case MSG_USER_SWITCHED: {
773 if (mCurrentUser != msg.arg1) {
774 // Restart the USB stack and re-apply user restrictions for MTP or PTP.
775 final boolean active = UsbManager.containsFunction(mCurrentFunctions,
776 UsbManager.USB_FUNCTION_MTP)
777 || UsbManager.containsFunction(mCurrentFunctions,
778 UsbManager.USB_FUNCTION_PTP);
779 if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) {
780 Slog.v(TAG, "Current user switched to " + mCurrentUser
781 + "; resetting USB host stack for MTP or PTP");
782 // avoid leaking sensitive data from previous user
783 mUsbDataUnlocked = false;
784 setEnabledFunctions(mCurrentFunctions, true);
786 mCurrentUser = msg.arg1;
793 public UsbAccessory getCurrentAccessory() {
794 return mCurrentAccessory;
797 private void updateUsbNotification() {
798 if (mNotificationManager == null || !mUseUsbNotification
799 || ("0".equals(SystemProperties.get("persist.charging.notify")))) return;
801 Resources r = mContext.getResources();
803 if (!mUsbDataUnlocked) {
805 id = com.android.internal.R.string.usb_supplying_notification_title;
807 id = com.android.internal.R.string.usb_charging_notification_title;
809 } else if (UsbManager.containsFunction(mCurrentFunctions,
810 UsbManager.USB_FUNCTION_MTP)) {
811 id = com.android.internal.R.string.usb_mtp_notification_title;
812 } else if (UsbManager.containsFunction(mCurrentFunctions,
813 UsbManager.USB_FUNCTION_PTP)) {
814 id = com.android.internal.R.string.usb_ptp_notification_title;
815 } else if (UsbManager.containsFunction(mCurrentFunctions,
816 UsbManager.USB_FUNCTION_MIDI)) {
817 id = com.android.internal.R.string.usb_midi_notification_title;
818 } else if (UsbManager.containsFunction(mCurrentFunctions,
819 UsbManager.USB_FUNCTION_ACCESSORY)) {
820 id = com.android.internal.R.string.usb_accessory_notification_title;
821 } else if (mSourcePower) {
822 id = com.android.internal.R.string.usb_supplying_notification_title;
824 id = com.android.internal.R.string.usb_charging_notification_title;
826 } else if (mSourcePower) {
827 id = com.android.internal.R.string.usb_supplying_notification_title;
828 } else if (mHostConnected && mSinkPower) {
829 id = com.android.internal.R.string.usb_charging_notification_title;
831 if (id != mUsbNotificationId) {
832 // clear notification if title needs changing
833 if (mUsbNotificationId != 0) {
834 mNotificationManager.cancelAsUser(null, mUsbNotificationId,
836 mUsbNotificationId = 0;
839 CharSequence message = r.getText(
840 com.android.internal.R.string.usb_notification_message);
841 CharSequence title = r.getText(id);
843 Intent intent = Intent.makeRestartActivityTask(
844 new ComponentName("com.android.settings",
845 "com.android.settings.deviceinfo.UsbModeChooserActivity"));
846 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
847 intent, 0, null, UserHandle.CURRENT);
849 Notification notification = new Notification.Builder(mContext)
850 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
854 .setDefaults(0) // please be quiet
855 .setPriority(Notification.PRIORITY_MIN)
856 .setColor(mContext.getColor(
857 com.android.internal.R.color.system_notification_accent_color))
858 .setContentTitle(title)
859 .setContentText(message)
860 .setContentIntent(pi)
861 .setVisibility(Notification.VISIBILITY_PUBLIC)
863 mNotificationManager.notifyAsUser(null, id, notification,
865 mUsbNotificationId = id;
870 private void updateAdbNotification() {
871 if (mNotificationManager == null) return;
872 final int id = com.android.internal.R.string.adb_active_notification_title;
873 if (mAdbEnabled && mConnected) {
874 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
876 if (!mAdbNotificationShown) {
877 Resources r = mContext.getResources();
878 CharSequence title = r.getText(id);
879 CharSequence message = r.getText(
880 com.android.internal.R.string.adb_active_notification_message);
882 Intent intent = Intent.makeRestartActivityTask(
883 new ComponentName("com.android.settings",
884 "com.android.settings.DevelopmentSettings"));
885 PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
886 intent, 0, null, UserHandle.CURRENT);
888 Notification notification = new Notification.Builder(mContext)
889 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
893 .setDefaults(0) // please be quiet
894 .setPriority(Notification.PRIORITY_DEFAULT)
895 .setColor(mContext.getColor(
896 com.android.internal.R.color.system_notification_accent_color))
897 .setContentTitle(title)
898 .setContentText(message)
899 .setContentIntent(pi)
900 .setVisibility(Notification.VISIBILITY_PUBLIC)
902 mAdbNotificationShown = true;
903 mNotificationManager.notifyAsUser(null, id, notification,
906 } else if (mAdbNotificationShown) {
907 mAdbNotificationShown = false;
908 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
912 private String getDefaultFunctions() {
913 String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY,
914 UsbManager.USB_FUNCTION_NONE);
915 if (UsbManager.USB_FUNCTION_NONE.equals(func)) {
916 func = UsbManager.USB_FUNCTION_MTP;
921 public void dump(IndentingPrintWriter pw) {
922 pw.println("USB Device State:");
923 pw.println(" mCurrentFunctions: " + mCurrentFunctions);
924 pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
925 pw.println(" mConnected: " + mConnected);
926 pw.println(" mConfigured: " + mConfigured);
927 pw.println(" mUsbDataUnlocked: " + mUsbDataUnlocked);
928 pw.println(" mCurrentAccessory: " + mCurrentAccessory);
929 pw.println(" mHostConnected: " + mHostConnected);
930 pw.println(" mSourcePower: " + mSourcePower);
931 pw.println(" mSinkPower: " + mSinkPower);
933 pw.println(" Kernel state: "
934 + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
935 pw.println(" Kernel function list: "
936 + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
937 } catch (IOException e) {
938 pw.println("IOException: " + e);
943 /* returns the currently attached USB accessory */
944 public UsbAccessory getCurrentAccessory() {
945 return mHandler.getCurrentAccessory();
948 /* opens the currently attached USB accessory */
949 public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
950 UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
951 if (currentAccessory == null) {
952 throw new IllegalArgumentException("no accessory attached");
954 if (!currentAccessory.equals(accessory)) {
955 String error = accessory.toString()
956 + " does not match current accessory "
958 throw new IllegalArgumentException(error);
960 getCurrentSettings().checkPermission(accessory);
961 return nativeOpenAccessory();
964 public boolean isFunctionEnabled(String function) {
965 return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
968 public void setCurrentFunctions(String functions) {
969 if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
970 mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
973 public void setUsbDataUnlocked(boolean unlocked) {
974 if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")");
975 mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked);
978 private void readOemUsbOverrideConfig() {
979 String[] configList = mContext.getResources().getStringArray(
980 com.android.internal.R.array.config_oemUsbModeOverride);
982 if (configList != null) {
983 for (String config: configList) {
984 String[] items = config.split(":");
985 if (items.length == 3) {
986 if (mOemModeMap == null) {
987 mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
989 List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
990 if (overrideList == null) {
991 overrideList = new LinkedList<Pair<String, String>>();
992 mOemModeMap.put(items[0], overrideList);
994 overrideList.add(new Pair<String, String>(items[1], items[2]));
1000 private String applyOemOverrideFunction(String usbFunctions) {
1001 if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
1003 String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
1005 List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
1006 if (overrides != null) {
1007 for (Pair<String, String> pair: overrides) {
1008 if (pair.first.equals(usbFunctions)) {
1009 Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
1014 // return passed in functions as is.
1015 return usbFunctions;
1018 public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
1019 if (mDebuggingManager != null) {
1020 mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
1024 public void denyUsbDebugging() {
1025 if (mDebuggingManager != null) {
1026 mDebuggingManager.denyUsbDebugging();
1030 public void clearUsbDebuggingKeys() {
1031 if (mDebuggingManager != null) {
1032 mDebuggingManager.clearUsbDebuggingKeys();
1034 throw new RuntimeException("Cannot clear Usb Debugging keys, "
1035 + "UsbDebuggingManager not enabled");
1039 public void dump(IndentingPrintWriter pw) {
1040 if (mHandler != null) {
1043 if (mDebuggingManager != null) {
1044 mDebuggingManager.dump(pw);
1048 private native String[] nativeGetAccessoryStrings();
1049 private native ParcelFileDescriptor nativeOpenAccessory();
1050 private native boolean nativeIsStartRequested();
1051 private native int nativeGetAudioMode();