Add OEM specific USB mode enumeration based on ro.bootmode property

This patch is adding a capability so that OEM can override USB mode
in case the device is boot up with OEM specific mode. (i.e. modem
debug, factory test etc.)

Bug:5964042
Change-Id: Ic8e23d302563ce71eedb74ce94cca8c65838a4f7
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 30002c5..5eb09e6 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -745,4 +745,11 @@
     <!-- Base "touch slop" value used by ViewConfiguration as a
          movement threshold where scrolling should begin. -->
     <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
+
+    <!-- Array of OEM specific USB mode override config.
+         OEM can override a certain USB mode depending on ro.bootmode.
+         Specify an array of below items to set override rule.
+         [bootmode]:[original USB mode]:[USB mode used]-->
+    <integer-array translatable="false" name="config_oemUsbModeOverride">
+    </integer-array>
 </resources>
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 8f51466..ed83fbe 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -46,6 +46,7 @@
 import android.os.SystemProperties;
 import android.os.UEventObserver;
 import android.provider.Settings;
+import android.util.Pair;
 import android.util.Slog;
 
 import java.io.File;
@@ -54,7 +55,10 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * UsbDeviceManager manages USB state in device mode.
@@ -88,6 +92,8 @@
     // which need debouncing.
     private static final int UPDATE_DELAY = 1000;
 
+    private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
+
     private UsbHandler mHandler;
     private boolean mBootCompleted;
 
@@ -98,6 +104,7 @@
     private final boolean mHasUsbAccessory;
     private boolean mUseUsbNotification;
     private boolean mAdbEnabled;
+    private Map<String, List<Pair<String, String>>> mOemModeMap;
 
     private class AdbSettingsObserver extends ContentObserver {
         public AdbSettingsObserver() {
@@ -138,6 +145,8 @@
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
         initRndisAddress();
 
+        readOemUsbOverrideConfig();
+
         // create a thread for our Handler
         HandlerThread thread = new HandlerThread("UsbDeviceManager",
                 Process.THREAD_PRIORITY_BACKGROUND);
@@ -259,6 +268,10 @@
                 // persist.sys.usb.config should never be unset.  But if it is, set it to "adb"
                 // so we have a chance of debugging what happened.
                 mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
+
+                // Check if USB mode needs to be overridden depending on OEM specific bootmode.
+                mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
+
                 // sanity check the sys.usb.config system property
                 // this may be necessary if we crashed while switching USB configurations
                 String config = SystemProperties.get("sys.usb.config", "none");
@@ -381,7 +394,11 @@
         }
 
         private void setEnabledFunctions(String functions, boolean makeDefault) {
-            if (functions != null && makeDefault) {
+
+            // Do not update persystent.sys.usb.config if the device is booted up
+            // with OEM specific mode.
+            if (functions != null && makeDefault && !needsOemUsbOverride()) {
+
                 if (mAdbEnabled) {
                     functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                 } else {
@@ -410,6 +427,10 @@
                 if (functions == null) {
                     functions = mDefaultFunctions;
                 }
+
+                // Override with bootmode specific usb mode if needed
+                functions = processOemUsbOverride(functions);
+
                 if (mAdbEnabled) {
                     functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
                 } else {
@@ -671,6 +692,53 @@
         }
     }
 
+    private void readOemUsbOverrideConfig() {
+        String[] configList = mContext.getResources().getStringArray(
+            com.android.internal.R.array.config_oemUsbModeOverride);
+
+        if (configList != null) {
+            for (String config: configList) {
+                String[] items = config.split(":");
+                if (items.length == 3) {
+                    if (mOemModeMap == null) {
+                        mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
+                    }
+                    List overrideList = mOemModeMap.get(items[0]);
+                    if (overrideList == null) {
+                        overrideList = new LinkedList<Pair<String, String>>();
+                        mOemModeMap.put(items[0], overrideList);
+                    }
+                    overrideList.add(new Pair<String, String>(items[1], items[2]));
+                }
+            }
+        }
+    }
+
+    private boolean needsOemUsbOverride() {
+        if (mOemModeMap == null) return false;
+
+        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+        return (mOemModeMap.get(bootMode) != null) ? true : false;
+    }
+
+    private String processOemUsbOverride(String usbFunctions) {
+        if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
+
+        String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+
+        List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
+        if (overrides != null) {
+            for (Pair<String, String> pair: overrides) {
+                if (pair.first.equals(usbFunctions)) {
+                    Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
+                    return pair.second;
+                }
+            }
+        }
+        // return passed in functions as is.
+        return usbFunctions;
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw) {
         if (mHandler != null) {
             mHandler.dump(fd, pw);