vold: Perform fstrim work in a separate thread.

Some devices can take up to a few minutes to do fstrim.  If done
in the same thread as the rest of the vold command listener, then
vold is blocked from responding to any other commands until the
trim is done.  So create a thread to do the work, and return
immediately.

bug: 8688454

Change-Id: I780baae03ba7de2d3e805c3e9f103ec03be84c47
diff --git a/fstrim.c b/fstrim.c
index 156446a..1ffd312 100644
--- a/fstrim.c
+++ b/fstrim.c
@@ -23,10 +23,11 @@
 #include <limits.h>
 #include <linux/fs.h>
 #include <fs_mgr.h>
+#include <pthread.h>
 #define LOG_TAG "fstrim"
 #include "cutils/log.h"
 
-int fstrim_filesystems(void)
+static void *do_fstrim_filesystems(void *ignored)
 {
     int i;
     int fd;
@@ -81,6 +82,36 @@
     }
     SLOGI("Finished fstrim work.\n");
 
-    return ret;
+    return (void *)ret;
 }
 
+int fstrim_filesystems(void)
+{
+    pthread_t t;
+    int ret;
+
+    /* Depending on the emmc chip and size, this can take upwards
+     * of a few minutes.  If done in the same thread as the caller
+     * of this function, that would block vold from accepting any
+     * commands until the trim is finished.  So start another thread
+     * to do the work, and return immediately.
+     *
+     * This function should not be called more than once per day, but
+     * even if it is called a second time before the first one finishes,
+     * the kernel will "do the right thing" and split the work between
+     * the two ioctls invoked in separate threads.
+     */
+    ret = pthread_create(&t, NULL, do_fstrim_filesystems, NULL);
+    if (ret) {
+        SLOGE("Cannot create thread to do fstrim");
+        return ret;
+    }
+
+    ret = pthread_detach(t);
+    if (ret) {
+        SLOGE("Cannot detach thread doing fstrim");
+        return ret;
+    }
+
+    return 0;
+}