am 38cf8867: Remove OBBs from state list when volume unmounted

Merge commit '38cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94' into gingerbread-plus-aosp

* commit '38cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94':
  Remove OBBs from state list when volume unmounted
This commit is contained in:
Kenny Root
2010-09-30 17:30:22 -07:00
committed by Android Git Automerger
5 changed files with 255 additions and 68 deletions

View File

@@ -52732,6 +52732,16 @@
visibility="public"
>
</field>
<field name="filename"
type="java.lang.String"
transient="false"
volatile="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="flags"
type="int"
transient="false"
@@ -130946,8 +130956,6 @@
</parameter>
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
</class>
</package>

View File

@@ -28,6 +28,11 @@ public class ObbInfo implements Parcelable {
/** Flag noting that this OBB is an overlay patch for a base OBB. */
public static final int OBB_OVERLAY = 1 << 0;
/**
* The canonical filename of the OBB.
*/
public String filename;
/**
* The name of the package to which the OBB file belongs.
*/
@@ -66,6 +71,7 @@ public class ObbInfo implements Parcelable {
}
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(filename);
dest.writeString(packageName);
dest.writeInt(version);
dest.writeInt(flags);
@@ -83,6 +89,7 @@ public class ObbInfo implements Parcelable {
};
private ObbInfo(Parcel source) {
filename = source.readString();
packageName = source.readString();
version = source.readInt();
flags = source.readInt();

View File

@@ -45,9 +45,14 @@ public class ObbScanner {
throw new IllegalArgumentException("OBB file does not exist: " + filePath);
}
/*
* XXX This will fail to find the real canonical path if bind mounts are
* used, but we don't use any bind mounts right now.
*/
final String canonicalFilePath = obbFile.getCanonicalPath();
ObbInfo obbInfo = new ObbInfo();
obbInfo.filename = canonicalFilePath;
getObbInfo_native(canonicalFilePath, obbInfo);
return obbInfo;

View File

@@ -434,7 +434,6 @@ public class StorageManager
* @param key secret used to encrypt the OBB; may be <code>null</code> if no
* encryption was used on the OBB.
* @return whether the mount call was successfully queued or not
* @throws IllegalArgumentException when the OBB is already mounted
*/
public boolean mountObb(String filename, String key, OnObbStateChangeListener listener) {
try {
@@ -468,10 +467,8 @@ public class StorageManager
* @param force whether to kill any programs using this in order to unmount
* it
* @return whether the unmount call was successfully queued or not
* @throws IllegalArgumentException when OBB is not already mounted
*/
public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener)
throws IllegalArgumentException {
public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener) {
try {
mObbActionListener.addListener(listener);
mMountService.unmountObb(filename, force, mObbActionListener);

View File

@@ -46,13 +46,18 @@ import android.os.storage.IObbActionListener;
import android.os.storage.StorageResultCode;
import android.util.Slog;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* MountService implements back-end services for platform storage
@@ -181,6 +186,22 @@ class MountService extends IMountService.Stub
token.asBinder().unlinkToDeath(this, 0);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ObbState{");
sb.append("filename=");
sb.append(filename);
sb.append(",token=");
sb.append(token.toString());
sb.append(",callerUid=");
sb.append(callerUid);
sb.append(",mounted=");
sb.append(mounted);
sb.append('}');
return sb.toString();
}
}
// OBB Action Handler
@@ -475,6 +496,34 @@ class MountService extends IMountService.Stub
} else if (Environment.MEDIA_MOUNTED.equals(state)) {
mPms.updateExternalMediaStatus(true, false);
}
// Remove all OBB mappings and listeners from this path
synchronized (mObbMounts) {
final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
final Iterator<Entry<String, ObbState>> i = mObbPathToStateMap.entrySet().iterator();
while (i.hasNext()) {
final Entry<String, ObbState> obbEntry = i.next();
// If this entry's source file is in the volume path that got
// unmounted, remove it because it's no longer valid.
if (obbEntry.getKey().startsWith(path)) {
obbStatesToRemove.add(obbEntry.getValue());
}
}
for (final ObbState obbState : obbStatesToRemove) {
removeObbState(obbState);
try {
obbState.token.onObbResult(obbState.filename, Environment.MEDIA_UNMOUNTED);
} catch (RemoteException e) {
Slog.i(TAG, "Couldn't send unmount notification for OBB: "
+ obbState.filename);
}
}
}
String oldState = mLegacyState;
mLegacyState = state;
@@ -1494,8 +1543,14 @@ class MountService extends IMountService.Stub
public boolean isObbMounted(String filename) {
synchronized (mObbMounts) {
return mObbPathToStateMap.containsKey(filename);
final ObbState obbState = mObbPathToStateMap.get(filename);
if (obbState != null) {
synchronized (obbState) {
return obbState.mounted;
}
}
}
return false;
}
public void mountObb(String filename, String key, IObbActionListener token) {
@@ -1512,7 +1567,12 @@ class MountService extends IMountService.Stub
synchronized (mObbMounts) {
if (isObbMounted(filename)) {
throw new IllegalArgumentException("OBB file is already mounted");
try {
token.onObbResult(filename, Environment.MEDIA_MOUNTED);
} catch (RemoteException e) {
Slog.d(TAG, "Could not send unmount notification for: " + filename);
}
return;
}
final int callerUid = Binder.getCallingUid();
@@ -1526,7 +1586,7 @@ class MountService extends IMountService.Stub
Slog.e(TAG, "Failed to link to listener death");
}
MountObbAction action = new MountObbAction(obbState, key);
ObbAction action = new MountObbAction(obbState, key);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
if (DEBUG_OBB)
@@ -1544,8 +1604,14 @@ class MountService extends IMountService.Stub
synchronized (mObbMounts) {
if (!isObbMounted(filename)) {
throw new IllegalArgumentException("OBB is not mounted");
try {
token.onObbResult(filename, Environment.MEDIA_UNMOUNTED);
} catch (RemoteException e) {
Slog.d(TAG, "Could not send unmount notification for: " + filename);
}
return;
}
obbState = mObbPathToStateMap.get(filename);
if (Binder.getCallingUid() != obbState.callerUid) {
@@ -1555,7 +1621,7 @@ class MountService extends IMountService.Stub
}
}
UnmountObbAction action = new UnmountObbAction(obbState, force);
ObbAction action = new UnmountObbAction(obbState, force);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
if (DEBUG_OBB)
@@ -1587,6 +1653,13 @@ class MountService extends IMountService.Stub
}
}
private void replaceObbState(ObbState oldObbState, ObbState newObbState) {
synchronized (mObbMounts) {
removeObbState(oldObbState);
addObbState(newObbState);
}
}
private class ObbActionHandler extends Handler {
private boolean mBound = false;
private List<ObbAction> mActions = new LinkedList<ObbAction>();
@@ -1760,6 +1833,29 @@ class MountService extends IMountService.Stub
abstract void handleExecute() throws RemoteException, IOException;
abstract void handleError();
protected ObbInfo getObbInfo() throws IOException {
ObbInfo obbInfo;
try {
obbInfo = mContainerService.getObbInfo(mObbState.filename);
} catch (RemoteException e) {
Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
+ mObbState.filename);
obbInfo = null;
}
if (obbInfo == null) {
throw new IOException("Couldn't read OBB file: " + mObbState.filename);
}
return obbInfo;
}
protected void sendNewStatusOrIgnore(String filename, String status) {
try {
mObbState.token.onObbResult(filename, status);
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
}
}
class MountObbAction extends ObbAction {
@@ -1770,10 +1866,42 @@ class MountService extends IMountService.Stub
mKey = key;
}
public void handleExecute() throws RemoteException, IOException {
final ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
if (obbInfo == null) {
throw new IOException("Couldn't read OBB file: " + mObbState.filename);
public void handleExecute() throws IOException {
final ObbInfo obbInfo = getObbInfo();
/*
* If someone tried to trick us with some weird characters, rectify
* it here.
*/
if (!mObbState.filename.equals(obbInfo.filename)) {
if (DEBUG_OBB)
Slog.i(TAG, "OBB filename " + mObbState.filename + " is actually "
+ obbInfo.filename);
synchronized (mObbMounts) {
/*
* If the real filename is already mounted, discard this
* state and notify the caller that the OBB is already
* mounted.
*/
if (isObbMounted(obbInfo.filename)) {
if (DEBUG_OBB)
Slog.i(TAG, "OBB already mounted as " + obbInfo.filename);
removeObbState(mObbState);
sendNewStatusOrIgnore(obbInfo.filename, Environment.MEDIA_MOUNTED);
return;
}
/*
* It's not already mounted, so we have to replace the state
* with the state containing the actual filename.
*/
ObbState newObbState = new ObbState(obbInfo.filename, mObbState.token,
mObbState.callerUid);
replaceObbState(mObbState, newObbState);
mObbState = newObbState;
}
}
if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
@@ -1784,42 +1912,47 @@ class MountService extends IMountService.Stub
mKey = "none";
}
int rc = StorageResultCode.OperationSucceeded;
String cmd = String.format("obb mount %s %s %d", mObbState.filename, mKey,
mObbState.callerUid);
try {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code != VoldResponseCode.OpFailedStorageBusy) {
rc = StorageResultCode.OperationFailedInternalError;
boolean mounted = false;
int rc;
synchronized (mObbState) {
if (mObbState.mounted) {
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED);
return;
}
rc = StorageResultCode.OperationSucceeded;
String cmd = String.format("obb mount %s %s %d", mObbState.filename, mKey,
mObbState.callerUid);
try {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code != VoldResponseCode.OpFailedStorageBusy) {
rc = StorageResultCode.OperationFailedInternalError;
}
}
if (rc == StorageResultCode.OperationSucceeded) {
mObbState.mounted = mounted = true;
}
}
if (rc == StorageResultCode.OperationSucceeded) {
try {
mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_MOUNTED);
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
if (mounted) {
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED);
} else {
Slog.e(TAG, "Couldn't mount OBB file: " + rc);
// We didn't succeed, so remove this from the mount-set.
removeObbState(mObbState);
mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED);
}
}
public void handleError() {
removeObbState(mObbState);
try {
mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
} catch (RemoteException e) {
Slog.e(TAG, "Couldn't send back OBB mount error for " + mObbState.filename);
}
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
}
@Override
@@ -1845,51 +1978,66 @@ class MountService extends IMountService.Stub
mForceUnmount = force;
}
public void handleExecute() throws RemoteException, IOException {
final ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
if (obbInfo == null) {
throw new IOException("Couldn't read OBB file: " + mObbState.filename);
}
public void handleExecute() throws IOException {
final ObbInfo obbInfo = getObbInfo();
int rc = StorageResultCode.OperationSucceeded;
String cmd = String.format("obb unmount %s%s", mObbState.filename,
(mForceUnmount ? " force" : ""));
try {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code == VoldResponseCode.OpFailedStorageBusy) {
rc = StorageResultCode.OperationFailedStorageBusy;
} else {
rc = StorageResultCode.OperationFailedInternalError;
/*
* If someone tried to trick us with some weird characters, rectify
* it here.
*/
synchronized (mObbMounts) {
if (!isObbMounted(obbInfo.filename)) {
removeObbState(mObbState);
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED);
return;
}
if (!mObbState.filename.equals(obbInfo.filename)) {
removeObbState(mObbState);
mObbState = mObbPathToStateMap.get(obbInfo.filename);
}
}
if (rc == StorageResultCode.OperationSucceeded) {
boolean unmounted = false;
synchronized (mObbState) {
if (!mObbState.mounted) {
sendNewStatusOrIgnore(obbInfo.filename, Environment.MEDIA_UNMOUNTED);
return;
}
int rc = StorageResultCode.OperationSucceeded;
String cmd = String.format("obb unmount %s%s", mObbState.filename,
(mForceUnmount ? " force" : ""));
try {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code == VoldResponseCode.OpFailedStorageBusy) {
rc = StorageResultCode.OperationFailedStorageBusy;
} else {
rc = StorageResultCode.OperationFailedInternalError;
}
}
if (rc == StorageResultCode.OperationSucceeded) {
mObbState.mounted = false;
unmounted = true;
}
}
if (unmounted) {
removeObbState(mObbState);
try {
mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_UNMOUNTED);
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED);
} else {
try {
mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED);
}
}
public void handleError() {
removeObbState(mObbState);
try {
mObbState.token.onObbResult(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
} catch (RemoteException e) {
Slog.e(TAG, "Couldn't send back OBB unmount error for " + mObbState.filename);
}
sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_BAD_REMOVAL);
}
@Override
@@ -1908,5 +2056,27 @@ class MountService extends IMountService.Stub
return sb.toString();
}
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump ActivityManager from from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ " without permission " + android.Manifest.permission.DUMP);
return;
}
pw.println(" mObbMounts:");
synchronized (mObbMounts) {
final Collection<List<ObbState>> obbStateLists = mObbMounts.values();
for (final List<ObbState> obbStates : obbStateLists) {
for (final ObbState obbState : obbStates) {
pw.print(" "); pw.println(obbState.toString());
}
}
}
}
}