Modify UsbDeviceManager stack to allow MtpServer to use FunctionFS drivers.

Functionfs requires MtpServer to write descriptors before the device can be
configured. This adds a new configure call that will occur only when
functions are changed (new argument added to updateUsbStateBroadcast for this)
and be called after sys.usb.config is changed but before the waitForState
call to ensure compatibility with configfs devices.

Bug: 30976142
Change-Id: I7e94a5847d3b19c0fd75139e1b15a3f2a1cea01d
Test: Manual
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 3df57bc..ee646c0 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -181,6 +181,14 @@
     public static final String USB_DATA_UNLOCKED = "unlocked";
 
     /**
+     * Boolean extra indicating whether the intent represents a change in the usb
+     * configuration (as opposed to a state update).
+     *
+     * {@hide}
+     */
+    public static final String USB_CONFIG_CHANGED = "config_changed";
+
+    /**
      * A placeholder indicating that no USB function is being specified.
      * Used to distinguish between selecting no function vs. the default function in
      * {@link #setCurrentFunction(String)}.
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 61fbfb9..3c2ea58 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -67,6 +67,11 @@
         native_remove_storage(storage.getStorageId());
     }
 
+    public static void configure(boolean usePtp) {
+        native_configure(usePtp);
+    }
+
+    public static native final void native_configure(boolean usePtp);
     private native final void native_setup(MtpDatabase database, boolean usePtp);
     private native final void native_run();
     private native final void native_cleanup();
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index d13187c..afd3082 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -56,17 +56,16 @@
     return (MtpServer*)env->GetLongField(thiz, field_MtpServer_nativeContext);
 }
 
+static void android_mtp_configure(JNIEnv *, jobject, jboolean usePtp) {
+    MtpServer::configure(usePtp);
+}
+
 static void
 android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp)
 {
-    int fd = open("/dev/mtp_usb", O_RDWR);
-    if (fd >= 0) {
-        MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase),
-                usePtp, AID_MEDIA_RW, 0664, 0775);
-        env->SetLongField(thiz, field_MtpServer_nativeContext, (jlong)server);
-    } else {
-        ALOGE("could not open MTP driver, errno: %d", errno);
-    }
+    MtpServer* server = new MtpServer(getMtpDatabase(env, javaDatabase),
+            usePtp, AID_MEDIA_RW, 0664, 0775);
+    env->SetLongField(thiz, field_MtpServer_nativeContext, (jlong)server);
 }
 
 static void
@@ -180,6 +179,7 @@
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
+    {"native_configure",              "(Z)V",  (void *)android_mtp_configure},
     {"native_setup",                "(Landroid/mtp/MtpDatabase;Z)V",
                                             (void *)android_mtp_MtpServer_setup},
     {"native_run",                  "()V",  (void *)android_mtp_MtpServer_run},
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 15a1e76..b3f5630 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -351,8 +351,6 @@
                             UsbManager.removeFunction(persisted, UsbManager.USB_FUNCTION_MTP));
                 }
 
-                setEnabledFunctions(null, false, false);
-
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                 updateState(state);
 
@@ -446,13 +444,12 @@
             return false;
         }
 
-        private boolean setUsbConfig(String config) {
+        private void setUsbConfig(String config) {
             if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
             // set the new configuration
             // we always set it due to b/23631400, where adbd was getting killed
             // and not restarted due to property timeouts on some devices
             SystemProperties.set(USB_CONFIG_PROPERTY, config);
-            return waitForState(config);
         }
 
         private void setAdbEnabled(boolean enable) {
@@ -547,8 +544,18 @@
                 // Kick the USB stack to close existing connections.
                 setUsbConfig(UsbManager.USB_FUNCTION_NONE);
 
+                if (!waitForState(UsbManager.USB_FUNCTION_NONE)) {
+                    Slog.e(TAG, "Failed to kick USB config");
+                    return false;
+                }
+
                 // Set the new USB configuration.
-                if (!setUsbConfig(functions)) {
+                setUsbConfig(functions);
+
+                // Start up dependent services.
+                updateUsbStateBroadcastIfNeeded(true);
+
+                if (!waitForState(functions)) {
                     Slog.e(TAG, "Failed to switch USB config to " + functions);
                     return false;
                 }
@@ -631,7 +638,7 @@
             return false;
         }
 
-        private void updateUsbStateBroadcastIfNeeded() {
+        private void updateUsbStateBroadcastIfNeeded(boolean configChanged) {
             // send a sticky broadcast containing current USB state
             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -640,6 +647,7 @@
             intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
             intent.putExtra(UsbManager.USB_CONFIGURED, mConfigured);
             intent.putExtra(UsbManager.USB_DATA_UNLOCKED, isUsbTransferAllowed() && mUsbDataUnlocked);
+            intent.putExtra(UsbManager.USB_CONFIG_CHANGED, configChanged);
 
             if (mCurrentFunctions != null) {
                 String[] functions = mCurrentFunctions.split(",");
@@ -737,7 +745,7 @@
                         setEnabledFunctions(null, false, false);
                     }
                     if (mBootCompleted) {
-                        updateUsbStateBroadcastIfNeeded();
+                        updateUsbStateBroadcastIfNeeded(false);
                         updateUsbFunctions();
                     }
                     break;
@@ -749,7 +757,7 @@
                     args.recycle();
                     updateUsbNotification();
                     if (mBootCompleted) {
-                        updateUsbStateBroadcastIfNeeded();
+                        updateUsbStateBroadcastIfNeeded(false);
                     }
                     break;
                 case MSG_ENABLE_ADB:
@@ -765,11 +773,11 @@
                 case MSG_SYSTEM_READY:
                     updateUsbNotification();
                     updateAdbNotification();
-                    updateUsbStateBroadcastIfNeeded();
                     updateUsbFunctions();
                     break;
                 case MSG_BOOT_COMPLETED:
                     mBootCompleted = true;
+                    setEnabledFunctions(null, false, false);
                     if (mCurrentAccessory != null) {
                         getCurrentSettings().accessoryAttached(mCurrentAccessory);
                     }