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