Merge "Abort long-running benchmarks, report progress."
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index a9a4118..699de94 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,6 +20,9 @@
 import static android.os.storage.StorageManager.PROP_HAS_ADOPTABLE;
 import static android.os.storage.StorageManager.PROP_VIRTUAL_DISK;
 
+import android.os.IBinder;
+import android.os.IVoldTaskListener;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
@@ -29,6 +32,8 @@
 import android.os.storage.VolumeInfo;
 import android.util.Log;
 
+import java.util.concurrent.CompletableFuture;
+
 public final class Sm {
     private static final String TAG = "Sm";
 
@@ -221,9 +226,23 @@
         mSm.format(volId);
     }
 
-    public void runBenchmark() throws RemoteException {
+    public void runBenchmark() throws Exception {
         final String volId = nextArg();
-        mSm.benchmark(volId);
+        final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+        mSm.benchmark(volId, new IVoldTaskListener.Stub() {
+            @Override
+            public void onStatus(int status, PersistableBundle extras) {
+                // Ignored
+            }
+
+            @Override
+            public void onFinished(int status, PersistableBundle extras) {
+                // Touch to unparcel
+                extras.size();
+                result.complete(extras);
+            }
+        });
+        System.out.println(result.get());
     }
 
     public void runForget() throws RemoteException {
@@ -235,8 +254,22 @@
         }
     }
 
-    public void runFstrim() throws RemoteException {
-        mSm.fstrim(0);
+    public void runFstrim() throws Exception {
+        final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+        mSm.fstrim(0, new IVoldTaskListener.Stub() {
+            @Override
+            public void onStatus(int status, PersistableBundle extras) {
+                // Ignored
+            }
+
+            @Override
+            public void onFinished(int status, PersistableBundle extras) {
+                // Touch to unparcel
+                extras.size();
+                result.complete(extras);
+            }
+        });
+        System.out.println(result.get());
     }
 
     public void runSetVirtualDisk() throws RemoteException {
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index e865ed1..0b76eec 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -17,6 +17,7 @@
 package android.os.storage;
 
 import android.content.pm.IPackageMoveObserver;
+import android.os.IVoldTaskListener;
 import android.os.ParcelFileDescriptor;
 import android.os.storage.DiskInfo;
 import android.os.storage.IStorageEventListener;
@@ -165,7 +166,7 @@
     void forgetAllVolumes() = 56;
     String getPrimaryStorageUuid() = 57;
     void setPrimaryStorageUuid(in String volumeUuid, IPackageMoveObserver callback) = 58;
-    long benchmark(in String volId) = 59;
+    void benchmark(in String volId, IVoldTaskListener listener) = 59;
     void setDebugFlags(int flags, int mask) = 60;
     void createUserKey(int userId, int serialNumber, boolean ephemeral) = 61;
     void destroyUserKey(int userId) = 62;
@@ -177,7 +178,7 @@
     boolean isConvertibleToFBE() = 68;
     void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
     void fixateNewestUserKeyAuth(int userId) = 71;
-    void fstrim(int flags) = 72;
+    void fstrim(int flags, IVoldTaskListener listener) = 72;
     AppFuseMount mountProxyFileDescriptorBridge() = 73;
     ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
     long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 6594cd0..0b007dd 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -42,10 +42,12 @@
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IVold;
+import android.os.IVoldTaskListener;
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelableException;
+import android.os.PersistableBundle;
 import android.os.ProxyFileDescriptorCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -87,7 +89,9 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -884,9 +888,32 @@
     }
 
     /** {@hide} */
+    @Deprecated
     public long benchmark(String volId) {
+        final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+        benchmark(volId, new IVoldTaskListener.Stub() {
+            @Override
+            public void onStatus(int status, PersistableBundle extras) {
+                // Ignored
+            }
+
+            @Override
+            public void onFinished(int status, PersistableBundle extras) {
+                result.complete(extras);
+            }
+        });
         try {
-            return mStorageManager.benchmark(volId);
+            // Convert ms to ns
+            return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
+        } catch (Exception e) {
+            return Long.MAX_VALUE;
+        }
+    }
+
+    /** {@hide} */
+    public void benchmark(String volId, IVoldTaskListener listener) {
+        try {
+            mStorageManager.benchmark(volId, listener);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index bfbce40..75e8000 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -56,6 +56,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.IProgressListener;
 import android.os.IStoraged;
 import android.os.IVold;
 import android.os.IVoldListener;
@@ -570,7 +571,7 @@
                     }
 
                     // TODO: Reintroduce shouldBenchmark() test
-                    fstrim(0);
+                    fstrim(0, null);
 
                     // invoke the completion callback, if any
                     // TODO: fstrim is non-blocking, so remove this useless callback
@@ -1576,21 +1577,19 @@
     }
 
     @Override
-    public long benchmark(String volId) {
+    public void benchmark(String volId, IVoldTaskListener listener) {
         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
 
-        // TODO: refactor for callers to provide a listener
         try {
-            final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
             mVold.benchmark(volId, new IVoldTaskListener.Stub() {
                 @Override
                 public void onStatus(int status, PersistableBundle extras) {
-                    // Not currently used
+                    dispatchOnStatus(listener, status, extras);
                 }
 
                 @Override
                 public void onFinished(int status, PersistableBundle extras) {
-                    result.complete(extras);
+                    dispatchOnFinished(listener, status, extras);
 
                     final String path = extras.getString("path");
                     final String ident = extras.getString("ident");
@@ -1611,10 +1610,8 @@
                     }
                 }
             });
-            return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE);
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
-            return Long.MAX_VALUE;
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
         }
     }
 
@@ -1742,13 +1739,15 @@
     }
 
     @Override
-    public void fstrim(int flags) {
+    public void fstrim(int flags, IVoldTaskListener listener) {
         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
 
         try {
             mVold.fstrim(flags, new IVoldTaskListener.Stub() {
                 @Override
                 public void onStatus(int status, PersistableBundle extras) {
+                    dispatchOnStatus(listener, status, extras);
+
                     // Ignore trim failures
                     if (status != 0) return;
 
@@ -1770,12 +1769,13 @@
 
                 @Override
                 public void onFinished(int status, PersistableBundle extras) {
-                    // Not currently used
+                    dispatchOnFinished(listener, status, extras);
+
                     // TODO: benchmark when desired
                 }
             });
-        } catch (Exception e) {
-            Slog.wtf(TAG, e);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
         }
     }
 
@@ -3239,6 +3239,26 @@
         }
     }
 
+    private void dispatchOnStatus(IVoldTaskListener listener, int status,
+            PersistableBundle extras) {
+        if (listener != null) {
+            try {
+                listener.onStatus(status, extras);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    private void dispatchOnFinished(IVoldTaskListener listener, int status,
+            PersistableBundle extras) {
+        if (listener != null) {
+            try {
+                listener.onFinished(status, extras);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
     private static class Callbacks extends Handler {
         private static final int MSG_STORAGE_STATE_CHANGED = 1;
         private static final int MSG_VOLUME_STATE_CHANGED = 2;