• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = getDefaultFunctions();
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                 // persisting default function
464                 setEnabledFunctions(mDefaultFunctions, true);
465                 // After persisting them use the lock-down aware function set
466                 setEnabledFunctions(getDefaultFunctions(), false);
467                 updateAdbNotification();
468             }
469             if (mDebuggingManager != null) {
470                 mDebuggingManager.setAdbEnabled(mAdbEnabled);
471             }
472         }
473 
setEnabledFunctions(String functions, boolean makeDefault)474         private void setEnabledFunctions(String functions, boolean makeDefault) {
475             if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
476                     + " makeDefault: " + makeDefault);
477 
478             // Do not update persystent.sys.usb.config if the device is booted up
479             // with OEM specific mode.
480             if (functions != null && makeDefault && !needsOemUsbOverride()) {
481 
482                 if (mAdbEnabled) {
483                     functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
484                 } else {
485                     functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
486                 }
487                 if (!mDefaultFunctions.equals(functions)) {
488                     if (!setUsbConfig("none")) {
489                         Slog.e(TAG, "Failed to disable USB");
490                         // revert to previous configuration if we fail
491                         setUsbConfig(mCurrentFunctions);
492                         return;
493                     }
494                     // setting this property will also change the current USB state
495                     // via a property trigger
496                     SystemProperties.set("persist.sys.usb.config", functions);
497                     if (waitForState(functions)) {
498                         mCurrentFunctions = functions;
499                         mDefaultFunctions = functions;
500                     } else {
501                         Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
502                         // revert to previous configuration if we fail
503                         SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
504                     }
505                 }
506             } else {
507                 if (functions == null) {
508                     functions = mDefaultFunctions;
509                 }
510 
511                 // Override with bootmode specific usb mode if needed
512                 functions = processOemUsbOverride(functions);
513 
514                 if (mAdbEnabled) {
515                     functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
516                 } else {
517                     functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
518                 }
519                 if (!mCurrentFunctions.equals(functions)) {
520                     if (!setUsbConfig("none")) {
521                         Slog.e(TAG, "Failed to disable USB");
522                         // revert to previous configuration if we fail
523                         setUsbConfig(mCurrentFunctions);
524                         return;
525                     }
526                     if (setUsbConfig(functions)) {
527                         mCurrentFunctions = functions;
528                     } else {
529                         Slog.e(TAG, "Failed to switch USB config to " + functions);
530                         // revert to previous configuration if we fail
531                         setUsbConfig(mCurrentFunctions);
532                     }
533                 }
534             }
535         }
536 
updateCurrentAccessory()537         private void updateCurrentAccessory() {
538             // We are entering accessory mode if we have received a request from the host
539             // and the request has not timed out yet.
540             boolean enteringAccessoryMode =
541                     mAccessoryModeRequestTime > 0 &&
542                         SystemClock.elapsedRealtime() <
543                             mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
544 
545             if (mConfigured && enteringAccessoryMode) {
546                 // successfully entered accessory mode
547 
548                 if (mAccessoryStrings != null) {
549                     mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
550                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
551                     // defer accessoryAttached if system is not ready
552                     if (mBootCompleted) {
553                         getCurrentSettings().accessoryAttached(mCurrentAccessory);
554                     } // else handle in mBootCompletedReceiver
555                 } else {
556                     Slog.e(TAG, "nativeGetAccessoryStrings failed");
557                 }
558             } else if (!enteringAccessoryMode) {
559                 // make sure accessory mode is off
560                 // and restore default functions
561                 Slog.d(TAG, "exited USB accessory mode");
562                 setEnabledFunctions(getDefaultFunctions(), false);
563 
564                 if (mCurrentAccessory != null) {
565                     if (mBootCompleted) {
566                         getCurrentSettings().accessoryDetached(mCurrentAccessory);
567                     }
568                     mCurrentAccessory = null;
569                     mAccessoryStrings = null;
570                 }
571             }
572         }
573 
574         private void updateUsbState() {
575             // send a sticky broadcast containing current USB state
576             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
577             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
578             intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
579             intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
580 
581             if (mCurrentFunctions != null) {
582                 String[] functions = mCurrentFunctions.split(",");
583                 for (int i = 0; i < functions.length; i++) {
584                     intent.putExtra(functions[i], true);
585                 }
586             }
587 
588             if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " connected: " + mConnected
589                                     + " configured: " + mConfigured);
590             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
591         }
592 
593         private void updateAudioSourceFunction() {
594             boolean enabled = containsFunction(mCurrentFunctions,
595                     UsbManager.USB_FUNCTION_AUDIO_SOURCE);
596             if (enabled != mAudioSourceEnabled) {
597                 // send a sticky broadcast containing current USB state
598                 Intent intent = new Intent(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
599                 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
600                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
601                 intent.putExtra("state", (enabled ? 1 : 0));
602                 if (enabled) {
603                     Scanner scanner = null;
604                     try {
605                         scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
606                         int card = scanner.nextInt();
607                         int device = scanner.nextInt();
608                         intent.putExtra("card", card);
609                         intent.putExtra("device", device);
610                     } catch (FileNotFoundException e) {
611                         Slog.e(TAG, "could not open audio source PCM file", e);
612                     } finally {
613                         if (scanner != null) {
614                             scanner.close();
615                         }
616                     }
617                 }
618                 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
619                 mAudioSourceEnabled = enabled;
620             }
621         }
622 
623         @Override
624         public void handleMessage(Message msg) {
625             switch (msg.what) {
626                 case MSG_UPDATE_STATE:
627                     mConnected = (msg.arg1 == 1);
628                     mConfigured = (msg.arg2 == 1);
629                     updateUsbNotification();
630                     updateAdbNotification();
631                     if (containsFunction(mCurrentFunctions,
632                             UsbManager.USB_FUNCTION_ACCESSORY)) {
633                         updateCurrentAccessory();
634                     } else if (!mConnected) {
635                         // restore defaults when USB is disconnected
636                         setEnabledFunctions(getDefaultFunctions(), false);
637                     }
638                     if (mBootCompleted) {
639                         updateUsbState();
640                         updateAudioSourceFunction();
641                     }
642                     break;
643                 case MSG_ENABLE_ADB:
644                     setAdbEnabled(msg.arg1 == 1);
645                     break;
646                 case MSG_SET_CURRENT_FUNCTIONS:
647                     String functions = (String)msg.obj;
648                     boolean makeDefault = (msg.arg1 == 1);
649                     setEnabledFunctions(functions, makeDefault);
650                     break;
651                 case MSG_SYSTEM_READY:
652                     updateUsbNotification();
653                     updateAdbNotification();
654                     updateUsbState();
655                     updateAudioSourceFunction();
656                     break;
657                 case MSG_BOOT_COMPLETED:
658                     mBootCompleted = true;
659                     if (mCurrentAccessory != null) {
660                         getCurrentSettings().accessoryAttached(mCurrentAccessory);
661                     }
662                     if (mDebuggingManager != null) {
663                         mDebuggingManager.setAdbEnabled(mAdbEnabled);
664                     }
665                     break;
666                 case MSG_USER_SWITCHED: {
667                     UserManager userManager =
668                             (UserManager) mContext.getSystemService(Context.USER_SERVICE);
669                     UserHandle userHandle = new UserHandle(msg.arg1);
670                     if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
671                             userHandle)) {
672                         Slog.v(TAG, "Switched to user " + msg.arg1 +
673                                 " with DISALLOW_USB_FILE_TRANSFER restriction; disabling USB.");
674                         setUsbConfig("none");
675                         mCurrentUser = msg.arg1;
676                         break;
677                     }
678 
679                     final boolean mtpActive =
680                             containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
681                             || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
682                     if (mtpActive && mCurrentUser != UserHandle.USER_NULL) {
683                         Slog.v(TAG, "Current user switched; resetting USB host stack for MTP");
684                         setUsbConfig("none");
685                         setUsbConfig(mCurrentFunctions);
686                     }
687                     mCurrentUser = msg.arg1;
688                     break;
689                 }
690             }
691         }
692 
693         public UsbAccessory getCurrentAccessory() {
694             return mCurrentAccessory;
695         }
696 
697         private void updateUsbNotification() {
698             if (mNotificationManager == null || !mUseUsbNotification) return;
699             int id = 0;
700             Resources r = mContext.getResources();
701             if (mConnected) {
702                 if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
703                     id = com.android.internal.R.string.usb_mtp_notification_title;
704                 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
705                     id = com.android.internal.R.string.usb_ptp_notification_title;
706                 } else if (containsFunction(mCurrentFunctions,
707                         UsbManager.USB_FUNCTION_MASS_STORAGE)) {
708                     id = com.android.internal.R.string.usb_cd_installer_notification_title;
709                 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
710                     id = com.android.internal.R.string.usb_accessory_notification_title;
711                 } else {
712                     // There is a different notification for USB tethering so we don't need one here
713                     //if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
714                     //    Slog.e(TAG, "No known USB function in updateUsbNotification");
715                     //}
716                 }
717             }
718             if (id != mUsbNotificationId) {
719                 // clear notification if title needs changing
720                 if (mUsbNotificationId != 0) {
721                     mNotificationManager.cancelAsUser(null, mUsbNotificationId,
722                             UserHandle.ALL);
723                     mUsbNotificationId = 0;
724                 }
725                 if (id != 0) {
726                     CharSequence message = r.getText(
727                             com.android.internal.R.string.usb_notification_message);
728                     CharSequence title = r.getText(id);
729 
730                     Notification notification = new Notification();
731                     notification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
732                     notification.when = 0;
733                     notification.flags = Notification.FLAG_ONGOING_EVENT;
734                     notification.tickerText = title;
735                     notification.defaults = 0; // please be quiet
736                     notification.sound = null;
737                     notification.vibrate = null;
738                     notification.priority = Notification.PRIORITY_MIN;
739 
740                     Intent intent = Intent.makeRestartActivityTask(
741                             new ComponentName("com.android.settings",
742                                     "com.android.settings.UsbSettings"));
743                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
744                             intent, 0, null, UserHandle.CURRENT);
745                     notification.color = mContext.getResources().getColor(
746                             com.android.internal.R.color.system_notification_accent_color);
747                     notification.setLatestEventInfo(mContext, title, message, pi);
748                     notification.visibility = Notification.VISIBILITY_PUBLIC;
749                     mNotificationManager.notifyAsUser(null, id, notification,
750                             UserHandle.ALL);
751                     mUsbNotificationId = id;
752                 }
753             }
754         }
755 
756         private void updateAdbNotification() {
757             if (mNotificationManager == null) return;
758             final int id = com.android.internal.R.string.adb_active_notification_title;
759             if (mAdbEnabled && mConnected) {
760                 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
761 
762                 if (!mAdbNotificationShown) {
763                     Resources r = mContext.getResources();
764                     CharSequence title = r.getText(id);
765                     CharSequence message = r.getText(
766                             com.android.internal.R.string.adb_active_notification_message);
767 
768                     Notification notification = new Notification();
769                     notification.icon = com.android.internal.R.drawable.stat_sys_adb;
770                     notification.when = 0;
771                     notification.flags = Notification.FLAG_ONGOING_EVENT;
772                     notification.tickerText = title;
773                     notification.defaults = 0; // please be quiet
774                     notification.sound = null;
775                     notification.vibrate = null;
776                     notification.priority = Notification.PRIORITY_LOW;
777 
778                     Intent intent = Intent.makeRestartActivityTask(
779                             new ComponentName("com.android.settings",
780                                     "com.android.settings.DevelopmentSettings"));
781                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
782                             intent, 0, null, UserHandle.CURRENT);
783                     notification.color = mContext.getResources().getColor(
784                             com.android.internal.R.color.system_notification_accent_color);
785                     notification.setLatestEventInfo(mContext, title, message, pi);
786                     notification.visibility = Notification.VISIBILITY_PUBLIC;
787                     mAdbNotificationShown = true;
788                     mNotificationManager.notifyAsUser(null, id, notification,
789                             UserHandle.ALL);
790                 }
791             } else if (mAdbNotificationShown) {
792                 mAdbNotificationShown = false;
793                 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
794             }
795         }
796 
797         private String getDefaultFunctions() {
798             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
799             if (userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
800                     new UserHandle(mCurrentUser))) {
801                 return "none";
802             }
803             return mDefaultFunctions;
804         }
805 
806         public void dump(FileDescriptor fd, PrintWriter pw) {
807             pw.println("  USB Device State:");
808             pw.println("    Current Functions: " + mCurrentFunctions);
809             pw.println("    Default Functions: " + mDefaultFunctions);
810             pw.println("    mConnected: " + mConnected);
811             pw.println("    mConfigured: " + mConfigured);
812             pw.println("    mCurrentAccessory: " + mCurrentAccessory);
813             try {
814                 pw.println("    Kernel state: "
815                         + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
816                 pw.println("    Kernel function list: "
817                         + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
818                 pw.println("    Mass storage backing file: "
819                         + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim());
820             } catch (IOException e) {
821                 pw.println("IOException: " + e);
822             }
823         }
824     }
825 
826     /* returns the currently attached USB accessory */
827     public UsbAccessory getCurrentAccessory() {
828         return mHandler.getCurrentAccessory();
829     }
830 
831     /* opens the currently attached USB accessory */
832     public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
833         UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
834         if (currentAccessory == null) {
835             throw new IllegalArgumentException("no accessory attached");
836         }
837         if (!currentAccessory.equals(accessory)) {
838             String error = accessory.toString()
839                     + " does not match current accessory "
840                     + currentAccessory;
841             throw new IllegalArgumentException(error);
842         }
843         getCurrentSettings().checkPermission(accessory);
844         return nativeOpenAccessory();
845     }
846 
847     public void setCurrentFunctions(String functions, boolean makeDefault) {
848         if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
849         mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
850     }
851 
852     public void setMassStorageBackingFile(String path) {
853         if (path == null) path = "";
854         try {
855             FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path);
856         } catch (IOException e) {
857            Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH);
858         }
859     }
860 
861     private void readOemUsbOverrideConfig() {
862         String[] configList = mContext.getResources().getStringArray(
863             com.android.internal.R.array.config_oemUsbModeOverride);
864 
865         if (configList != null) {
866             for (String config: configList) {
867                 String[] items = config.split(":");
868                 if (items.length == 3) {
869                     if (mOemModeMap == null) {
870                         mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
871                     }
872                     List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
873                     if (overrideList == null) {
874                         overrideList = new LinkedList<Pair<String, String>>();
875                         mOemModeMap.put(items[0], overrideList);
876                     }
877                     overrideList.add(new Pair<String, String>(items[1], items[2]));
878                 }
879             }
880         }
881     }
882 
883     private boolean needsOemUsbOverride() {
884         if (mOemModeMap == null) return false;
885 
886         String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
887         return (mOemModeMap.get(bootMode) != null) ? true : false;
888     }
889 
890     private String processOemUsbOverride(String usbFunctions) {
891         if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
892 
893         String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
894 
895         List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
896         if (overrides != null) {
897             for (Pair<String, String> pair: overrides) {
898                 if (pair.first.equals(usbFunctions)) {
899                     Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
900                     return pair.second;
901                 }
902             }
903         }
904         // return passed in functions as is.
905         return usbFunctions;
906     }
907 
908     public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
909         if (mDebuggingManager != null) {
910             mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
911         }
912     }
913 
914     public void denyUsbDebugging() {
915         if (mDebuggingManager != null) {
916             mDebuggingManager.denyUsbDebugging();
917         }
918     }
919 
920     public void clearUsbDebuggingKeys() {
921         if (mDebuggingManager != null) {
922             mDebuggingManager.clearUsbDebuggingKeys();
923         } else {
924             throw new RuntimeException("Cannot clear Usb Debugging keys, "
925                         + "UsbDebuggingManager not enabled");
926         }
927     }
928 
929     public void dump(FileDescriptor fd, PrintWriter pw) {
930         if (mHandler != null) {
931             mHandler.dump(fd, pw);
932         }
933         if (mDebuggingManager != null) {
934             mDebuggingManager.dump(fd, pw);
935         }
936     }
937 
938     private native String[] nativeGetAccessoryStrings();
939     private native ParcelFileDescriptor nativeOpenAccessory();
940     private native boolean nativeIsStartRequested();
941     private native int nativeGetAudioMode();
942 }
943