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