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