diff options
Diffstat (limited to 'services/java/com/android/server/MountService.java')
-rw-r--r-- | services/java/com/android/server/MountService.java | 555 |
1 files changed, 321 insertions, 234 deletions
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 6382646..456244a 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -23,29 +23,34 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; -import android.os.IMountService; -import android.os.IMountServiceListener; -import android.os.MountServiceResultCode; +import android.os.storage.IMountService; +import android.os.storage.IMountServiceListener; +import android.os.storage.StorageResultCode; import android.os.RemoteException; import android.os.IBinder; import android.os.Environment; import android.os.ServiceManager; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UEventObserver; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; +import java.util.HashSet; import java.io.File; import java.io.FileReader; /** - * MountService implements an to the mount service daemon - * @hide + * MountService implements back-end services for platform storage + * management. + * @hide - Applications should use android.os.storage.StorageManager + * to access the MountService. */ class MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks { + private static final boolean LOCAL_LOGD = false; private static final String TAG = "MountService"; @@ -109,45 +114,40 @@ class MountService extends IMountService.Stub private PackageManagerService mPms; private boolean mUmsEnabling; private ArrayList<MountServiceBinderListener> mListeners; + private boolean mBooted; + private boolean mReady; /** - * Constructs a new MountService instance - * - * @param context Binder context for this service + * Private hash of currently mounted secure containers. */ - public MountService(Context context) { - mContext = context; - - // XXX: This will go away soon in favor of IMountServiceObserver - mPms = (PackageManagerService) ServiceManager.getService("package"); - - // Register a BOOT_COMPLETED handler so that we can start - // our NativeDaemonConnector. We defer the startup so that we don't - // start processing events before we ought-to - mContext.registerReceiver(mBroadcastReceiver, - new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + private HashSet<String> mAsecMountSet = new HashSet<String>(); - mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector"); - mListeners = new ArrayList<MountServiceBinderListener>(); + private void waitForReady() { + while (mReady == false) { + for (int retries = 5; retries > 0; retries--) { + if (mReady) { + return; + } + SystemClock.sleep(1000); + } + Log.w(TAG, "Waiting too long for mReady!"); + } } - BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { - /* - * Vold does not run in the simulator, so fake out a mounted - * event to trigger MediaScanner - */ - if ("simulator".equals(SystemProperties.get("ro.product.device"))) { - updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED); - return; - } + mBooted = true; - Thread thread = new Thread( - mConnector, NativeDaemonConnector.class.getName()); - thread.start(); + String path = Environment.getExternalStorageDirectory().getPath(); + if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) { + int rc = doMountVolume(path); + if (rc != StorageResultCode.OperationSucceeded) { + Log.e(TAG, String.format("Boot-time mount failed (%d)", rc)); + } + } } } }; @@ -161,7 +161,7 @@ class MountService extends IMountService.Stub } public void binderDied() { - Log.d(TAG, "An IMountServiceListener has died!"); + if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!"); synchronized(mListeners) { mListeners.remove(this); mListener.asBinder().unlinkToDeath(this, 0); @@ -169,7 +169,7 @@ class MountService extends IMountService.Stub } } - int doShareUnshareVolume(String path, String method, boolean enable) { + private int doShareUnshareVolume(String path, String method, boolean enable) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); // TODO: Add support for multiple share methods @@ -182,9 +182,13 @@ class MountService extends IMountService.Stub */ String vs = getVolumeState(path); if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { - mUmsEnabling = enable; // Supress unmounted events - unmountVolume(path); - mUmsEnabling = false; // Unsupress unmounted events + mUmsEnabling = enable; // Override for isUsbMassStorageEnabled() + int rc = doUnmountVolume(path); + mUmsEnabling = false; // Clear override + if (rc != StorageResultCode.OperationSucceeded) { + Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc)); + return rc; + } } try { @@ -192,14 +196,14 @@ class MountService extends IMountService.Stub "volume %sshare %s %s", (enable ? "" : "un"), path, method)); } catch (NativeDaemonConnectorException e) { Log.e(TAG, "Failed to share/unshare", e); - return MountServiceResultCode.OperationFailedInternalError; + return StorageResultCode.OperationFailedInternalError; } /* * If we disabled UMS then mount the volume */ if (!enable) { - if (mountVolume(path) != MountServiceResultCode.OperationSucceeded) { + if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { Log.e(TAG, String.format( "Failed to remount %s after disabling share method %s", path, method)); /* @@ -210,15 +214,19 @@ class MountService extends IMountService.Stub } } - return MountServiceResultCode.OperationSucceeded; + return StorageResultCode.OperationSucceeded; } - void updatePublicVolumeState(String path, String state) { + private void updatePublicVolumeState(String path, String state) { if (!path.equals(Environment.getExternalStorageDirectory().getPath())) { Log.w(TAG, "Multiple volumes not currently supported"); return; } - Log.i(TAG, "State for {" + path + "} = {" + state + "}"); + + if (mLegacyState.equals(state)) { + Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state)); + return; + } String oldState = mLegacyState; mLegacyState = state; @@ -227,7 +235,7 @@ class MountService extends IMountService.Stub for (int i = mListeners.size() -1; i >= 0; i--) { MountServiceBinderListener bl = mListeners.get(i); try { - bl.mListener.onVolumeStateChanged("", path, oldState, state); + bl.mListener.onStorageStateChanged(path, oldState, state); } catch (RemoteException rex) { Log.e(TAG, "Listener dead"); mListeners.remove(i); @@ -270,11 +278,7 @@ class MountService extends IMountService.Stub if (st == VolumeState.NoMedia) { state = Environment.MEDIA_REMOVED; } else if (st == VolumeState.Idle) { - state = null; - int rc = mountVolume(path); - if (rc != MountServiceResultCode.OperationSucceeded) { - Log.e(TAG, String.format("Connection-mount failed (%d)", rc)); - } + state = Environment.MEDIA_UNMOUNTED; } else if (st == VolumeState.Mounted) { state = Environment.MEDIA_MOUNTED; Log.i(TAG, "Media already mounted on daemon connection"); @@ -294,23 +298,26 @@ class MountService extends IMountService.Stub } try { - boolean avail = getShareMethodAvailable("ums"); + boolean avail = doGetShareMethodAvailable("ums"); notifyShareAvailabilityChange("ums", avail); } catch (Exception ex) { Log.w(TAG, "Failed to get share availability"); } + /* + * Now that we've done our initialization, release + * the hounds! + */ + mReady = true; } }.start(); } /** - * * Callback from NativeDaemonConnector */ public boolean onEvent(int code, String raw, String[] cooked) { Intent in = null; - // Log.d(TAG, "event {" + raw + "}"); if (code == VoldResponseCode.VolumeStateChange) { /* * One of the volumes we're managing has changed state. @@ -347,34 +354,12 @@ class MountService extends IMountService.Stub Log.e(TAG, "Failed to parse major/minor", ex); } - synchronized (mListeners) { - for (int i = mListeners.size() -1; i >= 0; i--) { - MountServiceBinderListener bl = mListeners.get(i); - try { - if (code == VoldResponseCode.VolumeDiskInserted) { - bl.mListener.onMediaInserted(label, path, major, minor); - } else if (code == VoldResponseCode.VolumeDiskRemoved) { - bl.mListener.onMediaRemoved(label, path, major, minor, true); - } else if (code == VoldResponseCode.VolumeBadRemoval) { - bl.mListener.onMediaRemoved(label, path, major, minor, false); - } else { - Log.e(TAG, String.format("Unknown code {%d}", code)); - } - } catch (RemoteException rex) { - Log.e(TAG, "Listener dead"); - mListeners.remove(i); - } catch (Exception ex) { - Log.e(TAG, "Listener failed", ex); - } - } - } - if (code == VoldResponseCode.VolumeDiskInserted) { new Thread() { public void run() { try { int rc; - if ((rc = mountVolume(path)) != MountServiceResultCode.OperationSucceeded) { + if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { Log.w(TAG, String.format("Insertion mount failed (%d)", rc)); } } catch (Exception ex) { @@ -417,7 +402,7 @@ class MountService extends IMountService.Stub return true; } - void notifyVolumeStateChange(String label, String path, int oldState, int newState) { + private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { String vs = getVolumeState(path); Intent in = null; @@ -471,7 +456,144 @@ class MountService extends IMountService.Stub } } - void notifyShareAvailabilityChange(String method, final boolean avail) { + private boolean doGetShareMethodAvailable(String method) { + ArrayList<String> rsp = mConnector.doCommand("share status " + method); + + for (String line : rsp) { + String []tok = line.split(" "); + int code; + try { + code = Integer.parseInt(tok[0]); + } catch (NumberFormatException nfe) { + Log.e(TAG, String.format("Error parsing code %s", tok[0])); + return false; + } + if (code == VoldResponseCode.ShareStatusResult) { + if (tok[2].equals("available")) + return true; + return false; + } else { + Log.e(TAG, String.format("Unexpected response code %d", code)); + return false; + } + } + Log.e(TAG, "Got an empty response"); + return false; + } + + private int doMountVolume(String path) { + int rc = StorageResultCode.OperationSucceeded; + + try { + mConnector.doCommand(String.format("volume mount %s", path)); + } catch (NativeDaemonConnectorException e) { + /* + * Mount failed for some reason + */ + Intent in = null; + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedNoMedia) { + /* + * Attempt to mount but no media inserted + */ + rc = StorageResultCode.OperationFailedNoMedia; + } else if (code == VoldResponseCode.OpFailedMediaBlank) { + /* + * Media is blank or does not contain a supported filesystem + */ + updatePublicVolumeState(path, Environment.MEDIA_NOFS); + in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); + rc = StorageResultCode.OperationFailedMediaBlank; + } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { + /* + * Volume consistency check failed + */ + updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); + in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); + rc = StorageResultCode.OperationFailedMediaCorrupt; + } else { + rc = StorageResultCode.OperationFailedInternalError; + } + + /* + * Send broadcast intent (if required for the failure) + */ + if (in != null) { + mContext.sendBroadcast(in); + } + } + + return rc; + } + + private int doUnmountVolume(String path) { + if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { + return VoldResponseCode.OpFailedVolNotMounted; + } + + // Notify PackageManager of potential media removal and deal with + // return code later on. The caller of this api should be aware or have been + // notified that the applications installed on the media will be killed. + mPms.updateExternalMediaStatus(false); + try { + mConnector.doCommand(String.format("volume unmount %s", path)); + return StorageResultCode.OperationSucceeded; + } catch (NativeDaemonConnectorException e) { + // Don't worry about mismatch in PackageManager since the + // call back will handle the status changes any way. + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedVolNotMounted) { + return StorageResultCode.OperationFailedVolumeNotMounted; + } else { + return StorageResultCode.OperationFailedInternalError; + } + } + } + + private int doFormatVolume(String path) { + try { + String cmd = String.format("volume format %s", path); + mConnector.doCommand(cmd); + return StorageResultCode.OperationSucceeded; + } catch (NativeDaemonConnectorException e) { + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedNoMedia) { + return StorageResultCode.OperationFailedNoMedia; + } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { + return StorageResultCode.OperationFailedMediaCorrupt; + } else { + return StorageResultCode.OperationFailedInternalError; + } + } + } + + private boolean doGetVolumeShared(String path, String method) { + String cmd = String.format("volume shared %s %s", path, method); + ArrayList<String> rsp = mConnector.doCommand(cmd); + + for (String line : rsp) { + String []tok = line.split(" "); + int code; + try { + code = Integer.parseInt(tok[0]); + } catch (NumberFormatException nfe) { + Log.e(TAG, String.format("Error parsing code %s", tok[0])); + return false; + } + if (code == VoldResponseCode.ShareEnabledResult) { + if (tok[2].equals("enabled")) + return true; + return false; + } else { + Log.e(TAG, String.format("Unexpected response code %d", code)); + return false; + } + } + Log.e(TAG, "Got an empty response"); + return false; + } + + private void notifyShareAvailabilityChange(String method, final boolean avail) { if (!method.equals("ums")) { Log.w(TAG, "Ignoring unsupported share method {" + method + "}"); return; @@ -481,7 +603,7 @@ class MountService extends IMountService.Stub for (int i = mListeners.size() -1; i >= 0; i--) { MountServiceBinderListener bl = mListeners.get(i); try { - bl.mListener.onShareAvailabilityChanged(method, avail); + bl.mListener.onUsbMassStorageConnectionChanged(avail); } catch (RemoteException rex) { Log.e(TAG, "Listener dead"); mListeners.remove(i); @@ -491,22 +613,55 @@ class MountService extends IMountService.Stub } } - Intent intent; - if (avail) { - intent = new Intent(Intent.ACTION_UMS_CONNECTED); - } else { - intent = new Intent(Intent.ACTION_UMS_DISCONNECTED); + if (mBooted == true) { + Intent intent; + if (avail) { + intent = new Intent(Intent.ACTION_UMS_CONNECTED); + } else { + intent = new Intent(Intent.ACTION_UMS_DISCONNECTED); + } + mContext.sendBroadcast(intent); } - mContext.sendBroadcast(intent); } - void validatePermission(String perm) { + private void validatePermission(String perm) { if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException(String.format("Requires %s permission", perm)); } } /** + * Constructs a new MountService instance + * + * @param context Binder context for this service + */ + public MountService(Context context) { + mContext = context; + + /* + * Vold does not run in the simulator, so fake out a mounted + * event to trigger MediaScanner + */ + if ("simulator".equals(SystemProperties.get("ro.product.device"))) { + updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED); + return; + } + + // XXX: This will go away soon in favor of IMountServiceObserver + mPms = (PackageManagerService) ServiceManager.getService("package"); + + mContext.registerReceiver(mBroadcastReceiver, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); + + mListeners = new ArrayList<MountServiceBinderListener>(); + + mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector"); + mReady = false; + Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName()); + thread.start(); + } + + /** * Exposed API calls below here */ @@ -549,7 +704,7 @@ class MountService extends IMountService.Stub * the UMS host could have dirty FAT cache entries * yet to flush. */ - if (unshareVolume(path, "ums") != MountServiceResultCode.OperationSucceeded) { + if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) { Log.e(TAG, "UMS disable on shutdown failed"); } } else if (state.equals(Environment.MEDIA_CHECKING)) { @@ -577,75 +732,30 @@ class MountService extends IMountService.Stub /* * If the media is mounted, then gracefully unmount it. */ - if (unmountVolume(path) != MountServiceResultCode.OperationSucceeded) { + if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to unmount media for shutdown"); } } } - public String[] getShareMethodList() { - String[] rdata = new String[1]; - rdata[0] = "ums"; - return rdata; - } + public boolean isUsbMassStorageConnected() { + waitForReady(); - public boolean getShareMethodAvailable(String method) { - ArrayList<String> rsp = mConnector.doCommand("share status " + method); - - for (String line : rsp) { - String []tok = line.split(" "); - int code; - try { - code = Integer.parseInt(tok[0]); - } catch (NumberFormatException nfe) { - Log.e(TAG, String.format("Error parsing code %s", tok[0])); - return false; - } - if (code == VoldResponseCode.ShareStatusResult) { - if (tok[2].equals("available")) - return true; - return false; - } else { - Log.e(TAG, String.format("Unexpected response code %d", code)); - return false; - } + if (mUmsEnabling) { + return true; } - Log.e(TAG, "Got an empty response"); - return false; + return doGetShareMethodAvailable("ums"); } - public int shareVolume(String path, String method) { - return doShareUnshareVolume(path, method, true); - } + public int setUsbMassStorageEnabled(boolean enable) { + waitForReady(); - public int unshareVolume(String path, String method) { - return doShareUnshareVolume(path, method, false); + return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable); } - public boolean getVolumeShared(String path, String method) { - String cmd = String.format("volume shared %s %s", path, method); - ArrayList<String> rsp = mConnector.doCommand(cmd); - - for (String line : rsp) { - String []tok = line.split(" "); - int code; - try { - code = Integer.parseInt(tok[0]); - } catch (NumberFormatException nfe) { - Log.e(TAG, String.format("Error parsing code %s", tok[0])); - return false; - } - if (code == VoldResponseCode.ShareEnabledResult) { - if (tok[2].equals("enabled")) - return true; - return false; - } else { - Log.e(TAG, String.format("Unexpected response code %d", code)); - return false; - } - } - Log.e(TAG, "Got an empty response"); - return false; + public boolean isUsbMassStorageEnabled() { + waitForReady(); + return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); } /** @@ -664,103 +774,38 @@ class MountService extends IMountService.Stub return mLegacyState; } - - /** - * Attempt to mount external media - */ public int mountVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); - int rc = MountServiceResultCode.OperationSucceeded; - - try { - mConnector.doCommand(String.format("volume mount %s", path)); - } catch (NativeDaemonConnectorException e) { - /* - * Mount failed for some reason - */ - Intent in = null; - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedNoMedia) { - /* - * Attempt to mount but no media inserted - */ - rc = MountServiceResultCode.OperationFailedNoMedia; - } else if (code == VoldResponseCode.OpFailedMediaBlank) { - /* - * Media is blank or does not contain a supported filesystem - */ - updatePublicVolumeState(path, Environment.MEDIA_NOFS); - in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); - rc = MountServiceResultCode.OperationFailedMediaBlank; - } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { - /* - * Volume consistency check failed - */ - updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); - in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); - rc = MountServiceResultCode.OperationFailedMediaCorrupt; - } else { - rc = MountServiceResultCode.OperationFailedInternalError; - } - - /* - * Send broadcast intent (if required for the failure) - */ - if (in != null) { - mContext.sendBroadcast(in); - } - } - - return rc; + waitForReady(); + return doMountVolume(path); } - /** - * Attempt to unmount external media to prepare for eject - */ public int unmountVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + waitForReady(); - try { - mConnector.doCommand(String.format("volume unmount %s", path)); - return MountServiceResultCode.OperationSucceeded; - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedVolNotMounted) { - return MountServiceResultCode.OperationFailedVolumeNotMounted; - } else { - return MountServiceResultCode.OperationFailedInternalError; - } - } + return doUnmountVolume(path); } - /** - * Synchronously formats a volume - * - * @param path The volume path to format - * @return Error code from MountServiceResultCode - */ public int formatVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); + waitForReady(); - try { - String cmd = String.format("volume format %s", path); - mConnector.doCommand(cmd); - return MountServiceResultCode.OperationSucceeded; - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedNoMedia) { - return MountServiceResultCode.OperationFailedNoMedia; - } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { - return MountServiceResultCode.OperationFailedMediaCorrupt; - } else { - return MountServiceResultCode.OperationFailedInternalError; - } + return doFormatVolume(path); + } + + private void warnOnNotMounted() { + if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + Log.w(TAG, "getSecureContainerList() called when storage not mounted"); } } public String[] getSecureContainerList() { validatePermission(android.Manifest.permission.ASEC_ACCESS); + waitForReady(); + warnOnNotMounted(); + try { return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult); } catch (NativeDaemonConnectorException e) { @@ -771,82 +816,124 @@ class MountService extends IMountService.Stub public int createSecureContainer(String id, int sizeMb, String fstype, String key, int ownerUid) { validatePermission(android.Manifest.permission.ASEC_CREATE); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public int finalizeSecureContainer(String id) { validatePermission(android.Manifest.permission.ASEC_CREATE); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; try { mConnector.doCommand(String.format("asec finalize %s", id)); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public int destroySecureContainer(String id) { validatePermission(android.Manifest.permission.ASEC_DESTROY); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; try { mConnector.doCommand(String.format("asec destroy %s", id)); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public int mountSecureContainer(String id, String key, int ownerUid) { validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec mount %s %s %d", id, key, ownerUid); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; + } + + if (rc == StorageResultCode.OperationSucceeded) { + synchronized (mAsecMountSet) { + mAsecMountSet.add(id); + } } return rc; } public int unmountSecureContainer(String id) { validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); + waitForReady(); + warnOnNotMounted(); + + synchronized (mAsecMountSet) { + if (!mAsecMountSet.contains(id)) { + return StorageResultCode.OperationFailedVolumeNotMounted; + } + } - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec unmount %s", id); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; + } + + if (rc == StorageResultCode.OperationSucceeded) { + synchronized (mAsecMountSet) { + mAsecMountSet.remove(id); + } } return rc; } + public boolean isSecureContainerMounted(String id) { + validatePermission(android.Manifest.permission.ASEC_ACCESS); + waitForReady(); + warnOnNotMounted(); + + synchronized (mAsecMountSet) { + return mAsecMountSet.contains(id); + } + } + public int renameSecureContainer(String oldId, String newId) { validatePermission(android.Manifest.permission.ASEC_RENAME); + waitForReady(); + warnOnNotMounted(); - int rc = MountServiceResultCode.OperationSucceeded; + int rc = StorageResultCode.OperationSucceeded; String cmd = String.format("asec rename %s %s", oldId, newId); try { mConnector.doCommand(cmd); } catch (NativeDaemonConnectorException e) { - rc = MountServiceResultCode.OperationFailedInternalError; + rc = StorageResultCode.OperationFailedInternalError; } return rc; } public String getSecureContainerPath(String id) { validatePermission(android.Manifest.permission.ASEC_ACCESS); + waitForReady(); + warnOnNotMounted(); + ArrayList<String> rsp = mConnector.doCommand("asec path " + id); for (String line : rsp) { |