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