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;