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:
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user