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