Skip to content

Commit

Permalink
Allow mounting of multiple volumes via mass storage (framework part)
Browse files Browse the repository at this point in the history
(cherry-picked from CM10)

The volumes to mount is taken from storage_list.xml (allowMassStorage)
rather than ro.additionalmounts in CM7.

Hand ported from the following patches:

commit 0233209
Author: Tony Layher <layhertony@gmail.com>
Date:   Sun Jan 2 12:46:38 2011 -0500

    forward port of 93bb959 to allow mounting and sharing of mulitple volumes to MountService.

    Change-Id: I9fa3994e6e7b85360b451f57c1cdd4df921bc035

(the second part of the above patch was not ported)

commit 678fadf
Author: Josh Stone <cuviper@gmail.com>
Date:   Sun Nov 7 13:38:58 2010 -0800

    MountService: Remount all volumes after USB disconnect

    If USB was removed while UMS was enabled, the MountService was only
    remounting the primary share.  Any other shares, like the HTC Inc's
    emmc, were left in limbo.  This patch now iterates over *all* shared
    volumes to remount after disconnect.

    Change-Id: Ie6fd49ad80ba6fa0e4e194a386549cac786b4bbe
    Signed-off-by: Josh Stone <cuviper@gmail.com>

commit b1da9ed
Author: Josh Stone <cuviper@gmail.com>
Date:   Sat Jan 22 12:03:53 2011 -0800

    MountService: Only notify PackageManager for true ASEC changes

    MountService can be dealing with multiple mounts (emmc, sdcard), but
    only the EXTERNAL_STORAGE has any ASEC mounts on it.  Since the PMS
    updateExternalMediaStatus doesn't specify the path, we need to make sure
    it's only called for the real ASEC mount.  Otherwise we get into nasty
    race conditions when multiple mounts are coming and going, like during
    UMS transitions, and sdcard-installed apps tend to break.

    Change-Id: I85c6a601e84afd30b44270b0892686c2d864ce8d

commit c8c58f3
Author: Josh Stone <cuviper@gmail.com>
Date:   Sun Mar 6 12:34:50 2011 -0800

    MountService: Unmount secondary volumes more carefully

    Use the same message handler for unmounting both the ASEC external-
    storage path and any secondary paths like emmc.  This seems to help with
    additional race conditions encountered on Inc.

    Change-Id: Icca71756fa6721bd85da1f35b8b8c7fc7caa1eb1

commit 47495ab
Author: atinm <atinm.dev@gmail.com>
Date:   Sun Apr 10 14:50:41 2011 -0400

    Allow multiple shareable SD Cards by using getShareableVolumes()
    to get all the volumes that are shareable and allowing
    sharing/unsharing for all of them rather than just the hardcoded
    getExternalStorage calls.

    Unmount immediately if PM is not updating and not an ASEC
    mount. Change from Josh Stone.
    Change-Id: Iaf1a7a4484deac373e1c1d7bf16d5f22ca49fd64

    Only allow package manager for sdcard (packages aren't on
    external card).

    Change-Id: I0d148ea52dc1285905a9dd061d1ceedcfb761b52

    Take out extra logging.

    Change-Id: I6beb007700ef4be04c3eb273bbf2069c87b30011

Change-Id: I5ea83afeda6cdaf63dd15857b3827bb00afbd6d2
  • Loading branch information
pawitp authored and Gerrit Code Review committed Nov 27, 2012
1 parent 416d7cb commit f75dcfe
Showing 1 changed file with 83 additions and 42 deletions.
125 changes: 83 additions & 42 deletions services/java/com/android/server/MountService.java
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,13 @@ public void handleMessage(Message msg) {
case H_UNMOUNT_PM_UPDATE: {
if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
if (!mUpdatingStatus && !isPrimaryStorage(ucb.path)) {
// If PM isn't already updating, and this isn't an ASEC
// mount, then go ahead and do the unmount immediately.
if (DEBUG_UNMOUNT) Slog.i(TAG, " skipping PackageManager for " + ucb.path);
ucb.handleFinished();
break;
}
mForceUnmounts.add(ucb);
if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
// Register only if needed.
Expand Down Expand Up @@ -1000,7 +1007,9 @@ private int doUnmountVolume(String path, boolean force, boolean removeEncryption
Runtime.getRuntime().gc();

// Redundant probably. But no harm in updating state again.
mPms.updateExternalMediaStatus(false, false);
if (isPrimaryStorage(path)) {
mPms.updateExternalMediaStatus(false, false);
}
try {
final Command cmd = new Command("volume", "unmount", path);
if (removeEncryption) {
Expand Down Expand Up @@ -1082,10 +1091,13 @@ private void notifyShareAvailabilityChange(final boolean avail) {
mSendUmsConnectedOnBoot = avail;
}

final StorageVolume primary = getPrimaryPhysicalVolume();
if (avail == false && primary != null
&& Environment.MEDIA_SHARED.equals(getVolumeState(primary.getPath()))) {
final String path = primary.getPath();
final ArrayList<String> volumes = getShareableVolumes();
boolean mediaShared = false;
for (String path : volumes) {
if (getVolumeState(path).equals(Environment.MEDIA_SHARED))
mediaShared = true;
}
if (avail == false && mediaShared) {
/*
* USB mass storage disconnected while enabled
*/
Expand All @@ -1095,11 +1107,15 @@ public void run() {
try {
int rc;
Slog.w(TAG, "Disabling UMS after cable disconnect");
doShareUnshareVolume(path, "ums", false);
if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
Slog.e(TAG, String.format(
"Failed to remount {%s} on UMS enabled-disconnect (%d)",
path, rc));
for (String path : volumes) {
if (getVolumeState(path).equals(Environment.MEDIA_SHARED)) {
doShareUnshareVolume(path, "ums", false);
if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
Slog.e(TAG, String.format(
"Failed to remount {%s} on UMS enabled-disconnect (%d)",
path, rc));
}
}
}
} catch (Exception ex) {
Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
Expand Down Expand Up @@ -1438,6 +1454,30 @@ public boolean isUsbMassStorageConnected() {
}
}

private boolean isPrimaryStorage(String path) {
synchronized (mVolumesLock) {
for (StorageVolume volume : mVolumes) {
if (volume.isPrimary() && volume.getPath().equals(path)) {
return true;
}
}
return false;
}
}

private ArrayList<String> getShareableVolumes() {
// Sharable volumes have android:allowMassStorage="true" in storage_list.xml
ArrayList<String> volumesToMount = new ArrayList<String>();
synchronized (mVolumesLock) {
for (StorageVolume v : mVolumes) {
if (v.allowMassStorage()) {
volumesToMount.add(v.getPath());
}
}
}
return volumesToMount;
}

public void setUsbMassStorageEnabled(boolean enable) {
waitForReady();
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Expand All @@ -1447,46 +1487,47 @@ public void setUsbMassStorageEnabled(boolean enable) {

// TODO: Add support for multiple share methods

/*
* If the volume is mounted and we're enabling then unmount it
*/
String path = primary.getPath();
String vs = getVolumeState(path);
String method = "ums";
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
// Override for isUsbMassStorageEnabled()
setUmsEnabling(enable);
UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
// Clear override
setUmsEnabling(false);
}
/*
* If we disabled UMS then mount the volume
*/
if (!enable) {
doShareUnshareVolume(path, method, enable);
if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
Slog.e(TAG, "Failed to remount " + path +
" after disabling share method " + method);
/*
* Even though the mount failed, the unshare didn't so don't indicate an error.
* The mountVolume() call will have set the storage state and sent the necessary
* broadcasts.
*/
for (String path : getShareableVolumes()) {
/*
* If the volume is mounted and we're enabling then unmount it
*/
String vs = getVolumeState(path);
String method = "ums";
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
// Override for isUsbMassStorageEnabled()
setUmsEnabling(enable);
UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
// Clear override
setUmsEnabling(false);
}
/*
* If we disabled UMS then mount the volume
*/
if (!enable) {
doShareUnshareVolume(path, method, enable);
if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
Slog.e(TAG, "Failed to remount " + path +
" after disabling share method " + method);
/*
* Even though the mount failed, the unshare didn't so don't indicate an error.
* The mountVolume() call will have set the storage state and sent the necessary
* broadcasts.
*/
}
}
}
}

public boolean isUsbMassStorageEnabled() {
waitForReady();

final StorageVolume primary = getPrimaryPhysicalVolume();
if (primary != null) {
return doGetVolumeShared(primary.getPath(), "ums");
} else {
return false;
for (String path : getShareableVolumes()) {
if (doGetVolumeShared(path, "ums"))
return true;
}
// no volume is shared
return false;
}

/**
Expand Down

0 comments on commit f75dcfe

Please sign in to comment.