framework: MountService: Add initial support for Android Secure External Caches
Signed-off-by: San Mehat <san@google.com>
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
index 447e764..1ea7200 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/IMountService.aidl
@@ -80,4 +80,39 @@
* Gets the state of an volume via it's mountpoint.
*/
String getVolumeState(String mountPoint);
+
+ /*
+ * Creates a secure cache with the specified parameters.
+ * On success, the filesystem cache-path is returned.
+ */
+ String createSecureCache(String id, int sizeMb, String fstype, String key, int ownerUid);
+
+ /*
+ * Finalize a cache which has just been created and populated.
+ * After finalization, the cache is immutable.
+ */
+ void finalizeSecureCache(String id);
+
+ /*
+ * Destroy a secure cache, and free up all resources associated with it.
+ * NOTE: Ensure all references are released prior to deleting.
+ */
+ void destroySecureCache(String id);
+
+ /*
+ * Mount a secure cache with the specified key and owner UID.
+ * On success, the filesystem cache-path is returned.
+ */
+ String mountSecureCache(String id, String key, int ownerUid);
+
+ /*
+ * Returns the filesystem path of a mounted secure cache.
+ */
+ String getSecureCachePath(String id);
+
+ /**
+ * Gets an Array of currently known secure cache IDs
+ */
+ String[] getSecureCacheList();
+
}
diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp
index fe11878..7f0dda7 100644
--- a/media/sdutils/sdutil.cpp
+++ b/media/sdutils/sdutil.cpp
@@ -99,6 +99,42 @@
return -1;
}
+static int asec_create(const char *id, int sizeMb, const char *fstype,
+ const char *key, int ownerUid) {
+ String16 sId(id);
+ String16 sFstype(fstype);
+ String16 sKey(key);
+
+ String16 r = gMountService->createSecureCache(sId, sizeMb, sFstype,
+ sKey, ownerUid);
+ return 0;
+}
+
+static int asec_finalize(const char *id) {
+ String16 sId(id);
+ gMountService->finalizeSecureCache(sId);
+ return 0;
+}
+
+static int asec_destroy(const char *id) {
+ String16 sId(id);
+ gMountService->destroySecureCache(sId);
+ return 0;
+}
+
+static int asec_mount(const char *id, const char *key, int ownerUid) {
+ String16 sId(id);
+ String16 sKey(key);
+ gMountService->mountSecureCache(sId, sKey, ownerUid);
+ return 0;
+}
+
+static int asec_path(const char *id) {
+ String16 sId(id);
+ gMountService->getSecureCachePath(sId);
+ return 0;
+}
+
static int unmount(const char* path) {
String16 string(path);
gMountService->unmountMedia(string);
@@ -153,14 +189,42 @@
android::init();
return android::umsEnable(false);
}
+ } else if (!strcmp(command, "asec")) {
+ const char* id = (argc > 3 ? argv[3] : NULL);
+
+ if (!id)
+ goto usage;
+
+ android::init();
+ if (!strcmp(argument, "create")) {
+
+ if (argc != 8)
+ goto usage;
+ return android::asec_create(id, atoi(argv[4]), argv[5], argv[6],
+ atoi(argv[7]));
+ } else if (!strcmp(argument, "finalize")) {
+ return android::asec_finalize(id);
+ } else if (!strcmp(argument, "destroy")) {
+ return android::asec_destroy(id);
+ } else if (!strcmp(argument, "mount")) {
+ return android::asec_mount(id, argv[4], atoi(argv[5]));
+ } else if (!strcmp(argument, "path")) {
+ return android::asec_path(id);
+ }
}
+usage:
fprintf(stderr, "usage:\n"
" sdutil mount <mount path> - mounts the SD card at the given mount point\n"
" sdutil unmount <mount path> - unmounts the SD card at the given mount point\n"
" sdutil format <mount path> - formats the SD card at the given mount point\n"
" sdutil ums enable - enables USB mass storage\n"
- " sdutil ums disable - disnables USB mass storage\n"
+ " sdutil ums disable - disables USB mass storage\n"
+ " sdutil asec create <id> <sizeMb> <fstype> <key> <ownerUid>\n"
+ " sdutil asec finalize <id>\n"
+ " sdutil asec destroy <id>\n"
+ " sdutil asec mount <id> <key> <ownerUid>\n"
+ " sdutil asec path <id>\n"
);
return -1;
}
diff --git a/services/java/com/android/server/MountListener.java b/services/java/com/android/server/MountListener.java
index d4943ff..5a1107b 100644
--- a/services/java/com/android/server/MountListener.java
+++ b/services/java/com/android/server/MountListener.java
@@ -21,7 +21,6 @@
import android.os.Environment;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.RemoteException;
import android.util.Config;
import android.util.Log;
@@ -29,6 +28,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
+import java.lang.IllegalStateException;
import java.util.List;
import java.util.ArrayList;
@@ -49,7 +49,13 @@
private OutputStream mOutputStream;
class ResponseCode {
+ public static final int ActionInitiated = 100;
+ public static final int VolumeListResult = 110;
+ public static final int AsecListResult = 111;
+
+ public static final int CommandOkay = 200;
public static final int ShareAvailabilityResult = 210;
+ public static final int AsecPathResult = 211;
public static final int UnsolicitedInformational = 600;
public static final int VolumeStateChange = 605;
@@ -163,7 +169,8 @@
SystemClock.sleep(5000);
}
- private void handleUnsolicitedEvent(int code, String raw, String[] cooked) throws RemoteException {
+ private void handleUnsolicitedEvent(int code, String raw,
+ String[] cooked) throws IllegalStateException {
// Log.d(TAG, "unsolicited {" + raw + "}");
if (code == ResponseCode.VolumeStateChange) {
// FMT: NNN Volume <label> <mountpoint> state changed from <old_#> (<old_str>) to <new_#> (<new_str>)
@@ -232,7 +239,7 @@
}
}
- private synchronized ArrayList<String> doCommand(String cmd) throws RemoteException {
+ private synchronized ArrayList<String> doCommand(String cmd) throws IllegalStateException {
sendCommand(cmd);
ArrayList<String> response = new ArrayList<String>();
@@ -255,13 +262,14 @@
}
if (code >= 400 && code < 600) {
- Log.w(TAG, "Vold cmd {" + cmd + "} err code " + code);
- throw new RemoteException();
+ throw new IllegalStateException(String.format(
+ "Command %s failed with code %d",
+ cmd, code));
}
return response;
}
- boolean getShareAvailable(String method) throws RemoteException {
+ boolean getShareAvailable(String method) throws IllegalStateException {
ArrayList<String> rsp = doCommand("share_available " + method);
for (String line : rsp) {
@@ -272,10 +280,10 @@
return true;
return false;
} else {
- throw new RemoteException();
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
}
}
- throw new RemoteException();
+ throw new IllegalStateException("Got an empty response");
}
/**
@@ -283,28 +291,87 @@
*
* @param enable true to enable USB mass storage support
*/
- void setShareMethodEnabled(String mountPoint, String method, boolean enable) throws RemoteException {
+ void setShareMethodEnabled(String mountPoint, String method,
+ boolean enable) throws IllegalStateException {
doCommand((enable ? "" : "un") + "share " + mountPoint + " " + method);
}
/**
* Mount media at given mount point.
*/
- public void mountVolume(String label) throws RemoteException {
+ public void mountVolume(String label) throws IllegalStateException {
doCommand("mount " + label);
}
/**
* Unmount media at given mount point.
*/
- public void unmountVolume(String label) throws RemoteException {
+ public void unmountVolume(String label) throws IllegalStateException {
doCommand("unmount " + label);
}
/**
* Format media at given mount point.
*/
- public void formatVolume(String label) throws RemoteException {
+ public void formatVolume(String label) throws IllegalStateException {
doCommand("format " + label);
}
+
+ public String createAsec(String id, int sizeMb, String fstype, String key,
+ int ownerUid) throws IllegalStateException {
+ String cmd = String.format("create_asec %s %d %s %s %d",
+ id, sizeMb, fstype, key, ownerUid);
+ doCommand(cmd);
+ return getAsecPath(id);
+ }
+
+ public void finalizeAsec(String id) throws IllegalStateException {
+ doCommand("finalize_asec " + id);
+ }
+
+ public void destroyAsec(String id) throws IllegalStateException {
+ doCommand("destroy_asec " + id);
+ }
+
+ public String mountAsec(String id, String key, int ownerUid) throws IllegalStateException {
+ String cmd = String.format("mount_asec %s %s %d",
+ id, key, ownerUid);
+ doCommand(cmd);
+ return getAsecPath(id);
+ }
+
+ public String getAsecPath(String id) throws IllegalStateException {
+ ArrayList<String> rsp = doCommand("asec_path " + id);
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == ResponseCode.AsecPathResult) {
+ return tok[1];
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
+
+ public String[] listAsec() throws IllegalStateException {
+ ArrayList<String> rsp = doCommand("list_asec");
+
+ String[] rdata = new String[rsp.size()];
+ int idx = 0;
+
+ for (String line : rsp) {
+ String []tok = line.split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code == ResponseCode.AsecPathResult) {
+ rdata[idx++] = tok[1];
+ } else if (code == ResponseCode.CommandOkay) {
+ return rdata;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ throw new IllegalStateException("Got an empty response");
+ }
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 93617d1..1b0b0eb 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -28,7 +28,6 @@
import android.net.Uri;
import android.os.IMountService;
import android.os.Environment;
-import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.text.TextUtils;
@@ -36,6 +35,7 @@
import java.io.File;
import java.io.FileReader;
+import java.lang.IllegalStateException;
/**
* MountService implements an to the mount service daemon
@@ -136,7 +136,7 @@
/**
* @return true if USB mass storage support is enabled.
*/
- public boolean getMassStorageEnabled() throws RemoteException {
+ public boolean getMassStorageEnabled() {
return mUmsEnabled;
}
@@ -145,7 +145,7 @@
*
* @param enable true to enable USB mass storage support
*/
- public void setMassStorageEnabled(boolean enable) throws RemoteException {
+ public void setMassStorageEnabled(boolean enable) throws IllegalStateException {
try {
String vp = Environment.getExternalStorageDirectory().getPath();
String vs = getVolumeState(vp);
@@ -164,7 +164,7 @@
Log.d(TAG, "Mounting media after UMS disable");
mountMedia(vp);
}
- } catch (RemoteException rex) {
+ } catch (IllegalStateException rex) {
Log.e(TAG, "Failed to set ums enable {" + enable + "}");
return;
}
@@ -173,14 +173,14 @@
/**
* @return true if USB mass storage is connected.
*/
- public boolean getMassStorageConnected() throws RemoteException {
+ public boolean getMassStorageConnected() {
return mUmsConnected;
}
/**
* @return state of the volume at the specified mount point
*/
- public String getVolumeState(String mountPoint) throws RemoteException {
+ public String getVolumeState(String mountPoint) throws IllegalStateException {
/*
* XXX: Until we have multiple volume discovery, just hardwire
* this to /sdcard
@@ -197,7 +197,7 @@
/**
* Attempt to mount external media
*/
- public void mountMedia(String mountPath) throws RemoteException {
+ public void mountMedia(String mountPath) throws IllegalStateException {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -209,7 +209,7 @@
/**
* Attempt to unmount external media to prepare for eject
*/
- public void unmountMedia(String mountPath) throws RemoteException {
+ public void unmountMedia(String mountPath) throws IllegalStateException {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -227,7 +227,7 @@
/**
* Attempt to format external media
*/
- public void formatMedia(String formatPath) throws RemoteException {
+ public void formatMedia(String formatPath) throws IllegalStateException {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -306,7 +306,7 @@
} else {
setUsbStorageNotification(0, 0, 0, false, false, null);
}
- } catch (RemoteException e) {
+ } catch (IllegalStateException e) {
// Nothing to do
}
}
@@ -335,7 +335,7 @@
} else {
Log.d(TAG, "Skipping connection-mount; already mounted");
}
- } catch (RemoteException rex) {
+ } catch (IllegalStateException rex) {
Log.e(TAG, "Exception while handling connection mount " + rex);
}
@@ -350,7 +350,7 @@
}
void notifyVolumeStateChange(String label, String mountPoint, int oldState,
- int newState) throws RemoteException {
+ int newState) throws IllegalStateException {
String vs = getVolumeState(mountPoint);
if (newState == VolumeState.Init) {
@@ -395,7 +395,7 @@
if (mAutoStartUms) {
try {
setMassStorageEnabled(true);
- } catch (RemoteException e) {
+ } catch (IllegalStateException e) {
}
} else {
updateUsbMassStorageNotification(false, true);
@@ -429,7 +429,7 @@
mContext.sendBroadcast(intent);
}
- void notifyMediaInserted(final String path) throws RemoteException {
+ void notifyMediaInserted(final String path) throws IllegalStateException {
new Thread() {
public void run() {
try {
@@ -445,7 +445,7 @@
/**
* Broadcasts the media removed event to all clients.
*/
- void notifyMediaRemoved(String path) throws RemoteException {
+ void notifyMediaRemoved(String path) throws IllegalStateException {
// Suppress this on bad removal
if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
@@ -755,5 +755,31 @@
notificationManager.cancel(notificationId);
}
}
+
+ public String[] getSecureCacheList() throws IllegalStateException {
+ return mListener.listAsec();
+ }
+
+ public String createSecureCache(String id, int sizeMb, String fstype,
+ String key, int ownerUid) throws IllegalStateException {
+ return mListener.createAsec(id, sizeMb, fstype, key, ownerUid);
+ }
+
+ public void finalizeSecureCache(String id) throws IllegalStateException {
+ mListener.finalizeAsec(id);
+ }
+
+ public void destroySecureCache(String id) throws IllegalStateException {
+ mListener.destroyAsec(id);
+ }
+
+ public String mountSecureCache(String id, String key, int ownerUid) throws IllegalStateException {
+ return mListener.mountAsec(id, key, ownerUid);
+ }
+
+ public String getSecureCachePath(String id) throws IllegalStateException {
+ return mListener.getAsecPath(id);
+ }
+
}