OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / services / usb / java / com / android / server / usb / UsbDeviceManager.java
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.hardware.usb.UsbPort;
34 import android.hardware.usb.UsbPortStatus;
35 import android.os.FileUtils;
36 import android.os.Handler;
37 import android.os.Looper;
38 import android.os.Message;
39 import android.os.ParcelFileDescriptor;
40 import android.os.SystemClock;
41 import android.os.SystemProperties;
42 import android.os.UEventObserver;
43 import android.os.UserHandle;
44 import android.os.UserManager;
45 import android.os.storage.StorageManager;
46 import android.os.storage.StorageVolume;
47 import android.provider.Settings;
48 import android.util.Pair;
49 import android.util.Slog;
50
51 import com.android.internal.annotations.GuardedBy;
52 import com.android.internal.os.SomeArgs;
53 import com.android.internal.util.IndentingPrintWriter;
54 import com.android.server.FgThread;
55
56 import java.io.File;
57 import java.io.FileNotFoundException;
58 import java.io.IOException;
59 import java.util.HashMap;
60 import java.util.LinkedList;
61 import java.util.List;
62 import java.util.Locale;
63 import java.util.Map;
64 import java.util.Scanner;
65 import java.util.Set;
66
67 /**
68  * UsbDeviceManager manages USB state in device mode.
69  */
70 public class UsbDeviceManager {
71
72     private static final String TAG = "UsbDeviceManager";
73     private static final boolean DEBUG = false;
74
75     /**
76      * The persistent property which stores whether adb is enabled or not.
77      * May also contain vendor-specific default functions for testing purposes.
78      */
79     private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
80
81     /**
82      * The non-persistent property which stores the current USB settings.
83      */
84     private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
85
86     /**
87      * The non-persistent property which stores the current USB actual state.
88      */
89     private static final String USB_STATE_PROPERTY = "sys.usb.state";
90
91     private static final String USB_STATE_MATCH =
92             "DEVPATH=/devices/virtual/android_usb/android0";
93     private static final String ACCESSORY_START_MATCH =
94             "DEVPATH=/devices/virtual/misc/usb_accessory";
95     private static final String FUNCTIONS_PATH =
96             "/sys/class/android_usb/android0/functions";
97     private static final String STATE_PATH =
98             "/sys/class/android_usb/android0/state";
99     private static final String RNDIS_ETH_ADDR_PATH =
100             "/sys/class/android_usb/android0/f_rndis/ethaddr";
101     private static final String AUDIO_SOURCE_PCM_PATH =
102             "/sys/class/android_usb/android0/f_audio_source/pcm";
103     private static final String MIDI_ALSA_PATH =
104             "/sys/class/android_usb/android0/f_midi/alsa";
105
106     private static final int MSG_UPDATE_STATE = 0;
107     private static final int MSG_ENABLE_ADB = 1;
108     private static final int MSG_SET_CURRENT_FUNCTIONS = 2;
109     private static final int MSG_SYSTEM_READY = 3;
110     private static final int MSG_BOOT_COMPLETED = 4;
111     private static final int MSG_USER_SWITCHED = 5;
112     private static final int MSG_SET_USB_DATA_UNLOCKED = 6;
113     private static final int MSG_UPDATE_USER_RESTRICTIONS = 7;
114     private static final int MSG_UPDATE_HOST_STATE = 8;
115
116     private static final int AUDIO_MODE_SOURCE = 1;
117
118     // Delay for debouncing USB disconnects.
119     // We often get rapid connect/disconnect events when enabling USB functions,
120     // which need debouncing.
121     private static final int UPDATE_DELAY = 1000;
122
123     // Time we received a request to enter USB accessory mode
124     private long mAccessoryModeRequestTime = 0;
125
126     // Timeout for entering USB request mode.
127     // Request is cancelled if host does not configure device within 10 seconds.
128     private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
129
130     private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
131
132     private UsbHandler mHandler;
133     private boolean mBootCompleted;
134
135     private final Object mLock = new Object();
136
137     private final Context mContext;
138     private final ContentResolver mContentResolver;
139     @GuardedBy("mLock")
140     private UsbSettingsManager mCurrentSettings;
141     private NotificationManager mNotificationManager;
142     private final boolean mHasUsbAccessory;
143     private boolean mUseUsbNotification;
144     private boolean mAdbEnabled;
145     private boolean mAudioSourceEnabled;
146     private boolean mMidiEnabled;
147     private int mMidiCard;
148     private int mMidiDevice;
149     private Map<String, List<Pair<String, String>>> mOemModeMap;
150     private String[] mAccessoryStrings;
151     private UsbDebuggingManager mDebuggingManager;
152     private final UsbAlsaManager mUsbAlsaManager;
153     private Intent mBroadcastedIntent;
154
155     private class AdbSettingsObserver extends ContentObserver {
156         public AdbSettingsObserver() {
157             super(null);
158         }
159         @Override
160         public void onChange(boolean selfChange) {
161             boolean enable = (Settings.Global.getInt(mContentResolver,
162                     Settings.Global.ADB_ENABLED, 0) > 0);
163             mHandler.sendMessage(MSG_ENABLE_ADB, enable);
164         }
165     }
166
167     /*
168      * Listens for uevent messages from the kernel to monitor the USB state
169      */
170     private final UEventObserver mUEventObserver = new UEventObserver() {
171         @Override
172         public void onUEvent(UEventObserver.UEvent event) {
173             if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
174
175             String state = event.get("USB_STATE");
176             String accessory = event.get("ACCESSORY");
177             if (state != null) {
178                 mHandler.updateState(state);
179             } else if ("START".equals(accessory)) {
180                 if (DEBUG) Slog.d(TAG, "got accessory start");
181                 startAccessoryMode();
182             }
183         }
184     };
185
186     private final BroadcastReceiver mHostReceiver = new BroadcastReceiver() {
187         @Override
188         public void onReceive(Context context, Intent intent) {
189             UsbPort port = intent.getParcelableExtra(UsbManager.EXTRA_PORT);
190             UsbPortStatus status = intent.getParcelableExtra(UsbManager.EXTRA_PORT_STATUS);
191             mHandler.updateHostState(port, status);
192         }
193     };
194
195     public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
196         mContext = context;
197         mUsbAlsaManager = alsaManager;
198         mContentResolver = context.getContentResolver();
199         PackageManager pm = mContext.getPackageManager();
200         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
201         initRndisAddress();
202
203         readOemUsbOverrideConfig();
204
205         mHandler = new UsbHandler(FgThread.get().getLooper());
206
207         if (nativeIsStartRequested()) {
208             if (DEBUG) Slog.d(TAG, "accessory attached at boot");
209             startAccessoryMode();
210         }
211
212         boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
213         boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
214         if (secureAdbEnabled && !dataEncrypted) {
215             mDebuggingManager = new UsbDebuggingManager(context);
216         }
217         mContext.registerReceiver(mHostReceiver,
218                 new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
219     }
220
221     private UsbSettingsManager getCurrentSettings() {
222         synchronized (mLock) {
223             return mCurrentSettings;
224         }
225     }
226
227     public void systemReady() {
228         if (DEBUG) Slog.d(TAG, "systemReady");
229
230         mNotificationManager = (NotificationManager)
231                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
232
233         // We do not show the USB notification if the primary volume supports mass storage.
234         // The legacy mass storage UI will be used instead.
235         boolean massStorageSupported = false;
236         final StorageManager storageManager = StorageManager.from(mContext);
237         final StorageVolume primary = storageManager.getPrimaryVolume();
238         massStorageSupported = primary != null && primary.allowMassStorage();
239         mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
240                 com.android.internal.R.bool.config_usbChargingMessage);
241
242         // make sure the ADB_ENABLED setting value matches the current state
243         try {
244             Settings.Global.putInt(mContentResolver,
245                     Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
246         } catch (SecurityException e) {
247             // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
248             Slog.d(TAG, "ADB_ENABLED is restricted.");
249         }
250         mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
251     }
252
253     public void bootCompleted() {
254         if (DEBUG) Slog.d(TAG, "boot completed");
255         mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
256     }
257
258     public void setCurrentUser(int userId, UsbSettingsManager settings) {
259         synchronized (mLock) {
260             mCurrentSettings = settings;
261             mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
262         }
263     }
264
265     public void updateUserRestrictions() {
266         mHandler.sendEmptyMessage(MSG_UPDATE_USER_RESTRICTIONS);
267     }
268
269     private void startAccessoryMode() {
270         if (!mHasUsbAccessory) return;
271
272         mAccessoryStrings = nativeGetAccessoryStrings();
273         boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
274         // don't start accessory mode if our mandatory strings have not been set
275         boolean enableAccessory = (mAccessoryStrings != null &&
276                         mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
277                         mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
278         String functions = null;
279
280         if (enableAccessory && enableAudio) {
281             functions = UsbManager.USB_FUNCTION_ACCESSORY + ","
282                     + UsbManager.USB_FUNCTION_AUDIO_SOURCE;
283         } else if (enableAccessory) {
284             functions = UsbManager.USB_FUNCTION_ACCESSORY;
285         } else if (enableAudio) {
286             functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
287         }
288
289         if (functions != null) {
290             mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
291             setCurrentFunctions(functions);
292         }
293     }
294
295     private static void initRndisAddress() {
296         // configure RNDIS ethernet address based on our serial number using the same algorithm
297         // we had been previously using in kernel board files
298         final int ETH_ALEN = 6;
299         int address[] = new int[ETH_ALEN];
300         // first byte is 0x02 to signify a locally administered address
301         address[0] = 0x02;
302
303         String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
304         int serialLength = serial.length();
305         // XOR the USB serial across the remaining 5 bytes
306         for (int i = 0; i < serialLength; i++) {
307             address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
308         }
309         String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
310             address[0], address[1], address[2], address[3], address[4], address[5]);
311         try {
312             FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
313         } catch (IOException e) {
314            Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
315         }
316     }
317
318     private final class UsbHandler extends Handler {
319
320         // current USB state
321         private boolean mConnected;
322         private boolean mHostConnected;
323         private boolean mSourcePower;
324         private boolean mSinkPower;
325         private boolean mConfigured;
326         private boolean mUsbDataUnlocked;
327         private String mCurrentFunctions;
328         private boolean mCurrentFunctionsApplied;
329         private UsbAccessory mCurrentAccessory;
330         private int mUsbNotificationId;
331         private boolean mAdbNotificationShown;
332         private int mCurrentUser = UserHandle.USER_NULL;
333
334         public UsbHandler(Looper looper) {
335             super(looper);
336             try {
337                 // Restore default functions.
338                 mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
339                         UsbManager.USB_FUNCTION_NONE);
340                 if (UsbManager.USB_FUNCTION_NONE.equals(mCurrentFunctions)) {
341                     mCurrentFunctions = UsbManager.USB_FUNCTION_MTP;
342                 }
343                 mCurrentFunctionsApplied = mCurrentFunctions.equals(
344                         SystemProperties.get(USB_STATE_PROPERTY));
345                 mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),
346                         UsbManager.USB_FUNCTION_ADB);
347                 setEnabledFunctions(null, false);
348
349                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
350                 updateState(state);
351
352                 // register observer to listen for settings changes
353                 mContentResolver.registerContentObserver(
354                         Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
355                                 false, new AdbSettingsObserver());
356
357                 // Watch for USB configuration changes
358                 mUEventObserver.startObserving(USB_STATE_MATCH);
359                 mUEventObserver.startObserving(ACCESSORY_START_MATCH);
360             } catch (Exception e) {
361                 Slog.e(TAG, "Error initializing UsbHandler", e);
362             }
363         }
364
365         public void sendMessage(int what, boolean arg) {
366             removeMessages(what);
367             Message m = Message.obtain(this, what);
368             m.arg1 = (arg ? 1 : 0);
369             sendMessage(m);
370         }
371
372         public void sendMessage(int what, Object arg) {
373             removeMessages(what);
374             Message m = Message.obtain(this, what);
375             m.obj = arg;
376             sendMessage(m);
377         }
378
379         public void updateState(String state) {
380             int connected, configured;
381
382             if ("DISCONNECTED".equals(state)) {
383                 connected = 0;
384                 configured = 0;
385             } else if ("CONNECTED".equals(state)) {
386                 connected = 1;
387                 configured = 0;
388             } else if ("CONFIGURED".equals(state)) {
389                 connected = 1;
390                 configured = 1;
391             } else {
392                 Slog.e(TAG, "unknown state " + state);
393                 return;
394             }
395             removeMessages(MSG_UPDATE_STATE);
396             Message msg = Message.obtain(this, MSG_UPDATE_STATE);
397             msg.arg1 = connected;
398             msg.arg2 = configured;
399             // debounce disconnects to avoid problems bringing up USB tethering
400             sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
401         }
402
403         public void updateHostState(UsbPort port, UsbPortStatus status) {
404             boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
405             boolean sourcePower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SOURCE;
406             boolean sinkPower = status.getCurrentPowerRole() == UsbPort.POWER_ROLE_SINK;
407
408             if (DEBUG) {
409                 Slog.i(TAG, "updateHostState " + port + " status=" + status);
410             }
411
412             SomeArgs args = SomeArgs.obtain();
413             args.argi1 = hostConnected ? 1 :0;
414             args.argi2 = sourcePower ? 1 :0;
415             args.argi3 = sinkPower ? 1 :0;
416
417             obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget();
418         }
419
420         private boolean waitForState(String state) {
421             // wait for the transition to complete.
422             // give up after 1 second.
423             String value = null;
424             for (int i = 0; i < 20; i++) {
425                 // State transition is done when sys.usb.state is set to the new configuration
426                 value = SystemProperties.get(USB_STATE_PROPERTY);
427                 if (state.equals(value)) return true;
428                 SystemClock.sleep(50);
429             }
430             Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
431             return false;
432         }
433
434         private boolean setUsbConfig(String config) {
435             if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
436             // set the new configuration
437             // we always set it due to b/23631400, where adbd was getting killed
438             // and not restarted due to property timeouts on some devices
439             SystemProperties.set(USB_CONFIG_PROPERTY, config);
440             return waitForState(config);
441         }
442
443         private void setUsbDataUnlocked(boolean enable) {
444             if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable);
445             mUsbDataUnlocked = enable;
446             updateUsbNotification();
447             updateUsbStateBroadcastIfNeeded();
448             setEnabledFunctions(mCurrentFunctions, true);
449         }
450
451         private void setAdbEnabled(boolean enable) {
452             if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
453             if (enable != mAdbEnabled) {
454                 mAdbEnabled = enable;
455
456                 // Due to the persist.sys.usb.config property trigger, changing adb state requires
457                 // persisting default function
458                 String oldFunctions = getDefaultFunctions();
459                 String newFunctions = applyAdbFunction(oldFunctions);
460                 if (!oldFunctions.equals(newFunctions)) {
461                     SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions);
462                 }
463
464                 // After persisting them use the lock-down aware function set
465                 setEnabledFunctions(mCurrentFunctions, false);
466                 updateAdbNotification();
467             }
468
469             if (mDebuggingManager != null) {
470                 mDebuggingManager.setAdbEnabled(mAdbEnabled);
471             }
472         }
473
474         /**
475          * Evaluates USB function policies and applies the change accordingly.
476          */
477         private void setEnabledFunctions(String functions, boolean forceRestart) {
478             if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
479                     + "forceRestart=" + forceRestart);
480
481             // Try to set the enabled functions.
482             final String oldFunctions = mCurrentFunctions;
483             final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
484             if (trySetEnabledFunctions(functions, forceRestart)) {
485                 return;
486             }
487
488             // Didn't work.  Try to revert changes.
489             // We always reapply the policy in case certain constraints changed such as
490             // user restrictions independently of any other new functions we were
491             // trying to activate.
492             if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
493                 Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
494                 if (trySetEnabledFunctions(oldFunctions, false)) {
495                     return;
496                 }
497             }
498
499             // Still didn't work.  Try to restore the default functions.
500             Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
501             if (trySetEnabledFunctions(null, false)) {
502                 return;
503             }
504
505             // Now we're desperate.  Ignore the default functions.
506             // Try to get ADB working if enabled.
507             Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
508             if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
509                 return;
510             }
511
512             // Ouch.
513             Slog.e(TAG, "Unable to set any USB functions!");
514         }
515
516         private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
517             if (functions == null) {
518                 functions = getDefaultFunctions();
519             }
520             functions = applyAdbFunction(functions);
521             functions = applyOemOverrideFunction(functions);
522
523             if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied
524                     || forceRestart) {
525                 Slog.i(TAG, "Setting USB config to " + functions);
526                 mCurrentFunctions = functions;
527                 mCurrentFunctionsApplied = false;
528
529                 // Kick the USB stack to close existing connections.
530                 setUsbConfig(UsbManager.USB_FUNCTION_NONE);
531
532                 // Set the new USB configuration.
533                 if (!setUsbConfig(functions)) {
534                     Slog.e(TAG, "Failed to switch USB config to " + functions);
535                     return false;
536                 }
537
538                 mCurrentFunctionsApplied = true;
539             }
540             return true;
541         }
542
543         private String applyAdbFunction(String functions) {
544             if (mAdbEnabled) {
545                 functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB);
546             } else {
547                 functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
548             }
549             return functions;
550         }
551
552         private boolean isUsbTransferAllowed() {
553             UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
554             return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
555         }
556
557         private void updateCurrentAccessory() {
558             // We are entering accessory mode if we have received a request from the host
559             // and the request has not timed out yet.
560             boolean enteringAccessoryMode =
561                     mAccessoryModeRequestTime > 0 &&
562                         SystemClock.elapsedRealtime() <
563                             mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
564
565             if (mConfigured && enteringAccessoryMode) {
566                 // successfully entered accessory mode
567
568                 if (mAccessoryStrings != null) {
569                     mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
570                     Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
571                     // defer accessoryAttached if system is not ready
572                     if (mBootCompleted) {
573                         getCurrentSettings().accessoryAttached(mCurrentAccessory);
574                     } // else handle in boot completed
575                 } else {
576                     Slog.e(TAG, "nativeGetAccessoryStrings failed");
577                 }
578             } else if (!enteringAccessoryMode) {
579                 // make sure accessory mode is off
580                 // and restore default functions
581                 Slog.d(TAG, "exited USB accessory mode");
582                 setEnabledFunctions(null, false);
583
584                 if (mCurrentAccessory != null) {
585                     if (mBootCompleted) {
586                         getCurrentSettings().accessoryDetached(mCurrentAccessory);
587                     }
588                     mCurrentAccessory = null;
589                     mAccessoryStrings = null;
590                 }
591             }
592         }
593
594         private boolean isUsbStateChanged(Intent intent) {
595             final Set<String> keySet = intent.getExtras().keySet();
596             if (mBroadcastedIntent == null) {
597                 for (String key : keySet) {
598                     if (intent.getBooleanExtra(key, false)) {
599                         // MTP function is enabled by default.
600                         if (UsbManager.USB_FUNCTION_MTP.equals(key)) {
601                             continue;
602                         }
603                         return true;
604                     }
605                 }
606             } else {
607                 if (!keySet.equals(mBroadcastedIntent.getExtras().keySet())) {
608                     return true;
609                 }
610                 for (String key : keySet) {
611                     if (intent.getBooleanExtra(key, false) !=
612                         mBroadcastedIntent.getBooleanExtra(key, false)) {
613                         return true;
614                     }
615                 }
616             }
617             return false;
618         }
619
620         private void updateUsbStateBroadcastIfNeeded() {
621             // send a sticky broadcast containing current USB state
622             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
623             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
624                     | Intent.FLAG_RECEIVER_FOREGROUND);
625             intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
626             intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
627             intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
628             intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked);
629
630             if (mCurrentFunctions != null) {
631                 String[] functions = mCurrentFunctions.split(",");
632                 for (int i = 0; i < functions.length; i++) {
633                     final String function = functions[i];
634                     if (UsbManager.USB_FUNCTION_NONE.equals(function)) {
635                         continue;
636                     }
637                     intent.putExtra(function, true);
638                 }
639             }
640
641             // send broadcast intent only if the USB state has changed
642             if (!isUsbStateChanged(intent)) {
643                 if (DEBUG) {
644                     Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
645                 }
646                 return;
647             }
648
649             if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
650             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
651             mBroadcastedIntent = intent;
652         }
653
654         private void updateUsbFunctions() {
655             updateAudioSourceFunction();
656             updateMidiFunction();
657         }
658
659         private void updateAudioSourceFunction() {
660             boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
661                     UsbManager.USB_FUNCTION_AUDIO_SOURCE);
662             if (enabled != mAudioSourceEnabled) {
663                 int card = -1;
664                 int device = -1;
665
666                 if (enabled) {
667                     Scanner scanner = null;
668                     try {
669                         scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
670                         card = scanner.nextInt();
671                         device = scanner.nextInt();
672                     } catch (FileNotFoundException e) {
673                         Slog.e(TAG, "could not open audio source PCM file", e);
674                     } finally {
675                         if (scanner != null) {
676                             scanner.close();
677                         }
678                     }
679                 }
680                 mUsbAlsaManager.setAccessoryAudioState(enabled, card, device);
681                 mAudioSourceEnabled = enabled;
682             }
683         }
684
685         private void updateMidiFunction() {
686             boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
687                     UsbManager.USB_FUNCTION_MIDI);
688             if (enabled != mMidiEnabled) {
689                 if (enabled) {
690                     Scanner scanner = null;
691                     try {
692                         scanner = new Scanner(new File(MIDI_ALSA_PATH));
693                         mMidiCard = scanner.nextInt();
694                         mMidiDevice = scanner.nextInt();
695                     } catch (FileNotFoundException e) {
696                         Slog.e(TAG, "could not open MIDI PCM file", e);
697                         enabled = false;
698                     } finally {
699                         if (scanner != null) {
700                             scanner.close();
701                         }
702                     }
703                 }
704                 mMidiEnabled = enabled;
705             }
706             mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
707         }
708
709         @Override
710         public void handleMessage(Message msg) {
711             switch (msg.what) {
712                 case MSG_UPDATE_STATE:
713                     mConnected = (msg.arg1 == 1);
714                     mConfigured = (msg.arg2 == 1);
715                     if (!mConnected) {
716                         // When a disconnect occurs, relock access to sensitive user data
717                         mUsbDataUnlocked = false;
718                     }
719                     updateUsbNotification();
720                     updateAdbNotification();
721                     if (UsbManager.containsFunction(mCurrentFunctions,
722                             UsbManager.USB_FUNCTION_ACCESSORY)) {
723                         updateCurrentAccessory();
724                     } else if (!mConnected) {
725                         // restore defaults when USB is disconnected
726                         setEnabledFunctions(null, false);
727                     }
728                     if (mBootCompleted) {
729                         updateUsbStateBroadcastIfNeeded();
730                         updateUsbFunctions();
731                     }
732                     break;
733                 case MSG_UPDATE_HOST_STATE:
734                     SomeArgs args = (SomeArgs) msg.obj;
735                     mHostConnected = (args.argi1 == 1);
736                     mSourcePower = (args.argi2 == 1);
737                     mSinkPower = (args.argi3 == 1);
738                     args.recycle();
739                     updateUsbNotification();
740                     if (mBootCompleted) {
741                         updateUsbStateBroadcastIfNeeded();
742                     }
743                     break;
744                 case MSG_ENABLE_ADB:
745                     setAdbEnabled(msg.arg1 == 1);
746                     break;
747                 case MSG_SET_CURRENT_FUNCTIONS:
748                     String functions = (String)msg.obj;
749                     setEnabledFunctions(functions, false);
750                     break;
751                 case MSG_UPDATE_USER_RESTRICTIONS:
752                     setEnabledFunctions(mCurrentFunctions, false);
753                     break;
754                 case MSG_SET_USB_DATA_UNLOCKED:
755                     setUsbDataUnlocked(msg.arg1 == 1);
756                     break;
757                 case MSG_SYSTEM_READY:
758                     updateUsbNotification();
759                     updateAdbNotification();
760                     updateUsbStateBroadcastIfNeeded();
761                     updateUsbFunctions();
762                     break;
763                 case MSG_BOOT_COMPLETED:
764                     mBootCompleted = true;
765                     if (mCurrentAccessory != null) {
766                         getCurrentSettings().accessoryAttached(mCurrentAccessory);
767                     }
768                     if (mDebuggingManager != null) {
769                         mDebuggingManager.setAdbEnabled(mAdbEnabled);
770                     }
771                     break;
772                 case MSG_USER_SWITCHED: {
773                     if (mCurrentUser != msg.arg1) {
774                         // Restart the USB stack and re-apply user restrictions for MTP or PTP.
775                         final boolean active = UsbManager.containsFunction(mCurrentFunctions,
776                                         UsbManager.USB_FUNCTION_MTP)
777                                 || UsbManager.containsFunction(mCurrentFunctions,
778                                         UsbManager.USB_FUNCTION_PTP);
779                         if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) {
780                             Slog.v(TAG, "Current user switched to " + mCurrentUser
781                                     + "; resetting USB host stack for MTP or PTP");
782                             // avoid leaking sensitive data from previous user
783                             mUsbDataUnlocked = false;
784                             setEnabledFunctions(mCurrentFunctions, true);
785                         }
786                         mCurrentUser = msg.arg1;
787                     }
788                     break;
789                 }
790             }
791         }
792
793         public UsbAccessory getCurrentAccessory() {
794             return mCurrentAccessory;
795         }
796
797         private void updateUsbNotification() {
798             if (mNotificationManager == null || !mUseUsbNotification
799                     || ("0".equals(SystemProperties.get("persist.charging.notify")))) return;
800             int id = 0;
801             Resources r = mContext.getResources();
802             if (mConnected) {
803                 if (!mUsbDataUnlocked) {
804                     if (mSourcePower) {
805                         id = com.android.internal.R.string.usb_supplying_notification_title;
806                     } else {
807                         id = com.android.internal.R.string.usb_charging_notification_title;
808                     }
809                 } else if (UsbManager.containsFunction(mCurrentFunctions,
810                         UsbManager.USB_FUNCTION_MTP)) {
811                     id = com.android.internal.R.string.usb_mtp_notification_title;
812                 } else if (UsbManager.containsFunction(mCurrentFunctions,
813                         UsbManager.USB_FUNCTION_PTP)) {
814                     id = com.android.internal.R.string.usb_ptp_notification_title;
815                 } else if (UsbManager.containsFunction(mCurrentFunctions,
816                         UsbManager.USB_FUNCTION_MIDI)) {
817                     id = com.android.internal.R.string.usb_midi_notification_title;
818                 } else if (UsbManager.containsFunction(mCurrentFunctions,
819                         UsbManager.USB_FUNCTION_ACCESSORY)) {
820                     id = com.android.internal.R.string.usb_accessory_notification_title;
821                 } else if (mSourcePower) {
822                     id = com.android.internal.R.string.usb_supplying_notification_title;
823                 } else {
824                     id = com.android.internal.R.string.usb_charging_notification_title;
825                 }
826             } else if (mSourcePower) {
827                 id = com.android.internal.R.string.usb_supplying_notification_title;
828             } else if (mHostConnected && mSinkPower) {
829                 id = com.android.internal.R.string.usb_charging_notification_title;
830             }
831             if (id != mUsbNotificationId) {
832                 // clear notification if title needs changing
833                 if (mUsbNotificationId != 0) {
834                     mNotificationManager.cancelAsUser(null, mUsbNotificationId,
835                             UserHandle.ALL);
836                     mUsbNotificationId = 0;
837                 }
838                 if (id != 0) {
839                     CharSequence message = r.getText(
840                             com.android.internal.R.string.usb_notification_message);
841                     CharSequence title = r.getText(id);
842
843                     Intent intent = Intent.makeRestartActivityTask(
844                             new ComponentName("com.android.settings",
845                                     "com.android.settings.deviceinfo.UsbModeChooserActivity"));
846                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
847                             intent, 0, null, UserHandle.CURRENT);
848
849                     Notification notification = new Notification.Builder(mContext)
850                             .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
851                             .setWhen(0)
852                             .setOngoing(true)
853                             .setTicker(title)
854                             .setDefaults(0)  // please be quiet
855                             .setPriority(Notification.PRIORITY_MIN)
856                             .setColor(mContext.getColor(
857                                     com.android.internal.R.color.system_notification_accent_color))
858                             .setContentTitle(title)
859                             .setContentText(message)
860                             .setContentIntent(pi)
861                             .setVisibility(Notification.VISIBILITY_PUBLIC)
862                             .build();
863                     mNotificationManager.notifyAsUser(null, id, notification,
864                             UserHandle.ALL);
865                     mUsbNotificationId = id;
866                 }
867             }
868         }
869
870         private void updateAdbNotification() {
871             if (mNotificationManager == null) return;
872             final int id = com.android.internal.R.string.adb_active_notification_title;
873             if (mAdbEnabled && mConnected) {
874                 if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
875
876                 if (!mAdbNotificationShown) {
877                     Resources r = mContext.getResources();
878                     CharSequence title = r.getText(id);
879                     CharSequence message = r.getText(
880                             com.android.internal.R.string.adb_active_notification_message);
881
882                     Intent intent = Intent.makeRestartActivityTask(
883                             new ComponentName("com.android.settings",
884                                     "com.android.settings.DevelopmentSettings"));
885                     PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
886                             intent, 0, null, UserHandle.CURRENT);
887
888                     Notification notification = new Notification.Builder(mContext)
889                             .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
890                             .setWhen(0)
891                             .setOngoing(true)
892                             .setTicker(title)
893                             .setDefaults(0)  // please be quiet
894                             .setPriority(Notification.PRIORITY_DEFAULT)
895                             .setColor(mContext.getColor(
896                                     com.android.internal.R.color.system_notification_accent_color))
897                             .setContentTitle(title)
898                             .setContentText(message)
899                             .setContentIntent(pi)
900                             .setVisibility(Notification.VISIBILITY_PUBLIC)
901                             .build();
902                     mAdbNotificationShown = true;
903                     mNotificationManager.notifyAsUser(null, id, notification,
904                             UserHandle.ALL);
905                 }
906             } else if (mAdbNotificationShown) {
907                 mAdbNotificationShown = false;
908                 mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
909             }
910         }
911
912         private String getDefaultFunctions() {
913             String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY,
914                     UsbManager.USB_FUNCTION_NONE);
915             if (UsbManager.USB_FUNCTION_NONE.equals(func)) {
916                 func = UsbManager.USB_FUNCTION_MTP;
917             }
918             return func;
919         }
920
921         public void dump(IndentingPrintWriter pw) {
922             pw.println("USB Device State:");
923             pw.println("  mCurrentFunctions: " + mCurrentFunctions);
924             pw.println("  mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
925             pw.println("  mConnected: " + mConnected);
926             pw.println("  mConfigured: " + mConfigured);
927             pw.println("  mUsbDataUnlocked: " + mUsbDataUnlocked);
928             pw.println("  mCurrentAccessory: " + mCurrentAccessory);
929             pw.println("  mHostConnected: " + mHostConnected);
930             pw.println("  mSourcePower: " + mSourcePower);
931             pw.println("  mSinkPower: " + mSinkPower);
932             try {
933                 pw.println("  Kernel state: "
934                         + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
935                 pw.println("  Kernel function list: "
936                         + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
937             } catch (IOException e) {
938                 pw.println("IOException: " + e);
939             }
940         }
941     }
942
943     /* returns the currently attached USB accessory */
944     public UsbAccessory getCurrentAccessory() {
945         return mHandler.getCurrentAccessory();
946     }
947
948     /* opens the currently attached USB accessory */
949     public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
950         UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
951         if (currentAccessory == null) {
952             throw new IllegalArgumentException("no accessory attached");
953         }
954         if (!currentAccessory.equals(accessory)) {
955             String error = accessory.toString()
956                     + " does not match current accessory "
957                     + currentAccessory;
958             throw new IllegalArgumentException(error);
959         }
960         getCurrentSettings().checkPermission(accessory);
961         return nativeOpenAccessory();
962     }
963
964     public boolean isFunctionEnabled(String function) {
965         return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
966     }
967
968     public void setCurrentFunctions(String functions) {
969         if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
970         mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
971     }
972
973     public void setUsbDataUnlocked(boolean unlocked) {
974         if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")");
975         mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked);
976     }
977
978     private void readOemUsbOverrideConfig() {
979         String[] configList = mContext.getResources().getStringArray(
980             com.android.internal.R.array.config_oemUsbModeOverride);
981
982         if (configList != null) {
983             for (String config: configList) {
984                 String[] items = config.split(":");
985                 if (items.length == 3) {
986                     if (mOemModeMap == null) {
987                         mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
988                     }
989                     List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
990                     if (overrideList == null) {
991                         overrideList = new LinkedList<Pair<String, String>>();
992                         mOemModeMap.put(items[0], overrideList);
993                     }
994                     overrideList.add(new Pair<String, String>(items[1], items[2]));
995                 }
996             }
997         }
998     }
999
1000     private String applyOemOverrideFunction(String usbFunctions) {
1001         if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
1002
1003         String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
1004
1005         List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
1006         if (overrides != null) {
1007             for (Pair<String, String> pair: overrides) {
1008                 if (pair.first.equals(usbFunctions)) {
1009                     Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
1010                     return pair.second;
1011                 }
1012             }
1013         }
1014         // return passed in functions as is.
1015         return usbFunctions;
1016     }
1017
1018     public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
1019         if (mDebuggingManager != null) {
1020             mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
1021         }
1022     }
1023
1024     public void denyUsbDebugging() {
1025         if (mDebuggingManager != null) {
1026             mDebuggingManager.denyUsbDebugging();
1027         }
1028     }
1029
1030     public void clearUsbDebuggingKeys() {
1031         if (mDebuggingManager != null) {
1032             mDebuggingManager.clearUsbDebuggingKeys();
1033         } else {
1034             throw new RuntimeException("Cannot clear Usb Debugging keys, "
1035                         + "UsbDebuggingManager not enabled");
1036         }
1037     }
1038
1039     public void dump(IndentingPrintWriter pw) {
1040         if (mHandler != null) {
1041             mHandler.dump(pw);
1042         }
1043         if (mDebuggingManager != null) {
1044             mDebuggingManager.dump(pw);
1045         }
1046     }
1047
1048     private native String[] nativeGetAccessoryStrings();
1049     private native ParcelFileDescriptor nativeOpenAccessory();
1050     private native boolean nativeIsStartRequested();
1051     private native int nativeGetAudioMode();
1052 }