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