UsbDeviceManager.java revision 823e805c1c72b34bed8439e269f96b2f3a5cbe4e
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            // we always set it due to b/23631400, where adbd was getting killed
420            // and not restarted due to property timeouts on some devices
421            SystemProperties.set(USB_CONFIG_PROPERTY, config);
422            return waitForState(config);
423        }
424
425        private void setUsbDataUnlocked(boolean enable) {
426            if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable);
427            mUsbDataUnlocked = enable;
428            updateUsbNotification();
429            updateUsbStateBroadcast();
430            setEnabledFunctions(mCurrentFunctions, true);
431        }
432
433        private void setAdbEnabled(boolean enable) {
434            if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
435            if (enable != mAdbEnabled) {
436                mAdbEnabled = enable;
437
438                // Due to the persist.sys.usb.config property trigger, changing adb state requires
439                // persisting default function
440                String oldFunctions = getDefaultFunctions();
441                String newFunctions = applyAdbFunction(oldFunctions);
442                if (!oldFunctions.equals(newFunctions)) {
443                    SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions);
444                }
445
446                // After persisting them use the lock-down aware function set
447                setEnabledFunctions(mCurrentFunctions, false);
448                updateAdbNotification();
449            }
450
451            if (mDebuggingManager != null) {
452                mDebuggingManager.setAdbEnabled(mAdbEnabled);
453            }
454        }
455
456        /**
457         * Evaluates USB function policies and applies the change accordingly.
458         */
459        private void setEnabledFunctions(String functions, boolean forceRestart) {
460            if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
461                    + "forceRestart=" + forceRestart);
462
463            // Try to set the enabled functions.
464            final String oldFunctions = mCurrentFunctions;
465            final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
466            if (trySetEnabledFunctions(functions, forceRestart)) {
467                return;
468            }
469
470            // Didn't work.  Try to revert changes.
471            // We always reapply the policy in case certain constraints changed such as
472            // user restrictions independently of any other new functions we were
473            // trying to activate.
474            if (oldFunctionsApplied && !oldFunctions.equals(functions)) {
475                Slog.e(TAG, "Failsafe 1: Restoring previous USB functions.");
476                if (trySetEnabledFunctions(oldFunctions, false)) {
477                    return;
478                }
479            }
480
481            // Still didn't work.  Try to restore the default functions.
482            Slog.e(TAG, "Failsafe 2: Restoring default USB functions.");
483            if (trySetEnabledFunctions(null, false)) {
484                return;
485            }
486
487            // Now we're desperate.  Ignore the default functions.
488            // Try to get ADB working if enabled.
489            Slog.e(TAG, "Failsafe 3: Restoring empty function list (with ADB if enabled).");
490            if (trySetEnabledFunctions(UsbManager.USB_FUNCTION_NONE, false)) {
491                return;
492            }
493
494            // Ouch.
495            Slog.e(TAG, "Unable to set any USB functions!");
496        }
497
498        private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
499            if (functions == null) {
500                functions = getDefaultFunctions();
501            }
502            functions = applyAdbFunction(functions);
503            functions = applyOemOverrideFunction(functions);
504
505            if (!mCurrentFunctions.equals(functions) || !mCurrentFunctionsApplied
506                    || forceRestart) {
507                Slog.i(TAG, "Setting USB config to " + functions);
508                mCurrentFunctions = functions;
509                mCurrentFunctionsApplied = false;
510
511                // Kick the USB stack to close existing connections.
512                setUsbConfig(UsbManager.USB_FUNCTION_NONE);
513
514                // Set the new USB configuration.
515                if (!setUsbConfig(functions)) {
516                    Slog.e(TAG, "Failed to switch USB config to " + functions);
517                    return false;
518                }
519
520                mCurrentFunctionsApplied = true;
521            }
522            return true;
523        }
524
525        private String applyAdbFunction(String functions) {
526            if (mAdbEnabled) {
527                functions = UsbManager.addFunction(functions, UsbManager.USB_FUNCTION_ADB);
528            } else {
529                functions = UsbManager.removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
530            }
531            return functions;
532        }
533
534        private boolean isUsbTransferAllowed() {
535            UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
536            return !userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
537        }
538
539        private void updateCurrentAccessory() {
540            // We are entering accessory mode if we have received a request from the host
541            // and the request has not timed out yet.
542            boolean enteringAccessoryMode =
543                    mAccessoryModeRequestTime > 0 &&
544                        SystemClock.elapsedRealtime() <
545                            mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
546
547            if (mConfigured && enteringAccessoryMode) {
548                // successfully entered accessory mode
549
550                if (mAccessoryStrings != null) {
551                    mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
552                    Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
553                    // defer accessoryAttached if system is not ready
554                    if (mBootCompleted) {
555                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
556                    } // else handle in boot completed
557                } else {
558                    Slog.e(TAG, "nativeGetAccessoryStrings failed");
559                }
560            } else if (!enteringAccessoryMode) {
561                // make sure accessory mode is off
562                // and restore default functions
563                Slog.d(TAG, "exited USB accessory mode");
564                setEnabledFunctions(null, false);
565
566                if (mCurrentAccessory != null) {
567                    if (mBootCompleted) {
568                        getCurrentSettings().accessoryDetached(mCurrentAccessory);
569                    }
570                    mCurrentAccessory = null;
571                    mAccessoryStrings = null;
572                }
573            }
574        }
575
576        private void updateUsbStateBroadcast() {
577            // send a sticky broadcast containing current USB state
578            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
579            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
580                    | Intent.FLAG_RECEIVER_FOREGROUND);
581            intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
582            intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
583            intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked);
584
585            if (mCurrentFunctions != null) {
586                String[] functions = mCurrentFunctions.split(",");
587                for (int i = 0; i < functions.length; i++) {
588                    intent.putExtra(functions[i], true);
589                }
590            }
591
592            if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " connected: " + mConnected
593                                    + " configured: " + mConfigured);
594            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
595        }
596
597        private void updateUsbFunctions() {
598            updateAudioSourceFunction();
599            updateMidiFunction();
600        }
601
602        private void updateAudioSourceFunction() {
603            boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
604                    UsbManager.USB_FUNCTION_AUDIO_SOURCE);
605            if (enabled != mAudioSourceEnabled) {
606                int card = -1;
607                int device = -1;
608
609                if (enabled) {
610                    Scanner scanner = null;
611                    try {
612                        scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
613                        card = scanner.nextInt();
614                        device = scanner.nextInt();
615                    } catch (FileNotFoundException e) {
616                        Slog.e(TAG, "could not open audio source PCM file", e);
617                    } finally {
618                        if (scanner != null) {
619                            scanner.close();
620                        }
621                    }
622                }
623                mUsbAlsaManager.setAccessoryAudioState(enabled, card, device);
624                mAudioSourceEnabled = enabled;
625            }
626        }
627
628        private void updateMidiFunction() {
629            boolean enabled = UsbManager.containsFunction(mCurrentFunctions,
630                    UsbManager.USB_FUNCTION_MIDI);
631            if (enabled != mMidiEnabled) {
632                if (enabled) {
633                    Scanner scanner = null;
634                    try {
635                        scanner = new Scanner(new File(MIDI_ALSA_PATH));
636                        mMidiCard = scanner.nextInt();
637                        mMidiDevice = scanner.nextInt();
638                    } catch (FileNotFoundException e) {
639                        Slog.e(TAG, "could not open MIDI PCM file", e);
640                        enabled = false;
641                    } finally {
642                        if (scanner != null) {
643                            scanner.close();
644                        }
645                    }
646                }
647                mMidiEnabled = enabled;
648            }
649            mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
650        }
651
652        @Override
653        public void handleMessage(Message msg) {
654            switch (msg.what) {
655                case MSG_UPDATE_STATE:
656                    mConnected = (msg.arg1 == 1);
657                    mConfigured = (msg.arg2 == 1);
658                    if (!mConnected) {
659                        // When a disconnect occurs, relock access to sensitive user data
660                        mUsbDataUnlocked = false;
661                    }
662                    updateUsbNotification();
663                    updateAdbNotification();
664                    if (UsbManager.containsFunction(mCurrentFunctions,
665                            UsbManager.USB_FUNCTION_ACCESSORY)) {
666                        updateCurrentAccessory();
667                    } else if (!mConnected) {
668                        // restore defaults when USB is disconnected
669                        setEnabledFunctions(null, false);
670                    }
671                    if (mBootCompleted) {
672                        updateUsbStateBroadcast();
673                        updateUsbFunctions();
674                    }
675                    break;
676                case MSG_UPDATE_HOST_STATE:
677                    mHostConnected = (msg.arg1 == 1);
678                    updateUsbNotification();
679                    break;
680                case MSG_ENABLE_ADB:
681                    setAdbEnabled(msg.arg1 == 1);
682                    break;
683                case MSG_SET_CURRENT_FUNCTIONS:
684                    String functions = (String)msg.obj;
685                    setEnabledFunctions(functions, false);
686                    break;
687                case MSG_UPDATE_USER_RESTRICTIONS:
688                    setEnabledFunctions(mCurrentFunctions, false);
689                    break;
690                case MSG_SET_USB_DATA_UNLOCKED:
691                    setUsbDataUnlocked(msg.arg1 == 1);
692                    break;
693                case MSG_SYSTEM_READY:
694                    updateUsbNotification();
695                    updateAdbNotification();
696                    updateUsbStateBroadcast();
697                    updateUsbFunctions();
698                    break;
699                case MSG_BOOT_COMPLETED:
700                    mBootCompleted = true;
701                    if (mCurrentAccessory != null) {
702                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
703                    }
704                    if (mDebuggingManager != null) {
705                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
706                    }
707                    break;
708                case MSG_USER_SWITCHED: {
709                    if (mCurrentUser != msg.arg1) {
710                        // Restart the USB stack and re-apply user restrictions for MTP or PTP.
711                        final boolean active = UsbManager.containsFunction(mCurrentFunctions,
712                                        UsbManager.USB_FUNCTION_MTP)
713                                || UsbManager.containsFunction(mCurrentFunctions,
714                                        UsbManager.USB_FUNCTION_PTP);
715                        if (active && mCurrentUser != UserHandle.USER_NULL) {
716                            Slog.v(TAG, "Current user switched to " + mCurrentUser
717                                    + "; resetting USB host stack for MTP or PTP");
718                            setEnabledFunctions(mCurrentFunctions, true);
719                        }
720                        mCurrentUser = msg.arg1;
721                    }
722                    break;
723                }
724            }
725        }
726
727        public UsbAccessory getCurrentAccessory() {
728            return mCurrentAccessory;
729        }
730
731        private void updateUsbNotification() {
732            if (mNotificationManager == null || !mUseUsbNotification) return;
733            int id = 0;
734            Resources r = mContext.getResources();
735            if (mConnected || mHostConnected) {
736                if (!mUsbDataUnlocked) {
737                    id = com.android.internal.R.string.usb_charging_notification_title;
738                } else if (UsbManager.containsFunction(mCurrentFunctions,
739                        UsbManager.USB_FUNCTION_MTP)) {
740                    id = com.android.internal.R.string.usb_mtp_notification_title;
741                } else if (UsbManager.containsFunction(mCurrentFunctions,
742                        UsbManager.USB_FUNCTION_PTP)) {
743                    id = com.android.internal.R.string.usb_ptp_notification_title;
744                } else if (UsbManager.containsFunction(mCurrentFunctions,
745                        UsbManager.USB_FUNCTION_MIDI)) {
746                    id = com.android.internal.R.string.usb_midi_notification_title;
747                } else if (UsbManager.containsFunction(mCurrentFunctions,
748                        UsbManager.USB_FUNCTION_ACCESSORY)) {
749                    id = com.android.internal.R.string.usb_accessory_notification_title;
750                } else {
751                    id = com.android.internal.R.string.usb_charging_notification_title;
752                }
753            }
754            if (id != mUsbNotificationId) {
755                // clear notification if title needs changing
756                if (mUsbNotificationId != 0) {
757                    mNotificationManager.cancelAsUser(null, mUsbNotificationId,
758                            UserHandle.ALL);
759                    mUsbNotificationId = 0;
760                }
761                if (id != 0) {
762                    CharSequence message = r.getText(
763                            com.android.internal.R.string.usb_notification_message);
764                    CharSequence title = r.getText(id);
765
766                    Intent intent = Intent.makeRestartActivityTask(
767                            new ComponentName("com.android.settings",
768                                    "com.android.settings.deviceinfo.UsbModeChooserActivity"));
769                    PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
770                            intent, 0, null, UserHandle.CURRENT);
771
772                    Notification notification = new Notification.Builder(mContext)
773                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
774                            .setWhen(0)
775                            .setOngoing(true)
776                            .setTicker(title)
777                            .setDefaults(0)  // please be quiet
778                            .setPriority(Notification.PRIORITY_MIN)
779                            .setColor(mContext.getColor(
780                                    com.android.internal.R.color.system_notification_accent_color))
781                            .setContentTitle(title)
782                            .setContentText(message)
783                            .setContentIntent(pi)
784                            .setVisibility(Notification.VISIBILITY_PUBLIC)
785                            .build();
786                    mNotificationManager.notifyAsUser(null, id, notification,
787                            UserHandle.ALL);
788                    mUsbNotificationId = id;
789                }
790            }
791        }
792
793        private void updateAdbNotification() {
794            if (mNotificationManager == null) return;
795            final int id = com.android.internal.R.string.adb_active_notification_title;
796            if (mAdbEnabled && mConnected) {
797                if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
798
799                if (!mAdbNotificationShown) {
800                    Resources r = mContext.getResources();
801                    CharSequence title = r.getText(id);
802                    CharSequence message = r.getText(
803                            com.android.internal.R.string.adb_active_notification_message);
804
805                    Intent intent = Intent.makeRestartActivityTask(
806                            new ComponentName("com.android.settings",
807                                    "com.android.settings.DevelopmentSettings"));
808                    PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
809                            intent, 0, null, UserHandle.CURRENT);
810
811                    Notification notification = new Notification.Builder(mContext)
812                            .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
813                            .setWhen(0)
814                            .setOngoing(true)
815                            .setTicker(title)
816                            .setDefaults(0)  // please be quiet
817                            .setPriority(Notification.PRIORITY_LOW)
818                            .setColor(mContext.getColor(
819                                    com.android.internal.R.color.system_notification_accent_color))
820                            .setContentTitle(title)
821                            .setContentText(message)
822                            .setContentIntent(pi)
823                            .setVisibility(Notification.VISIBILITY_PUBLIC)
824                            .build();
825                    mAdbNotificationShown = true;
826                    mNotificationManager.notifyAsUser(null, id, notification,
827                            UserHandle.ALL);
828                }
829            } else if (mAdbNotificationShown) {
830                mAdbNotificationShown = false;
831                mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
832            }
833        }
834
835        private String getDefaultFunctions() {
836            String func = SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY,
837                    UsbManager.USB_FUNCTION_NONE);
838            if (UsbManager.USB_FUNCTION_NONE.equals(func)) {
839                func = UsbManager.USB_FUNCTION_MTP;
840            }
841            return func;
842        }
843
844        public void dump(IndentingPrintWriter pw) {
845            pw.println("USB Device State:");
846            pw.println("  mCurrentFunctions: " + mCurrentFunctions);
847            pw.println("  mCurrentFunctionsApplied: " + mCurrentFunctionsApplied);
848            pw.println("  mConnected: " + mConnected);
849            pw.println("  mConfigured: " + mConfigured);
850            pw.println("  mUsbDataUnlocked: " + mUsbDataUnlocked);
851            pw.println("  mCurrentAccessory: " + mCurrentAccessory);
852            try {
853                pw.println("  Kernel state: "
854                        + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
855                pw.println("  Kernel function list: "
856                        + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
857            } catch (IOException e) {
858                pw.println("IOException: " + e);
859            }
860        }
861    }
862
863    /* returns the currently attached USB accessory */
864    public UsbAccessory getCurrentAccessory() {
865        return mHandler.getCurrentAccessory();
866    }
867
868    /* opens the currently attached USB accessory */
869    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
870        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
871        if (currentAccessory == null) {
872            throw new IllegalArgumentException("no accessory attached");
873        }
874        if (!currentAccessory.equals(accessory)) {
875            String error = accessory.toString()
876                    + " does not match current accessory "
877                    + currentAccessory;
878            throw new IllegalArgumentException(error);
879        }
880        getCurrentSettings().checkPermission(accessory);
881        return nativeOpenAccessory();
882    }
883
884    public boolean isFunctionEnabled(String function) {
885        return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
886    }
887
888    public void setCurrentFunctions(String functions) {
889        if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
890        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
891    }
892
893    public void setUsbDataUnlocked(boolean unlocked) {
894        if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")");
895        mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked);
896    }
897
898    private void readOemUsbOverrideConfig() {
899        String[] configList = mContext.getResources().getStringArray(
900            com.android.internal.R.array.config_oemUsbModeOverride);
901
902        if (configList != null) {
903            for (String config: configList) {
904                String[] items = config.split(":");
905                if (items.length == 3) {
906                    if (mOemModeMap == null) {
907                        mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
908                    }
909                    List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
910                    if (overrideList == null) {
911                        overrideList = new LinkedList<Pair<String, String>>();
912                        mOemModeMap.put(items[0], overrideList);
913                    }
914                    overrideList.add(new Pair<String, String>(items[1], items[2]));
915                }
916            }
917        }
918    }
919
920    private String applyOemOverrideFunction(String usbFunctions) {
921        if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
922
923        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
924
925        List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
926        if (overrides != null) {
927            for (Pair<String, String> pair: overrides) {
928                if (pair.first.equals(usbFunctions)) {
929                    Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
930                    return pair.second;
931                }
932            }
933        }
934        // return passed in functions as is.
935        return usbFunctions;
936    }
937
938    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
939        if (mDebuggingManager != null) {
940            mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
941        }
942    }
943
944    public void denyUsbDebugging() {
945        if (mDebuggingManager != null) {
946            mDebuggingManager.denyUsbDebugging();
947        }
948    }
949
950    public void clearUsbDebuggingKeys() {
951        if (mDebuggingManager != null) {
952            mDebuggingManager.clearUsbDebuggingKeys();
953        } else {
954            throw new RuntimeException("Cannot clear Usb Debugging keys, "
955                        + "UsbDebuggingManager not enabled");
956        }
957    }
958
959    public void dump(IndentingPrintWriter pw) {
960        if (mHandler != null) {
961            mHandler.dump(pw);
962        }
963        if (mDebuggingManager != null) {
964            mDebuggingManager.dump(pw);
965        }
966    }
967
968    private native String[] nativeGetAccessoryStrings();
969    private native ParcelFileDescriptor nativeOpenAccessory();
970    private native boolean nativeIsStartRequested();
971    private native int nativeGetAudioMode();
972}
973