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