framework: storage: Add 'force' option to unmount/destroy storage apis, and update callsites.

Also adds additional storage unit tests

Signed-off-by: San Mehat <san@google.com>
diff --git a/api/current.xml b/api/current.xml
index 5592759..8573a36 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -119461,6 +119461,17 @@
  visibility="public"
 >
 </field>
+<field name="OperationFailedStorageBusy"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="OperationFailedStorageMounted"
  type="int"
  transient="false"
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 816baf3..79a6cfe 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -63,7 +63,7 @@
      * Safely unmount external storage at given mount point.
      * Returns an int consistent with MountServiceResultCode
      */
-    int unmountVolume(String mountPoint);
+    int unmountVolume(String mountPoint, boolean force);
 
     /**
      * Format external storage given a mount point.
@@ -100,7 +100,7 @@
      * NOTE: Ensure all references are released prior to deleting.
      * Returns an int consistent with MountServiceResultCode
      */
-    int destroySecureContainer(String id);
+    int destroySecureContainer(String id, boolean force);
 
     /*
      * Mount a secure container with the specified key and owner UID.
@@ -112,7 +112,7 @@
      * Unount a secure container.
      * Returns an int consistent with MountServiceResultCode
      */
-    int unmountSecureContainer(String id);
+    int unmountSecureContainer(String id, boolean force);
 
     /*
      * Returns true if the specified container is mounted
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
index 249bacf..07d95df 100644
--- a/core/java/android/os/storage/StorageResultCode.java
+++ b/core/java/android/os/storage/StorageResultCode.java
@@ -64,4 +64,10 @@
      */
     public static final int OperationFailedStorageMounted     = -6;
 
+    /**
+     * Operation failed: Storage is busy.
+     * @see android.os.storage.StorageManager
+     */
+    public static final int OperationFailedStorageBusy        = -7;
+
 }
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index c5b869b..bc7dbf4 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -93,7 +93,7 @@
 
    public static boolean unMountSdDir(String cid) {
     try {
-        int rc = getMountService().unmountSecureContainer(cid);
+        int rc = getMountService().unmountSecureContainer(cid, false);
         if (rc != StorageResultCode.OperationSucceeded) {
             Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
             return false;
@@ -148,7 +148,7 @@
 
     public static boolean destroySdDir(String cid) {
         try {
-            int rc = getMountService().destroySecureContainer(cid);
+            int rc = getMountService().destroySecureContainer(cid, false);
             if (rc != StorageResultCode.OperationSucceeded) {
                 Log.i(TAG, "Failed to destroy container " + cid);
                 return false;
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 4e2ffa4..ad377e3 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -97,7 +97,7 @@
         public static final int OpFailedMediaBlank             = 402;
         public static final int OpFailedMediaCorrupt           = 403;
         public static final int OpFailedVolNotMounted          = 404;
-        public static final int OpFailedVolBusy                = 405;
+        public static final int OpFailedStorageBusy            = 405;
 
         /*
          * 600 series - Unsolicited broadcasts.
@@ -184,7 +184,7 @@
         String vs = getVolumeState(path);
         if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
             mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
-            int rc = doUnmountVolume(path);
+            int rc = doUnmountVolume(path, false);
             mUmsEnabling = false; // Clear override
             if (rc != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
@@ -527,7 +527,7 @@
         return rc;
     }
 
-    private int doUnmountVolume(String path) {
+    private int doUnmountVolume(String path, boolean force) {
         if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
             return VoldResponseCode.OpFailedVolNotMounted;
         }
@@ -537,7 +537,8 @@
         // notified that the applications installed on the media will be killed.
         mPms.updateExternalMediaStatus(false);
         try {
-            mConnector.doCommand(String.format("volume unmount %s", path));
+            mConnector.doCommand(String.format(
+                    "volume unmount %s%s", path, (force ? " force" : "")));
             return StorageResultCode.OperationSucceeded;
         } catch (NativeDaemonConnectorException e) {
             // Don't worry about mismatch in PackageManager since the
@@ -545,6 +546,8 @@
             int code = e.getCode();
             if (code == VoldResponseCode.OpFailedVolNotMounted) {
                 return StorageResultCode.OperationFailedStorageNotMounted;
+            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
+                return StorageResultCode.OperationFailedStorageBusy;
             } else {
                 return StorageResultCode.OperationFailedInternalError;
             }
@@ -733,7 +736,7 @@
             /*
              * If the media is mounted, then gracefully unmount it.
              */
-            if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) {
+            if (doUnmountVolume(path, true) != StorageResultCode.OperationSucceeded) {
                 Log.e(TAG, "Failed to unmount media for shutdown");
             }
         }
@@ -782,11 +785,11 @@
         return doMountVolume(path);
     }
 
-    public int unmountVolume(String path) {
+    public int unmountVolume(String path, boolean force) {
         validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
         waitForReady();
 
-        return doUnmountVolume(path);
+        return doUnmountVolume(path, force);
     }
 
     public int formatVolume(String path) {
@@ -878,16 +881,21 @@
         return rc;
     }
 
-    public int destroySecureContainer(String id) {
+    public int destroySecureContainer(String id, boolean force) {
         validatePermission(android.Manifest.permission.ASEC_DESTROY);
         waitForReady();
         warnOnNotMounted();
 
         int rc = StorageResultCode.OperationSucceeded;
         try {
-            mConnector.doCommand(String.format("asec destroy %s", id));
+            mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
         } catch (NativeDaemonConnectorException e) {
-            rc = StorageResultCode.OperationFailedInternalError;
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedStorageBusy) {
+                rc = StorageResultCode.OperationFailedStorageBusy;
+            } else {
+                rc = StorageResultCode.OperationFailedInternalError;
+            }
         }
 
         if (rc == StorageResultCode.OperationSucceeded) {
@@ -928,7 +936,7 @@
         return rc;
     }
 
-    public int unmountSecureContainer(String id) {
+    public int unmountSecureContainer(String id, boolean force) {
         validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
         waitForReady();
         warnOnNotMounted();
@@ -940,11 +948,16 @@
          }
 
         int rc = StorageResultCode.OperationSucceeded;
-        String cmd = String.format("asec unmount %s", id);
+        String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
         try {
             mConnector.doCommand(cmd);
         } catch (NativeDaemonConnectorException e) {
-            rc = StorageResultCode.OperationFailedInternalError;
+            int code = e.getCode();
+            if (code == VoldResponseCode.OpFailedStorageBusy) {
+                rc = StorageResultCode.OperationFailedStorageBusy;
+            } else {
+                rc = StorageResultCode.OperationFailedInternalError;
+            }
         }
 
         if (rc == StorageResultCode.OperationSucceeded) {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
index 7569d7a..bdf397c 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
@@ -73,7 +73,7 @@
 
         for (int i = 0; i < containers.length; i++) {
             if (containers[i].startsWith("com.android.unittests.AsecTests.")) {
-                ms.destroySecureContainer(containers[i]);
+                ms.destroySecureContainer(containers[i], true);
             }
         }
     }
@@ -103,7 +103,32 @@
         Assert.assertTrue(isMediaMounted());
         IMountService ms = getMs();
         try {
-            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testCreateContainer", 4, "fat", "none", 1000);
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testCreateContainer",
+                    4, "fat", "none", android.os.Process.myUid());
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testCreateZeroSizeContainer() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testCreateZeroSizeContainer",
+                    0, "fat", "none", android.os.Process.myUid());
+            Assert.assertEquals(StorageResultCode.OperationFailedInternalError, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testCreateMinSizeContainer() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testCreateMinSizeContainer",
+                    1, "fat", "none", android.os.Process.myUid());
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
         } catch (Exception e) {
             failStr(e);
@@ -114,9 +139,10 @@
         Assert.assertTrue(isMediaMounted());
         IMountService ms = getMs();
         try {
-            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testDestroyContainer", 4, "fat", "none", 1000);
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testDestroyContainer",
+                    4, "fat", "none", android.os.Process.myUid());
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
-            rc = ms.destroySecureContainer("com.android.unittests.AsecTests.testDestroyContainer");
+            rc = ms.destroySecureContainer("com.android.unittests.AsecTests.testDestroyContainer", true);
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
         } catch (Exception e) {
             failStr(e);
@@ -128,13 +154,15 @@
         IMountService ms = getMs();
         try {
             int rc = ms.createSecureContainer(
-                    "com.android.unittests.AsecTests.testMountContainer", 4, "fat", "none", 1000);
+                    "com.android.unittests.AsecTests.testMountContainer",
+                            4, "fat", "none", android.os.Process.myUid());
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
 
-            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountContainer");
+            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountContainer", false);
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
 
-            rc = ms.mountSecureContainer("com.android.unittests.AsecTests.testMountContainer", "none", 1000);
+            rc = ms.mountSecureContainer("com.android.unittests.AsecTests.testMountContainer", "none",
+                    android.os.Process.myUid());
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
         } catch (Exception e) {
             failStr(e);
@@ -147,10 +175,10 @@
         try {
             int rc = ms.createSecureContainer(
                     "com.android.unittests.AsecTests.testMountBadKey", 4, "fat",
-                            "00000000000000000000000000000000", 1000);
+                            "00000000000000000000000000000000", android.os.Process.myUid());
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
 
-            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountBadKey");
+            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testMountBadKey", false);
             Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
 
             rc = ms.mountSecureContainer(
@@ -165,4 +193,52 @@
             failStr(e);
         }
     }
+
+    public void testUnmountBusyContainer() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testUnmountBusyContainer",
+                    4, "fat", "none", android.os.Process.myUid());
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+
+            String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer");
+            Context con = super.getContext();
+
+            File f = new File(path, "reference");
+            FileOutputStream fos = new FileOutputStream(f);
+            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testUnmountBusyContainer", false);
+            Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy, rc);
+            fos.close();
+
+            rc = ms.unmountSecureContainer("com.android.unittests.AsecTests.testUnmountBusyContainer", false);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
+
+    public void testDestroyBusyContainer() {
+        Assert.assertTrue(isMediaMounted());
+        IMountService ms = getMs();
+        try {
+            int rc = ms.createSecureContainer("com.android.unittests.AsecTests.testUnmountBusyContainer",
+                    4, "fat", "none", android.os.Process.myUid());
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+
+            String path = ms.getSecureContainerPath("com.android.unittests.AsecTests.testUnmountBusyContainer");
+            Context con = super.getContext();
+
+            File f = new File(path, "reference");
+            FileOutputStream fos = new FileOutputStream(f);
+            rc = ms.destroySecureContainer("com.android.unittests.AsecTests.testUnmountBusyContainer", false);
+            Assert.assertEquals(StorageResultCode.OperationFailedStorageBusy, rc);
+            fos.close();
+
+            rc = ms.destroySecureContainer("com.android.unittests.AsecTests.testUnmountBusyContainer", false);
+            Assert.assertEquals(StorageResultCode.OperationSucceeded, rc);
+        } catch (Exception e) {
+            failStr(e);
+        }
+    }
 }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 8f4d0a1..be9571c 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -716,7 +716,7 @@
         }
         try {
         String mPath = Environment.getExternalStorageDirectory().toString();
-        int ret = getMs().unmountVolume(mPath);
+        int ret = getMs().unmountVolume(mPath, false);
         return ret == StorageResultCode.OperationSucceeded;
         } catch (RemoteException e) {
             return true;