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