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