UsbDeviceManager.java revision 8338ed00ae44635d099b530b3360e6d1f7041827
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;
237
238        // make sure the ADB_ENABLED setting value matches the current state
239        try {
240            Settings.Global.putInt(mContentResolver,
241                    Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
242        } catch (SecurityException e) {
243            // If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't be changed.
244            Slog.d(TAG, "ADB_ENABLED is restricted.");
245        }
246        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
247    }
248
249    public void bootCompleted() {
250        if (DEBUG) Slog.d(TAG, "boot completed");
251        mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
252    }
253
254    public void setCurrentUser(int userId, UsbSettingsManager settings) {
255        synchronized (mLock) {
256            mCurrentSettings = settings;
257            mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
258        }
259    }
260
261    public void updateUserRestrictions() {
262        mHandler.sendEmptyMessage(MSG_UPDATE_USER_RESTRICTIONS);
263    }
264
265    private void startAccessoryMode() {
266        if (!mHasUsbAccessory) return;
267
268        mAccessoryStrings = nativeGetAccessoryStrings();
269        boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
270        // don't start accessory mode if our mandatory strings have not been set
271        boolean enableAccessory = (mAccessoryStrings != null &&
272                        mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
273                        mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
274        String functions = null;
275
276        if (enableAccessory && enableAudio) {
277            functions = UsbManager.USB_FUNCTION_ACCESSORY + ","
278                    + UsbManager.USB_FUNCTION_AUDIO_SOURCE;
279        } else if (enableAccessory) {
280            functions = UsbManager.USB_FUNCTION_ACCESSORY;
281        } else if (enableAudio) {
282            functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
283        }
284
285        if (functions != null) {
286            mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
287            setCurrentFunctions(functions);
288        }
289    }
290
291    private static void initRndisAddress() {
292        // configure RNDIS ethernet address based on our serial number using the same algorithm
293        // we had been previously using in kernel board files
294        final int ETH_ALEN = 6;
295        int address[] = new int[ETH_ALEN];
296        // first byte is 0x02 to signify a locally administered address
297        address[0] = 0x02;
298
299        String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
300        int serialLength = serial.length();
301        // XOR the USB serial across the remaining 5 bytes
302        for (int i = 0; i < serialLength; i++) {
303            address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
304        }
305        String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
306            address[0], address[1], address[2], address[3], address[4], address[5]);
307        try {
308            FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
309        } catch (IOException e) {
310           Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
311        }
312    }
313
314    private final class UsbHandler extends Handler {
315
316        // current USB state
317        private boolean mConnected;
318        private boolean mHostConnected;
319        private boolean mConfigured;
320        private boolean mUsbDataUnlocked;
321        private String mCurrentFunctions;
322        private boolean mCurrentFunctionsApplied;
323        private UsbAccessory mCurrentAccessory;
324        private int mUsbNotificationId;
325        private boolean mAdbNotificationShown;
326        private int mCurrentUser = UserHandle.USER_NULL;
327
328        public UsbHandler(Looper looper) {
329            super(looper);
330            try {
331                // Restore default functions.
332                mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
333                        UsbManager.USB_FUNCTION_NONE);
334                if (UsbManager.USB_FUNCTION_NONE.equals(mCurrentFunctions)) {
335                    mCurrentFunctions = UsbManager.USB_FUNCTION_MTP;
336                }
337                mCurrentFunctionsApplied = mCurrentFunctions.equals(
338                        SystemProperties.get(USB_STATE_PROPERTY));
339                mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),
340                        UsbManager.USB_FUNCTION_ADB);
341                setEnabledFunctions(null, false);
342
343                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
344                updateState(state);
345
346                // register observer to listen for settings changes
347                mContentResolver.registerContentObserver(
348                        Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
349                                false, new AdbSettingsObserver());
350
351                // Watch for USB configuration changes
352                mUEventObserver.startObserving(USB_STATE_MATCH);
353                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
354            } catch (Exception e) {
355                Slog.e(TAG, "Error initializing UsbHandler", e);
356            }
357        }
358
359        public void sendMessage(int what, boolean arg) {
360            removeMessages(what);
361            Message m = Message.obtain(this, what);
362            m.arg1 = (arg ? 1 : 0);
363            sendMessage(m);
364        }
365
366        public void sendMessage(int what, Object arg) {
367            removeMessages(what);
368            Message m = Message.obtain(this, what);
369            m.obj = arg;
370            sendMessage(m);
371        }
372
373        public void updateState(String state) {
374            int connected, configured;
375
376            if ("DISCONNECTED".equals(state)) {
377                connected = 0;
378                configured = 0;
379            } else if ("CONNECTED".equals(state)) {
380                connected = 1;
381                configured = 0;
382            } else if ("CONFIGURED".equals(state)) {
383                connected = 1;
384                configured = 1;
385            } else {
386                Slog.e(TAG, "unknown state " + state);
387                return;
388            }
389            removeMessages(MSG_UPDATE_STATE);
390            Message msg = Message.obtain(this, MSG_UPDATE_STATE);
391            msg.arg1 = connected;
392            msg.arg2 = configured;
393            // debounce disconnects to avoid problems bringing up USB tethering
394            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
395        }
396
397        public void updateHostState(UsbPort port, UsbPortStatus status) {
398            boolean hostConnected = status.getCurrentDataRole() == UsbPort.DATA_ROLE_HOST;
399            obtainMessage(MSG_UPDATE_HOST_STATE, hostConnected ? 1 :0, 0).sendToTarget();
400        }
401
402        private boolean waitForState(String state) {
403            // wait for the transition to complete.
404            // give up after 1 second.
405            String value = null;
406            for (int i = 0; i < 20; i++) {
407                // State transition is done when sys.usb.state is set to the new configuration
408                value = SystemProperties.get(USB_STATE_PROPERTY);
409                if (state.equals(value)) return true;
410                SystemClock.sleep(50);
411            }
412            Slog.e(TAG, "waitForState(" + state + ") FAILED: got " + value);
413            return false;
414        }
415
416        private boolean setUsbConfig(String config) {
417            if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
418            // set the new configuration
419            String oldConfig = SystemProperties.get(USB_CONFIG_PROPERTY);
420            if (!config.equals(oldConfig)) {
421                SystemProperties.set(USB_CONFIG_PROPERTY, config);
422            }
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                            setEnabledFunctions(mCurrentFunctions, true);
720                        }
721                        mCurrentUser = msg.arg1;
722                    }
723                    break;
724                }
725            }
726        }
727
728        public UsbAccessory getCurrentAccessory() {
729            return mCurrentAccessory;
730        }
731
732        private void updateUsbNotification() {
733            if (mNotificationManager == null || !mUseUsbNotification) return;
734            int id = 0;
735            Resources r = mContext.getResources();
736            if (mConnected || mHostConnected) {
737                if (!mUsbDataUnlocked) {
738                    id = com.android.internal.R.string.usb_charging_notification_title;
739                } else if (UsbManager.containsFunction(mCurrentFunctions,
740                        UsbManager.USB_FUNCTION_MTP)) {
741                    id = com.android.internal.R.string.usb_mtp_notification_title;
742                } else if (UsbManager.containsFunction(mCurrentFunctions,
743                        UsbManager.USB_FUNCTION_PTP)) {
744                    id = com.android.internal.R.string.usb_ptp_notification_title;
745                } else if (UsbManager.containsFunction(mCurrentFunctions,
746                        UsbManager.USB_FUNCTION_MIDI)) {
747                    id = com.android.internal.R.string.usb_midi_notification_title;
748                } else if (UsbManager.containsFunction(mCurrentFunctions,
749                        UsbManager.USB_FUNCTION_ACCESSORY)) {
750                    id = com.android.internal.R.string.usb_accessory_notification_title;
751                } else {
752                    id = com.android.internal.R.string.usb_charging_notification_title;
753                }
754            }
755            if (id != mUsbNotificationId) {
756                // clear notification if title needs changing
757                if (mUsbNotificationId != 0) {
758                    mNotificationManager.cancelAsUser(null, mUsbNotificationId,
759                            UserHandle.ALL);
760                    mUsbNotificationId = 0;
761                }
762                if (id != 0) {
763                    CharSequence message = r.getText(
764                            com.android.internal.R.string.usb_notification_message);
765                    CharSequence title = r.getText(id);
766
767                    Intent intent = Intent.makeRestartActivityTask(
768                            new ComponentName("com.android.settings",
769                                    "com.android.settings.deviceinfo.UsbModeChooserActivity"));
770                    PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
771                            intent, 0, null, UserHandle.CURRENT);
772
773                    Notification notification = new Notification.Builder(mContext)
774                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
775                            .setWhen(0)
776                            .setOngoing(true)
777                            .setTicker(title)
778                            .setDefaults(0)  // please be quiet
779                            .setPriority(Notification.PRIORITY_MIN)
780                            .setColor(mContext.getColor(
781                                    com.android.internal.R.color.system_notification_accent_color))
782                            .setContentTitle(title)
783                            .setContentText(message)
784                            .setContentIntent(pi)
785                            .setVisibility(Notification.VISIBILITY_PUBLIC)
786                            .build();
787                    mNotificationManager.notifyAsUser(null, id, notification,
788                            UserHandle.ALL);
789                    mUsbNotificationId = id;
790                }
791            }
792        }
793
794        private void updateAdbNotification() {
795            if (mNotificationManager == null) return;
796            final int id = com.android.internal.R.string.adb_active_notification_title;
797            if (mAdbEnabled && mConnected) {
798                if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
799
800                if (!mAdbNotificationShown) {
801                    Resources r = mContext.getResources();
802                    CharSequence title = r.getText(id);
803                    CharSequence message = r.getText(
804                            com.android.internal.R.string.adb_active_notification_message);
805
806                    Intent intent = Intent.makeRestartActivityTask(
807                            new ComponentName("com.android.settings",
808                                    "com.android.settings.DevelopmentSettings"));
809                    PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
810                            intent, 0, null, UserHandle.CURRENT);
811
812                    Notification notification = new Notification.Builder(mContext)
813                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
814                            .setWhen(0)
815                            .setOngoing(true)
816                            .setTicker(title)
817                            .setDefaults(0)  // please be quiet
818                            .setPriority(Notification.PRIORITY_LOW)
819                            .setColor(mContext.getColor(
820                                    com.android.internal.R.color.system_notification_accent_color))
821                            .setContentTitle(title)
822                            .setContentText(message)
823                            .setContentIntent(pi)
824                            .setVisibility(Notification.VISIBILITY_PUBLIC)
825                            .build();
826                    mAdbNotificationShown = true;
827                    mNotificationManager.notifyAsUser(null, id, notification,
828                            UserHandle.ALL);
829                }
830            } else if (mAdbNotificationShown) {
831                mAdbNotificationShown = false;
832                mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
833            }
834        }
835
836        private String getDefaultFunctions() {
837            String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY,
838                    UsbManager.USB_FUNCTION_NONE);
839            if (UsbManager.USB_FUNCTION_NONE.equals(func)) {
840                func = UsbManager.USB_FUNCTION_MTP;
841            }
842            return func;
843        }
844
845        public void dump(IndentingPrintWriter pw) {
846            pw.println("USB Device State:");
847            pw.println("  mCurrentFunctions: " + mCurrentFunctions);
848            pw.println("  mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
849            pw.println("  mConnected: " + mConnected);
850            pw.println("  mConfigured: " + mConfigured);
851            pw.println("  mUsbDataUnlocked: " + mUsbDataUnlocked);
852            pw.println("  mCurrentAccessory: " + mCurrentAccessory);
853            try {
854                pw.println("  Kernel state: "
855                        + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
856                pw.println("  Kernel function list: "
857                        + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
858            } catch (IOException e) {
859                pw.println("IOException: " + e);
860            }
861        }
862    }
863
864    /* returns the currently attached USB accessory */
865    public UsbAccessory getCurrentAccessory() {
866        return mHandler.getCurrentAccessory();
867    }
868
869    /* opens the currently attached USB accessory */
870    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
871        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
872        if (currentAccessory == null) {
873            throw new IllegalArgumentException("no accessory attached");
874        }
875        if (!currentAccessory.equals(accessory)) {
876            String error = accessory.toString()
877                    + " does not match current accessory "
878                    + currentAccessory;
879            throw new IllegalArgumentException(error);
880        }
881        getCurrentSettings().checkPermission(accessory);
882        return nativeOpenAccessory();
883    }
884
885    public boolean isFunctionEnabled(String function) {
886        return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
887    }
888
889    public void setCurrentFunctions(String functions) {
890        if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
891        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
892    }
893
894    public void setUsbDataUnlocked(boolean unlocked) {
895        if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")");
896        mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked);
897    }
898
899    private void readOemUsbOverrideConfig() {
900        String[] configList = mContext.getResources().getStringArray(
901            com.android.internal.R.array.config_oemUsbModeOverride);
902
903        if (configList != null) {
904            for (String config: configList) {
905                String[] items = config.split(":");
906                if (items.length == 3) {
907                    if (mOemModeMap == null) {
908                        mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
909                    }
910                    List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
911                    if (overrideList == null) {
912                        overrideList = new LinkedList<Pair<String, String>>();
913                        mOemModeMap.put(items[0], overrideList);
914                    }
915                    overrideList.add(new Pair<String, String>(items[1], items[2]));
916                }
917            }
918        }
919    }
920
921    private String applyOemOverrideFunction(String usbFunctions) {
922        if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
923
924        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
925
926        List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
927        if (overrides != null) {
928            for (Pair<String, String> pair: overrides) {
929                if (pair.first.equals(usbFunctions)) {
930                    Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
931                    return pair.second;
932                }
933            }
934        }
935        // return passed in functions as is.
936        return usbFunctions;
937    }
938
939    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
940        if (mDebuggingManager != null) {
941            mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
942        }
943    }
944
945    public void denyUsbDebugging() {
946        if (mDebuggingManager != null) {
947            mDebuggingManager.denyUsbDebugging();
948        }
949    }
950
951    public void clearUsbDebuggingKeys() {
952        if (mDebuggingManager != null) {
953            mDebuggingManager.clearUsbDebuggingKeys();
954        } else {
955            throw new RuntimeException("Cannot clear Usb Debugging keys, "
956                        + "UsbDebuggingManager not enabled");
957        }
958    }
959
960    public void dump(IndentingPrintWriter pw) {
961        if (mHandler != null) {
962            mHandler.dump(pw);
963        }
964        if (mDebuggingManager != null) {
965            mDebuggingManager.dump(pw);
966        }
967    }
968
969    private native String[] nativeGetAccessoryStrings();
970    private native ParcelFileDescriptor nativeOpenAccessory();
971    private native boolean nativeIsStartRequested();
972    private native int nativeGetAudioMode();
973}
974