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