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