Add 'fstrim' command for use from shell.

Test: builds, boots, new command works
Bug: 20948199
Change-Id: If7b122a6c98a4ce2a2f38e545015a22decd1b516
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 4291c77..db3772d 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -92,6 +92,8 @@
             runSetEmulateFbe();
         } else if ("get-fbe-mode".equals(op)) {
             runGetFbeMode();
+        } else if ("fstrim".equals(op)) {
+            runFstrim();
         } else {
             throw new IllegalArgumentException();
         }
@@ -210,7 +212,7 @@
         mSm.benchmark(volId);
     }
 
-    public void runForget() throws RemoteException{
+    public void runForget() throws RemoteException {
         final String fsUuid = nextArg();
         if ("all".equals(fsUuid)) {
             mSm.forgetAllVolumes();
@@ -219,6 +221,10 @@
         }
     }
 
+    public void runFstrim() throws RemoteException {
+        mSm.fstrim(0);
+    }
+
     private String nextArg() {
         if (mNextArg >= mArgs.length) {
             return null;
@@ -240,6 +246,7 @@
         System.err.println("       sm unmount VOLUME");
         System.err.println("       sm format VOLUME");
         System.err.println("       sm benchmark VOLUME");
+        System.err.println("       sm fstrim");
         System.err.println("");
         System.err.println("       sm forget [UUID|all]");
         System.err.println("");
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 98cbce6..27c0526 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -288,4 +288,5 @@
     ParcelFileDescriptor mountAppFuse(in String name) = 69;
     void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
     void fixateNewestUserKeyAuth(int userId) = 71;
-}
\ No newline at end of file
+    void fstrim(int flags) = 72;
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0472e02..3fc7dba 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -134,6 +134,11 @@
     /** {@hide} */
     public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
 
+    /** {@hide} */
+    public static final int FSTRIM_FLAG_DEEP = 1 << 0;
+    /** {@hide} */
+    public static final int FSTRIM_FLAG_BENCHMARK = 1 << 1;
+
     /** @hide The volume is not encrypted. */
     public static final int ENCRYPTION_STATE_NONE = 1;
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 11fabb4..55d31c3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -644,14 +644,8 @@
                         Slog.e(TAG, "Unable to record last fstrim!");
                     }
 
-                    final boolean shouldBenchmark = shouldBenchmark();
-                    try {
-                        // This method must be run on the main (handler) thread,
-                        // so it is safe to directly call into vold.
-                        mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
-                    } catch (NativeDaemonConnectorException ndce) {
-                        Slog.e(TAG, "Failed to run fstrim!");
-                    }
+                    final int flags = shouldBenchmark() ? StorageManager.FSTRIM_FLAG_BENCHMARK : 0;
+                    fstrim(flags);
 
                     // invoke the completion callback, if any
                     // TODO: fstrim is non-blocking, so remove this useless callback
@@ -1956,6 +1950,28 @@
         }
     }
 
+    @Override
+    public void fstrim(int flags) {
+        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+        waitForReady();
+
+        String cmd;
+        if ((flags & StorageManager.FSTRIM_FLAG_DEEP) != 0) {
+            cmd = "dodtrim";
+        } else {
+            cmd = "dotrim";
+        }
+        if ((flags & StorageManager.FSTRIM_FLAG_BENCHMARK) != 0) {
+            cmd += "bench";
+        }
+
+        try {
+            mConnector.execute("fstrim", cmd);
+        } catch (NativeDaemonConnectorException e) {
+            Slog.e(TAG, "Failed to run fstrim: " + e);
+        }
+    }
+
     private void remountUidExternalStorage(int uid, int mode) {
         waitForReady();