UsbDeviceManager.java revision c84b4d7ff20c21aa3658c81c18546a74921be441
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.os.FileUtils;
34import android.os.Handler;
35import android.os.Looper;
36import android.os.Message;
37import android.os.ParcelFileDescriptor;
38import android.os.SystemClock;
39import android.os.SystemProperties;
40import android.os.UEventObserver;
41import android.os.UserHandle;
42import android.os.storage.StorageManager;
43import android.os.storage.StorageVolume;
44import android.provider.Settings;
45import android.util.Pair;
46import android.util.Slog;
47
48import com.android.internal.annotations.GuardedBy;
49import com.android.server.FgThread;
50
51import java.io.File;
52import java.io.FileDescriptor;
53import java.io.FileNotFoundException;
54import java.io.IOException;
55import java.io.PrintWriter;
56import java.util.Arrays;
57import java.util.HashMap;
58import java.util.LinkedList;
59import java.util.List;
60import java.util.Locale;
61import java.util.Map;
62import java.util.Scanner;
63
64/**
65 * UsbDeviceManager manages USB state in device mode.
66 */
67public class UsbDeviceManager {
68
69    private static final String TAG = UsbDeviceManager.class.getSimpleName();
70    private static final boolean DEBUG = false;
71
72    private static final String USB_STATE_MATCH =
73            "DEVPATH=/devices/virtual/android_usb/android0";
74    private static final String ACCESSORY_START_MATCH =
75            "DEVPATH=/devices/virtual/misc/usb_accessory";
76    private static final String FUNCTIONS_PATH =
77            "/sys/class/android_usb/android0/functions";
78    private static final String STATE_PATH =
79            "/sys/class/android_usb/android0/state";
80    private static final String MASS_STORAGE_FILE_PATH =
81            "/sys/class/android_usb/android0/f_mass_storage/lun/file";
82    private static final String RNDIS_ETH_ADDR_PATH =
83            "/sys/class/android_usb/android0/f_rndis/ethaddr";
84    private static final String AUDIO_SOURCE_PCM_PATH =
85            "/sys/class/android_usb/android0/f_audio_source/pcm";
86
87    private static final int MSG_UPDATE_STATE = 0;
88    private static final int MSG_ENABLE_ADB = 1;
89    private static final int MSG_SET_CURRENT_FUNCTIONS = 2;
90    private static final int MSG_SYSTEM_READY = 3;
91    private static final int MSG_BOOT_COMPLETED = 4;
92    private static final int MSG_USER_SWITCHED = 5;
93
94    private static final int AUDIO_MODE_NONE = 0;
95    private static final int AUDIO_MODE_SOURCE = 1;
96
97    // Delay for debouncing USB disconnects.
98    // We often get rapid connect/disconnect events when enabling USB functions,
99    // which need debouncing.
100    private static final int UPDATE_DELAY = 1000;
101
102    // Time we received a request to enter USB accessory mode
103    private long mAccessoryModeRequestTime = 0;
104
105    // Timeout for entering USB request mode.
106    // Request is cancelled if host does not configure device within 10 seconds.
107    private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
108
109    private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
110
111    private UsbHandler mHandler;
112    private boolean mBootCompleted;
113
114    private final Object mLock = new Object();
115
116    private final Context mContext;
117    private final ContentResolver mContentResolver;
118    @GuardedBy("mLock")
119    private UsbSettingsManager mCurrentSettings;
120    private NotificationManager mNotificationManager;
121    private final boolean mHasUsbAccessory;
122    private boolean mUseUsbNotification;
123    private boolean mAdbEnabled;
124    private boolean mAudioSourceEnabled;
125    private Map<String, List<Pair<String, String>>> mOemModeMap;
126    private String[] mAccessoryStrings;
127    private UsbDebuggingManager mDebuggingManager;
128
129    private class AdbSettingsObserver extends ContentObserver {
130        public AdbSettingsObserver() {
131            super(null);
132        }
133        @Override
134        public void onChange(boolean selfChange) {
135            boolean enable = (Settings.Global.getInt(mContentResolver,
136                    Settings.Global.ADB_ENABLED, 0) > 0);
137            mHandler.sendMessage(MSG_ENABLE_ADB, enable);
138        }
139    }
140
141    /*
142     * Listens for uevent messages from the kernel to monitor the USB state
143     */
144    private final UEventObserver mUEventObserver = new UEventObserver() {
145        @Override
146        public void onUEvent(UEventObserver.UEvent event) {
147            if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
148
149            String state = event.get("USB_STATE");
150            String accessory = event.get("ACCESSORY");
151            if (state != null) {
152                mHandler.updateState(state);
153            } else if ("START".equals(accessory)) {
154                if (DEBUG) Slog.d(TAG, "got accessory start");
155                startAccessoryMode();
156            }
157        }
158    };
159
160    public UsbDeviceManager(Context context) {
161        mContext = context;
162        mContentResolver = context.getContentResolver();
163        PackageManager pm = mContext.getPackageManager();
164        mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
165        initRndisAddress();
166
167        readOemUsbOverrideConfig();
168
169        mHandler = new UsbHandler(FgThread.get().getLooper());
170
171        if (nativeIsStartRequested()) {
172            if (DEBUG) Slog.d(TAG, "accessory attached at boot");
173            startAccessoryMode();
174        }
175
176        boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
177        boolean dataEncrypted = "1".equals(SystemProperties.get("vold.decrypt"));
178        if (secureAdbEnabled && !dataEncrypted) {
179            mDebuggingManager = new UsbDebuggingManager(context);
180        }
181    }
182
183    public void setCurrentSettings(UsbSettingsManager settings) {
184        synchronized (mLock) {
185            mCurrentSettings = settings;
186        }
187    }
188
189    private UsbSettingsManager getCurrentSettings() {
190        synchronized (mLock) {
191            return mCurrentSettings;
192        }
193    }
194
195    public void systemReady() {
196        if (DEBUG) Slog.d(TAG, "systemReady");
197
198        mNotificationManager = (NotificationManager)
199                mContext.getSystemService(Context.NOTIFICATION_SERVICE);
200
201        // We do not show the USB notification if the primary volume supports mass storage.
202        // The legacy mass storage UI will be used instead.
203        boolean massStorageSupported = false;
204        final StorageManager storageManager = StorageManager.from(mContext);
205        final StorageVolume primary = storageManager.getPrimaryVolume();
206        massStorageSupported = primary != null && primary.allowMassStorage();
207        mUseUsbNotification = !massStorageSupported;
208
209        // make sure the ADB_ENABLED setting value matches the current state
210        Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, mAdbEnabled ? 1 : 0);
211
212        mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
213    }
214
215    private void startAccessoryMode() {
216        if (!mHasUsbAccessory) return;
217
218        mAccessoryStrings = nativeGetAccessoryStrings();
219        boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
220        // don't start accessory mode if our mandatory strings have not been set
221        boolean enableAccessory = (mAccessoryStrings != null &&
222                        mAccessoryStrings[UsbAccessory.MANUFACTURER_STRING] != null &&
223                        mAccessoryStrings[UsbAccessory.MODEL_STRING] != null);
224        String functions = null;
225
226        if (enableAccessory && enableAudio) {
227            functions = UsbManager.USB_FUNCTION_ACCESSORY + ","
228                    + UsbManager.USB_FUNCTION_AUDIO_SOURCE;
229        } else if (enableAccessory) {
230            functions = UsbManager.USB_FUNCTION_ACCESSORY;
231        } else if (enableAudio) {
232            functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
233        }
234
235        if (functions != null) {
236            mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
237            setCurrentFunctions(functions, false);
238        }
239    }
240
241    private static void initRndisAddress() {
242        // configure RNDIS ethernet address based on our serial number using the same algorithm
243        // we had been previously using in kernel board files
244        final int ETH_ALEN = 6;
245        int address[] = new int[ETH_ALEN];
246        // first byte is 0x02 to signify a locally administered address
247        address[0] = 0x02;
248
249        String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
250        int serialLength = serial.length();
251        // XOR the USB serial across the remaining 5 bytes
252        for (int i = 0; i < serialLength; i++) {
253            address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
254        }
255        String addrString = String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
256            address[0], address[1], address[2], address[3], address[4], address[5]);
257        try {
258            FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
259        } catch (IOException e) {
260           Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
261        }
262    }
263
264     private static String addFunction(String functions, String function) {
265         if ("none".equals(functions)) {
266             return function;
267         }
268        if (!containsFunction(functions, function)) {
269            if (functions.length() > 0) {
270                functions += ",";
271            }
272            functions += function;
273        }
274        return functions;
275    }
276
277    private static String removeFunction(String functions, String function) {
278        String[] split = functions.split(",");
279        for (int i = 0; i < split.length; i++) {
280            if (function.equals(split[i])) {
281                split[i] = null;
282            }
283        }
284        if (split.length == 1 && split[0] == null) {
285            return "none";
286        }
287        StringBuilder builder = new StringBuilder();
288         for (int i = 0; i < split.length; i++) {
289            String s = split[i];
290            if (s != null) {
291                if (builder.length() > 0) {
292                    builder.append(",");
293                }
294                builder.append(s);
295            }
296        }
297        return builder.toString();
298    }
299
300    private static boolean containsFunction(String functions, String function) {
301        return Arrays.asList(functions.split(",")).contains(function);
302    }
303
304    private final class UsbHandler extends Handler {
305
306        // current USB state
307        private boolean mConnected;
308        private boolean mConfigured;
309        private String mCurrentFunctions;
310        private String mDefaultFunctions;
311        private UsbAccessory mCurrentAccessory;
312        private int mUsbNotificationId;
313        private boolean mAdbNotificationShown;
314        private int mCurrentUser = UserHandle.USER_NULL;
315
316        private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
317            @Override
318            public void onReceive(Context context, Intent intent) {
319                if (DEBUG) Slog.d(TAG, "boot completed");
320                mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
321            }
322        };
323
324        private final BroadcastReceiver mUserSwitchedReceiver = new BroadcastReceiver() {
325            @Override
326            public void onReceive(Context context, Intent intent) {
327                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
328                mHandler.obtainMessage(MSG_USER_SWITCHED, userId, 0).sendToTarget();
329            }
330        };
331
332        public UsbHandler(Looper looper) {
333            super(looper);
334            try {
335                // persist.sys.usb.config should never be unset.  But if it is, set it to "adb"
336                // so we have a chance of debugging what happened.
337                mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
338
339                // Check if USB mode needs to be overridden depending on OEM specific bootmode.
340                mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
341
342                // sanity check the sys.usb.config system property
343                // this may be necessary if we crashed while switching USB configurations
344                String config = SystemProperties.get("sys.usb.config", "none");
345                if (!config.equals(mDefaultFunctions)) {
346                    Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
347                    SystemProperties.set("sys.usb.config", mDefaultFunctions);
348                }
349
350                mCurrentFunctions = mDefaultFunctions;
351                String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
352                updateState(state);
353                mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
354
355                // Upgrade step for previous versions that used persist.service.adb.enable
356                String value = SystemProperties.get("persist.service.adb.enable", "");
357                if (value.length() > 0) {
358                    char enable = value.charAt(0);
359                    if (enable == '1') {
360                        setAdbEnabled(true);
361                    } else if (enable == '0') {
362                        setAdbEnabled(false);
363                    }
364                    SystemProperties.set("persist.service.adb.enable", "");
365                }
366
367                // register observer to listen for settings changes
368                mContentResolver.registerContentObserver(
369                        Settings.Global.getUriFor(Settings.Global.ADB_ENABLED),
370                                false, new AdbSettingsObserver());
371
372                // Watch for USB configuration changes
373                mUEventObserver.startObserving(USB_STATE_MATCH);
374                mUEventObserver.startObserving(ACCESSORY_START_MATCH);
375
376                mContext.registerReceiver(
377                        mBootCompletedReceiver, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
378                mContext.registerReceiver(
379                        mUserSwitchedReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
380            } catch (Exception e) {
381                Slog.e(TAG, "Error initializing UsbHandler", e);
382            }
383        }
384
385        public void sendMessage(int what, boolean arg) {
386            removeMessages(what);
387            Message m = Message.obtain(this, what);
388            m.arg1 = (arg ? 1 : 0);
389            sendMessage(m);
390        }
391
392        public void sendMessage(int what, Object arg) {
393            removeMessages(what);
394            Message m = Message.obtain(this, what);
395            m.obj = arg;
396            sendMessage(m);
397        }
398
399        public void sendMessage(int what, Object arg0, boolean arg1) {
400            removeMessages(what);
401            Message m = Message.obtain(this, what);
402            m.obj = arg0;
403            m.arg1 = (arg1 ? 1 : 0);
404            sendMessage(m);
405        }
406
407        public void updateState(String state) {
408            int connected, configured;
409
410            if ("DISCONNECTED".equals(state)) {
411                connected = 0;
412                configured = 0;
413            } else if ("CONNECTED".equals(state)) {
414                connected = 1;
415                configured = 0;
416            } else if ("CONFIGURED".equals(state)) {
417                connected = 1;
418                configured = 1;
419            } else {
420                Slog.e(TAG, "unknown state " + state);
421                return;
422            }
423            removeMessages(MSG_UPDATE_STATE);
424            Message msg = Message.obtain(this, MSG_UPDATE_STATE);
425            msg.arg1 = connected;
426            msg.arg2 = configured;
427            // debounce disconnects to avoid problems bringing up USB tethering
428            sendMessageDelayed(msg, (connected == 0) ? UPDATE_DELAY : 0);
429        }
430
431        private boolean waitForState(String state) {
432            // wait for the transition to complete.
433            // give up after 1 second.
434            for (int i = 0; i < 20; i++) {
435                // State transition is done when sys.usb.state is set to the new configuration
436                if (state.equals(SystemProperties.get("sys.usb.state"))) return true;
437                SystemClock.sleep(50);
438            }
439            Slog.e(TAG, "waitForState(" + state + ") FAILED");
440            return false;
441        }
442
443        private boolean setUsbConfig(String config) {
444            if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
445            // set the new configuration
446            SystemProperties.set("sys.usb.config", config);
447            return waitForState(config);
448        }
449
450        private void setAdbEnabled(boolean enable) {
451            if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
452            if (enable != mAdbEnabled) {
453                mAdbEnabled = enable;
454                // Due to the persist.sys.usb.config property trigger, changing adb state requires
455                // switching to default function
456                setEnabledFunctions(mDefaultFunctions, true);
457                updateAdbNotification();
458            }
459            if (mDebuggingManager != null) {
460                mDebuggingManager.setAdbEnabled(mAdbEnabled);
461            }
462        }
463
464        private void setEnabledFunctions(String functions, boolean makeDefault) {
465            if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
466                    + " makeDefault: " + makeDefault);
467
468            // Do not update persystent.sys.usb.config if the device is booted up
469            // with OEM specific mode.
470            if (functions != null && makeDefault && !needsOemUsbOverride()) {
471
472                if (mAdbEnabled) {
473                    functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
474                } else {
475                    functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
476                }
477                if (!mDefaultFunctions.equals(functions)) {
478                    if (!setUsbConfig("none")) {
479                        Slog.e(TAG, "Failed to disable USB");
480                        // revert to previous configuration if we fail
481                        setUsbConfig(mCurrentFunctions);
482                        return;
483                    }
484                    // setting this property will also change the current USB state
485                    // via a property trigger
486                    SystemProperties.set("persist.sys.usb.config", functions);
487                    if (waitForState(functions)) {
488                        mCurrentFunctions = functions;
489                        mDefaultFunctions = functions;
490                    } else {
491                        Slog.e(TAG, "Failed to switch persistent USB config to " + functions);
492                        // revert to previous configuration if we fail
493                        SystemProperties.set("persist.sys.usb.config", mDefaultFunctions);
494                    }
495                }
496            } else {
497                if (functions == null) {
498                    functions = mDefaultFunctions;
499                }
500
501                // Override with bootmode specific usb mode if needed
502                functions = processOemUsbOverride(functions);
503
504                if (mAdbEnabled) {
505                    functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
506                } else {
507                    functions = removeFunction(functions, UsbManager.USB_FUNCTION_ADB);
508                }
509                if (!mCurrentFunctions.equals(functions)) {
510                    if (!setUsbConfig("none")) {
511                        Slog.e(TAG, "Failed to disable USB");
512                        // revert to previous configuration if we fail
513                        setUsbConfig(mCurrentFunctions);
514                        return;
515                    }
516                    if (setUsbConfig(functions)) {
517                        mCurrentFunctions = functions;
518                    } else {
519                        Slog.e(TAG, "Failed to switch USB config to " + functions);
520                        // revert to previous configuration if we fail
521                        setUsbConfig(mCurrentFunctions);
522                    }
523                }
524            }
525        }
526
527        private void updateCurrentAccessory() {
528            // We are entering accessory mode if we have received a request from the host
529            // and the request has not timed out yet.
530            boolean enteringAccessoryMode =
531                    mAccessoryModeRequestTime > 0 &&
532                        SystemClock.elapsedRealtime() <
533                            mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
534
535            if (mConfigured && enteringAccessoryMode) {
536                // successfully entered accessory mode
537                mAccessoryModeRequestTime = 0;
538
539                if (mAccessoryStrings != null) {
540                    mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
541                    Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
542                    // defer accessoryAttached if system is not ready
543                    if (mBootCompleted) {
544                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
545                    } // else handle in mBootCompletedReceiver
546                } else {
547                    Slog.e(TAG, "nativeGetAccessoryStrings failed");
548                }
549            } else if (!enteringAccessoryMode) {
550                // make sure accessory mode is off
551                // and restore default functions
552                Slog.d(TAG, "exited USB accessory mode");
553                setEnabledFunctions(mDefaultFunctions, false);
554
555                if (mCurrentAccessory != null) {
556                    if (mBootCompleted) {
557                        getCurrentSettings().accessoryDetached(mCurrentAccessory);
558                    }
559                    mCurrentAccessory = null;
560                    mAccessoryStrings = null;
561                }
562            }
563        }
564
565        private void updateUsbState() {
566            // send a sticky broadcast containing current USB state
567            Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
568            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
569            intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
570            intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
571
572            if (mCurrentFunctions != null) {
573                String[] functions = mCurrentFunctions.split(",");
574                for (int i = 0; i < functions.length; i++) {
575                    intent.putExtra(functions[i], true);
576                }
577            }
578
579            if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " connected: " + mConnected
580                                    + " configured: " + mConfigured);
581            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
582        }
583
584        private void updateAudioSourceFunction() {
585            boolean enabled = containsFunction(mCurrentFunctions,
586                    UsbManager.USB_FUNCTION_AUDIO_SOURCE);
587            if (enabled != mAudioSourceEnabled) {
588                // send a sticky broadcast containing current USB state
589                Intent intent = new Intent(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
590                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
591                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
592                intent.putExtra("state", (enabled ? 1 : 0));
593                if (enabled) {
594                    try {
595                        Scanner scanner = new Scanner(new File(AUDIO_SOURCE_PCM_PATH));
596                        int card = scanner.nextInt();
597                        int device = scanner.nextInt();
598                        intent.putExtra("card", card);
599                        intent.putExtra("device", device);
600                    } catch (FileNotFoundException e) {
601                        Slog.e(TAG, "could not open audio source PCM file", e);
602                    }
603                }
604                mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
605                mAudioSourceEnabled = enabled;
606            }
607        }
608
609        @Override
610        public void handleMessage(Message msg) {
611            switch (msg.what) {
612                case MSG_UPDATE_STATE:
613                    mConnected = (msg.arg1 == 1);
614                    mConfigured = (msg.arg2 == 1);
615                    updateUsbNotification();
616                    updateAdbNotification();
617                    if (containsFunction(mCurrentFunctions,
618                            UsbManager.USB_FUNCTION_ACCESSORY)) {
619                        updateCurrentAccessory();
620                    } else if (!mConnected) {
621                        // restore defaults when USB is disconnected
622                        setEnabledFunctions(mDefaultFunctions, false);
623                    }
624                    if (mBootCompleted) {
625                        updateUsbState();
626                        updateAudioSourceFunction();
627                    }
628                    break;
629                case MSG_ENABLE_ADB:
630                    setAdbEnabled(msg.arg1 == 1);
631                    break;
632                case MSG_SET_CURRENT_FUNCTIONS:
633                    String functions = (String)msg.obj;
634                    boolean makeDefault = (msg.arg1 == 1);
635                    setEnabledFunctions(functions, makeDefault);
636                    break;
637                case MSG_SYSTEM_READY:
638                    updateUsbNotification();
639                    updateAdbNotification();
640                    updateUsbState();
641                    updateAudioSourceFunction();
642                    break;
643                case MSG_BOOT_COMPLETED:
644                    mBootCompleted = true;
645                    if (mCurrentAccessory != null) {
646                        getCurrentSettings().accessoryAttached(mCurrentAccessory);
647                    }
648                    if (mDebuggingManager != null) {
649                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
650                    }
651                    break;
652                case MSG_USER_SWITCHED: {
653                    final boolean mtpActive =
654                            containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
655                            || containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
656                    if (mtpActive && mCurrentUser != UserHandle.USER_NULL) {
657                        Slog.v(TAG, "Current user switched; resetting USB host stack for MTP");
658                        setUsbConfig("none");
659                        setUsbConfig(mCurrentFunctions);
660                    }
661                    mCurrentUser = msg.arg1;
662                    break;
663                }
664            }
665        }
666
667        public UsbAccessory getCurrentAccessory() {
668            return mCurrentAccessory;
669        }
670
671        private void updateUsbNotification() {
672            if (mNotificationManager == null || !mUseUsbNotification) return;
673            int id = 0;
674            Resources r = mContext.getResources();
675            if (mConnected) {
676                if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
677                    id = com.android.internal.R.string.usb_mtp_notification_title;
678                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
679                    id = com.android.internal.R.string.usb_ptp_notification_title;
680                } else if (containsFunction(mCurrentFunctions,
681                        UsbManager.USB_FUNCTION_MASS_STORAGE)) {
682                    id = com.android.internal.R.string.usb_cd_installer_notification_title;
683                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) {
684                    id = com.android.internal.R.string.usb_accessory_notification_title;
685                } else {
686                    // There is a different notification for USB tethering so we don't need one here
687                    //if (!containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_RNDIS)) {
688                    //    Slog.e(TAG, "No known USB function in updateUsbNotification");
689                    //}
690                }
691            }
692            if (id != mUsbNotificationId) {
693                // clear notification if title needs changing
694                if (mUsbNotificationId != 0) {
695                    mNotificationManager.cancelAsUser(null, mUsbNotificationId,
696                            UserHandle.ALL);
697                    mUsbNotificationId = 0;
698                }
699                if (id != 0) {
700                    CharSequence message = r.getText(
701                            com.android.internal.R.string.usb_notification_message);
702                    CharSequence title = r.getText(id);
703
704                    Notification notification = new Notification();
705                    notification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
706                    notification.when = 0;
707                    notification.flags = Notification.FLAG_ONGOING_EVENT;
708                    notification.tickerText = title;
709                    notification.defaults = 0; // please be quiet
710                    notification.sound = null;
711                    notification.vibrate = null;
712                    notification.priority = Notification.PRIORITY_MIN;
713
714                    Intent intent = Intent.makeRestartActivityTask(
715                            new ComponentName("com.android.settings",
716                                    "com.android.settings.UsbSettings"));
717                    PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
718                            intent, 0, null, UserHandle.CURRENT);
719                    notification.setLatestEventInfo(mContext, title, message, pi);
720                    notification.visibility = Notification.VISIBILITY_PUBLIC;
721                    mNotificationManager.notifyAsUser(null, id, notification,
722                            UserHandle.ALL);
723                    mUsbNotificationId = id;
724                }
725            }
726        }
727
728        private void updateAdbNotification() {
729            if (mNotificationManager == null) return;
730            final int id = com.android.internal.R.string.adb_active_notification_title;
731            if (mAdbEnabled && mConnected) {
732                if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
733
734                if (!mAdbNotificationShown) {
735                    Resources r = mContext.getResources();
736                    CharSequence title = r.getText(id);
737                    CharSequence message = r.getText(
738                            com.android.internal.R.string.adb_active_notification_message);
739
740                    Notification notification = new Notification();
741                    notification.icon = com.android.internal.R.drawable.stat_sys_adb;
742                    notification.when = 0;
743                    notification.flags = Notification.FLAG_ONGOING_EVENT;
744                    notification.tickerText = title;
745                    notification.defaults = 0; // please be quiet
746                    notification.sound = null;
747                    notification.vibrate = null;
748                    notification.priority = Notification.PRIORITY_LOW;
749
750                    Intent intent = Intent.makeRestartActivityTask(
751                            new ComponentName("com.android.settings",
752                                    "com.android.settings.DevelopmentSettings"));
753                    PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
754                            intent, 0, null, UserHandle.CURRENT);
755                    notification.setLatestEventInfo(mContext, title, message, pi);
756                    notification.visibility = Notification.VISIBILITY_PUBLIC;
757                    mAdbNotificationShown = true;
758                    mNotificationManager.notifyAsUser(null, id, notification,
759                            UserHandle.ALL);
760                }
761            } else if (mAdbNotificationShown) {
762                mAdbNotificationShown = false;
763                mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
764            }
765        }
766
767        public void dump(FileDescriptor fd, PrintWriter pw) {
768            pw.println("  USB Device State:");
769            pw.println("    Current Functions: " + mCurrentFunctions);
770            pw.println("    Default Functions: " + mDefaultFunctions);
771            pw.println("    mConnected: " + mConnected);
772            pw.println("    mConfigured: " + mConfigured);
773            pw.println("    mCurrentAccessory: " + mCurrentAccessory);
774            try {
775                pw.println("    Kernel state: "
776                        + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
777                pw.println("    Kernel function list: "
778                        + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
779                pw.println("    Mass storage backing file: "
780                        + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim());
781            } catch (IOException e) {
782                pw.println("IOException: " + e);
783            }
784        }
785    }
786
787    /* returns the currently attached USB accessory */
788    public UsbAccessory getCurrentAccessory() {
789        return mHandler.getCurrentAccessory();
790    }
791
792    /* opens the currently attached USB accessory */
793    public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
794        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
795        if (currentAccessory == null) {
796            throw new IllegalArgumentException("no accessory attached");
797        }
798        if (!currentAccessory.equals(accessory)) {
799            String error = accessory.toString()
800                    + " does not match current accessory "
801                    + currentAccessory;
802            throw new IllegalArgumentException(error);
803        }
804        getCurrentSettings().checkPermission(accessory);
805        return nativeOpenAccessory();
806    }
807
808    public void setCurrentFunctions(String functions, boolean makeDefault) {
809        if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ") default: " + makeDefault);
810        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, makeDefault);
811    }
812
813    public void setMassStorageBackingFile(String path) {
814        if (path == null) path = "";
815        try {
816            FileUtils.stringToFile(MASS_STORAGE_FILE_PATH, path);
817        } catch (IOException e) {
818           Slog.e(TAG, "failed to write to " + MASS_STORAGE_FILE_PATH);
819        }
820    }
821
822    private void readOemUsbOverrideConfig() {
823        String[] configList = mContext.getResources().getStringArray(
824            com.android.internal.R.array.config_oemUsbModeOverride);
825
826        if (configList != null) {
827            for (String config: configList) {
828                String[] items = config.split(":");
829                if (items.length == 3) {
830                    if (mOemModeMap == null) {
831                        mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
832                    }
833                    List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
834                    if (overrideList == null) {
835                        overrideList = new LinkedList<Pair<String, String>>();
836                        mOemModeMap.put(items[0], overrideList);
837                    }
838                    overrideList.add(new Pair<String, String>(items[1], items[2]));
839                }
840            }
841        }
842    }
843
844    private boolean needsOemUsbOverride() {
845        if (mOemModeMap == null) return false;
846
847        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
848        return (mOemModeMap.get(bootMode) != null) ? true : false;
849    }
850
851    private String processOemUsbOverride(String usbFunctions) {
852        if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
853
854        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
855
856        List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
857        if (overrides != null) {
858            for (Pair<String, String> pair: overrides) {
859                if (pair.first.equals(usbFunctions)) {
860                    Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
861                    return pair.second;
862                }
863            }
864        }
865        // return passed in functions as is.
866        return usbFunctions;
867    }
868
869    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
870        if (mDebuggingManager != null) {
871            mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
872        }
873    }
874
875    public void denyUsbDebugging() {
876        if (mDebuggingManager != null) {
877            mDebuggingManager.denyUsbDebugging();
878        }
879    }
880
881    public void clearUsbDebuggingKeys() {
882        if (mDebuggingManager != null) {
883            mDebuggingManager.clearUsbDebuggingKeys();
884        } else {
885            throw new RuntimeException("Cannot clear Usb Debugging keys, "
886                        + "UsbDebuggingManager not enabled");
887        }
888    }
889
890    public void dump(FileDescriptor fd, PrintWriter pw) {
891        if (mHandler != null) {
892            mHandler.dump(fd, pw);
893        }
894        if (mDebuggingManager != null) {
895            mDebuggingManager.dump(fd, pw);
896        }
897    }
898
899    private native String[] nativeGetAccessoryStrings();
900    private native ParcelFileDescriptor nativeOpenAccessory();
901    private native boolean nativeIsStartRequested();
902    private native int nativeGetAudioMode();
903}
904