Merge "Move OBB file reading to DefaultContainerService" into gingerbread

This commit is contained in:
Kenny Root
2010-08-11 14:06:39 -07:00
committed by Android (Google) Code Review
8 changed files with 572 additions and 112 deletions

View File

@ -121,6 +121,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/storage/IMountService.aidl \
core/java/android/os/storage/IMountServiceListener.aidl \
core/java/android/os/storage/IMountShutdownObserver.aidl \
core/java/android/os/storage/IObbActionListener.aidl \
core/java/android/os/INetworkManagementService.aidl \
core/java/android/os/INetStatService.aidl \
core/java/android/os/IPermissionController.aidl \

View File

@ -129531,6 +129531,8 @@
>
<parameter name="filename" type="java.lang.String">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
<method name="mountObb"
return="boolean"
@ -129561,6 +129563,8 @@
</parameter>
<parameter name="force" type="boolean">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
</class>
</package>

View File

@ -19,6 +19,7 @@ package android.os.storage;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
import android.os.storage.IObbActionListener;
/** WARNING! Update IMountService.h and IMountService.cpp if you change this file.
* In particular, the ordering of the methods below must match the
@ -156,14 +157,20 @@ interface IMountService
/**
* Mounts an Opaque Binary Blob (OBB) with the specified decryption key and only
* allows the calling process's UID access to the contents.
*
* MountService will call back to the supplied IObbActionListener to inform
* it of the terminal state of the call.
*/
int mountObb(String filename, String key);
void mountObb(String filename, String key, IObbActionListener token);
/**
* Unmounts an Opaque Binary Blob (OBB). When the force flag is specified, any
* program using it will be forcibly killed to unmount the image.
*
* MountService will call back to the supplied IObbActionListener to inform
* it of the terminal state of the call.
*/
int unmountObb(String filename, boolean force);
void unmountObb(String filename, boolean force, IObbActionListener token);
/**
* Checks whether the specified Opaque Binary Blob (OBB) is mounted somewhere.

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os.storage;
/**
* Callback class for receiving events from MountService about
* Opaque Binary Blobs (OBBs).
*
* @hide - Applications should use android.os.storage.StorageManager
* to interact with OBBs.
*/
interface IObbActionListener {
/**
* Return from an OBB action result.
*
* @param filename the path to the OBB the operation was performed on
* @param returnCode status of the operation
*/
void onObbResult(String filename, String status);
}

View File

@ -16,28 +16,14 @@
package android.os.storage;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.Looper;
import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.util.Log;
import android.util.SparseArray;
import java.io.FileDescriptor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
/**
* StorageManager is the interface to the systems storage service.
@ -86,6 +72,17 @@ public class StorageManager
}
}
/**
* Binder listener for OBB action results.
*/
private final ObbActionBinderListener mObbActionListener = new ObbActionBinderListener();
private class ObbActionBinderListener extends IObbActionListener.Stub {
@Override
public void onObbResult(String filename, String status) throws RemoteException {
Log.i(TAG, "filename = " + filename + ", result = " + status);
}
}
/**
* Private base class for messages sent between the callback thread
* and the target looper handler.
@ -299,12 +296,23 @@ public class StorageManager
}
/**
* Mount an OBB file.
* Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
* specified, it is supplied to the mounting process to be used in any
* encryption used in the OBB.
* <p>
* <em>Note:</em> you can only mount OBB files for which the OBB tag on the
* file matches a package ID that is owned by the calling program's UID.
* That is, shared UID applications can obtain access to any other
* application's OBB that shares its UID.
*
* @param filename the path to the OBB file
* @param key decryption key
* @return whether the mount call was successfully queued or not
*/
public boolean mountObb(String filename, String key) {
try {
return mMountService.mountObb(filename, key)
== StorageResultCode.OperationSucceeded;
mMountService.mountObb(filename, key, mObbActionListener);
return true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to mount OBB", e);
}
@ -313,12 +321,24 @@ public class StorageManager
}
/**
* Mount an OBB file.
* Unmount an Opaque Binary Blob (OBB) file. If the <code>force</code> flag
* is true, it will kill any application needed to unmount the given OBB.
* <p>
* <em>Note:</em> you can only mount OBB files for which the OBB tag on the
* file matches a package ID that is owned by the calling program's UID.
* That is, shared UID applications can obtain access to any other
* application's OBB that shares its UID.
*
* @param filename path to the OBB file
* @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) {
public boolean unmountObb(String filename, boolean force) throws IllegalArgumentException {
try {
return mMountService.unmountObb(filename, force)
== StorageResultCode.OperationSucceeded;
mMountService.unmountObb(filename, force, mObbActionListener);
return true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to mount OBB", e);
}
@ -326,7 +346,13 @@ public class StorageManager
return false;
}
public boolean isObbMounted(String filename) {
/**
* Check whether an Opaque Binary Blob (OBB) is mounted or not.
*
* @param filename path to OBB image
* @return true if OBB is mounted; false if not mounted or on error
*/
public boolean isObbMounted(String filename) throws IllegalArgumentException {
try {
return mMountService.isObbMounted(filename);
} catch (RemoteException e) {
@ -337,13 +363,21 @@ public class StorageManager
}
/**
* Check the mounted path of an OBB file.
* Check the mounted path of an Opaque Binary Blob (OBB) file. This will
* give you the path to where you can obtain access to the internals of the
* OBB.
*
* @param filename path to OBB image
* @return absolute path to mounted OBB image data or <code>null</code> if
* not mounted or exception encountered trying to read status
*/
public String getMountedObbPath(String filename) {
try {
return mMountService.getMountedObbPath(filename);
} catch (RemoteException e) {
Log.e(TAG, "Failed to find mounted path for OBB", e);
} catch (IllegalArgumentException e) {
Log.d(TAG, "Couldn't read OBB file", e);
}
return null;

View File

@ -19,6 +19,7 @@ package com.android.internal.app;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.content.pm.PackageInfoLite;
import android.content.res.ObbInfo;
interface IMediaContainerService {
String copyResourceToContainer(in Uri packageURI,
@ -28,4 +29,5 @@ interface IMediaContainerService {
in ParcelFileDescriptor outStream);
PackageInfoLite getMinimalPackageInfo(in Uri fileUri, int flags);
boolean checkFreeStorage(boolean external, in Uri fileUri);
ObbInfo getObbInfo(String filename);
}

View File

@ -24,6 +24,8 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.res.ObbInfo;
import android.content.res.ObbScanner;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
@ -142,6 +144,10 @@ public class DefaultContainerService extends IntentService {
public boolean checkFreeStorage(boolean external, Uri fileUri) {
return checkFreeStorageInner(external, fileUri);
}
public ObbInfo getObbInfo(String filename) {
return ObbScanner.getObbInfo(filename);
}
};
public DefaultContainerService() {

View File

@ -16,34 +16,42 @@
package com.android.server;
import com.android.internal.app.IMediaContainerService;
import com.android.server.am.ActivityManagerService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.res.ObbInfo;
import android.content.res.ObbScanner;
import android.net.Uri;
import android.os.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
import android.os.storage.StorageResultCode;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
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.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;
import android.os.storage.IObbActionListener;
import android.os.storage.StorageResultCode;
import android.util.Slog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* MountService implements back-end services for platform storage
@ -135,9 +143,77 @@ class MountService extends IMountService.Stub
final private HashSet<String> mAsecMountSet = new HashSet<String>();
/**
* Private hash of currently mounted filesystem images.
* Mounted OBB tracking information. Used to track the current state of all
* OBBs.
*/
final private HashSet<String> mObbMountSet = new HashSet<String>();
final private Map<IObbActionListener, ObbState> mObbMounts = new HashMap<IObbActionListener, ObbState>();
final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
class ObbState implements IBinder.DeathRecipient {
public ObbState(String filename, IObbActionListener token, int callerUid) {
this.filename = filename;
this.token = token;
this.callerUid = callerUid;
mounted = false;
}
// OBB source filename
String filename;
// Token of remote Binder caller
IObbActionListener token;
// Binder.callingUid()
public int callerUid;
// Whether this is mounted currently.
boolean mounted;
@Override
public void binderDied() {
ObbAction action = new UnmountObbAction(this, true);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
removeObbState(this);
token.asBinder().unlinkToDeath(this, 0);
}
}
// OBB Action Handler
final private ObbActionHandler mObbActionHandler;
// OBB action handler messages
private static final int OBB_RUN_ACTION = 1;
private static final int OBB_MCS_BOUND = 2;
private static final int OBB_MCS_UNBIND = 3;
private static final int OBB_MCS_RECONNECT = 4;
private static final int OBB_MCS_GIVE_UP = 5;
/*
* Default Container Service information
*/
static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
"com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
class DefaultContainerConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG_OBB)
Slog.i(TAG, "onServiceConnected");
IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
}
public void onServiceDisconnected(ComponentName name) {
if (DEBUG_OBB)
Slog.i(TAG, "onServiceDisconnected");
}
};
// Used in the ObbActionHandler
private IMediaContainerService mContainerService = null;
// Handler messages
private static final int H_UNMOUNT_PM_UPDATE = 1;
@ -359,7 +435,7 @@ class MountService extends IMountService.Stub
public void binderDied() {
if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
synchronized(mListeners) {
synchronized (mListeners) {
mListeners.remove(this);
mListener.asBinder().unlinkToDeath(this, 0);
}
@ -904,6 +980,9 @@ class MountService extends IMountService.Stub
mHandlerThread.start();
mHandler = new MountServiceHandler(mHandlerThread.getLooper());
// Add OBB Action Handler to MountService thread.
mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
/*
* Vold does not run in the simulator, so pretend the connector thread
* ran and did its thing.
@ -1338,12 +1417,16 @@ class MountService extends IMountService.Stub
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
}
private boolean isCallerOwnerOfPackage(String packageName) {
private boolean isCallerOwnerOfPackageOrSystem(String packageName) {
final int callerUid = Binder.getCallingUid();
return isUidOwnerOfPackage(packageName, callerUid);
return isUidOwnerOfPackageOrSystem(packageName, callerUid);
}
private boolean isUidOwnerOfPackage(String packageName, int callerUid) {
private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
if (callerUid == android.os.Process.SYSTEM_UID) {
return true;
}
if (packageName == null) {
return false;
}
@ -1362,12 +1445,6 @@ class MountService extends IMountService.Stub
waitForReady();
warnOnNotMounted();
// XXX replace with call to IMediaContainerService
ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
if (!isCallerOwnerOfPackage(obbInfo.packageName)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
}
try {
ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename));
String []tok = rsp.get(0).split(" ");
@ -1379,7 +1456,7 @@ class MountService extends IMountService.Stub
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code == VoldResponseCode.OpFailedStorageNotFound) {
throw new IllegalArgumentException(String.format("OBB '%s' not found", filename));
return null;
} else {
throw new IllegalStateException(String.format("Unexpected response code %d", code));
}
@ -1387,95 +1464,390 @@ class MountService extends IMountService.Stub
}
public boolean isObbMounted(String filename) {
waitForReady();
warnOnNotMounted();
// XXX replace with call to IMediaContainerService
ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
if (!isCallerOwnerOfPackage(obbInfo.packageName)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
}
synchronized (mObbMountSet) {
return mObbMountSet.contains(filename);
synchronized (mObbMounts) {
return mObbPathToStateMap.containsKey(filename);
}
}
public int mountObb(String filename, String key) {
public void mountObb(String filename, String key, IObbActionListener token) {
waitForReady();
warnOnNotMounted();
synchronized (mObbMountSet) {
if (mObbMountSet.contains(filename)) {
return StorageResultCode.OperationFailedStorageMounted;
final ObbState obbState;
synchronized (mObbMounts) {
if (isObbMounted(filename)) {
throw new IllegalArgumentException("OBB file is already mounted");
}
if (mObbMounts.containsKey(token)) {
throw new IllegalArgumentException("You may only have one OBB mounted at a time");
}
final int callerUid = Binder.getCallingUid();
obbState = new ObbState(filename, token, callerUid);
addObbState(obbState);
}
final int callerUid = Binder.getCallingUid();
// XXX replace with call to IMediaContainerService
ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
if (!isUidOwnerOfPackage(obbInfo.packageName, callerUid)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
}
if (key == null) {
key = "none";
}
int rc = StorageResultCode.OperationSucceeded;
String cmd = String.format("obb mount %s %s %d", filename, key, callerUid);
try {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code != VoldResponseCode.OpFailedStorageBusy) {
rc = StorageResultCode.OperationFailedInternalError;
}
token.asBinder().linkToDeath(obbState, 0);
} catch (RemoteException rex) {
Slog.e(TAG, "Failed to link to listener death");
}
if (rc == StorageResultCode.OperationSucceeded) {
synchronized (mObbMountSet) {
mObbMountSet.add(filename);
}
}
return rc;
MountObbAction action = new MountObbAction(obbState, key);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
if (DEBUG_OBB)
Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
public int unmountObb(String filename, boolean force) {
waitForReady();
warnOnNotMounted();
public void unmountObb(String filename, boolean force, IObbActionListener token) {
final ObbState obbState;
ObbInfo obbInfo = ObbScanner.getObbInfo(filename);
if (!isCallerOwnerOfPackage(obbInfo.packageName)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
synchronized (mObbMounts) {
if (!isObbMounted(filename)) {
throw new IllegalArgumentException("OBB is not mounted");
}
obbState = mObbPathToStateMap.get(filename);
}
synchronized (mObbMountSet) {
if (!mObbMountSet.contains(filename)) {
return StorageResultCode.OperationFailedStorageNotMounted;
}
}
UnmountObbAction action = new UnmountObbAction(obbState, force);
mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
int rc = StorageResultCode.OperationSucceeded;
String cmd = String.format("obb unmount %s%s", filename, (force ? " force" : ""));
try {
mConnector.doCommand(cmd);
} catch (NativeDaemonConnectorException e) {
int code = e.getCode();
if (code == VoldResponseCode.OpFailedStorageBusy) {
rc = StorageResultCode.OperationFailedStorageBusy;
if (DEBUG_OBB)
Slog.i(TAG, "Send to OBB handler: " + action.toString());
}
private void addObbState(ObbState obbState) {
synchronized (mObbMounts) {
mObbMounts.put(obbState.token, obbState);
mObbPathToStateMap.put(obbState.filename, obbState);
}
}
private void removeObbState(ObbState obbState) {
synchronized (mObbMounts) {
mObbMounts.remove(obbState.token);
mObbPathToStateMap.remove(obbState.filename);
}
}
private class ObbActionHandler extends Handler {
private boolean mBound = false;
private List<ObbAction> mActions = new LinkedList<ObbAction>();
ObbActionHandler(Looper l) {
super(l);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case OBB_RUN_ACTION: {
ObbAction action = (ObbAction) msg.obj;
if (DEBUG_OBB)
Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
// If a bind was already initiated we don't really
// need to do anything. The pending install
// will be processed later on.
if (!mBound) {
// If this is the only one pending we might
// have to bind to the service again.
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
action.handleError();
return;
} else {
// Once we bind to the service, the first
// pending request will be processed.
mActions.add(action);
}
} else {
// Already bound to the service. Just make
// sure we trigger off processing the first request.
if (mActions.size() == 0) {
mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
}
mActions.add(action);
}
break;
}
case OBB_MCS_BOUND: {
if (DEBUG_OBB)
Slog.i(TAG, "OBB_MCS_BOUND");
if (msg.obj != null) {
mContainerService = (IMediaContainerService) msg.obj;
}
if (mContainerService == null) {
// Something seriously wrong. Bail out
Slog.e(TAG, "Cannot bind to media container service");
for (ObbAction action : mActions) {
// Indicate service bind error
action.handleError();
}
mActions.clear();
} else if (mActions.size() > 0) {
ObbAction action = mActions.get(0);
if (action != null) {
action.execute(this);
}
} else {
// Should never happen ideally.
Slog.w(TAG, "Empty queue");
}
break;
}
case OBB_MCS_RECONNECT: {
if (DEBUG_OBB)
Slog.i(TAG, "OBB_MCS_RECONNECT");
if (mActions.size() > 0) {
if (mBound) {
disconnectService();
}
if (!connectToService()) {
Slog.e(TAG, "Failed to bind to media container service");
for (ObbAction action : mActions) {
// Indicate service bind error
action.handleError();
}
mActions.clear();
}
}
break;
}
case OBB_MCS_UNBIND: {
if (DEBUG_OBB)
Slog.i(TAG, "OBB_MCS_UNBIND");
// Delete pending install
if (mActions.size() > 0) {
mActions.remove(0);
}
if (mActions.size() == 0) {
if (mBound) {
disconnectService();
}
} else {
// There are more pending requests in queue.
// Just post MCS_BOUND message to trigger processing
// of next pending install.
mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
}
break;
}
case OBB_MCS_GIVE_UP: {
if (DEBUG_OBB)
Slog.i(TAG, "OBB_MCS_GIVE_UP");
mActions.remove(0);
break;
}
}
}
private boolean connectToService() {
if (DEBUG_OBB)
Slog.i(TAG, "Trying to bind to DefaultContainerService");
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
mBound = true;
return true;
}
return false;
}
private void disconnectService() {
mContainerService = null;
mBound = false;
mContext.unbindService(mDefContainerConn);
}
}
abstract class ObbAction {
private static final int MAX_RETRIES = 3;
private int mRetries;
ObbState mObbState;
ObbAction(ObbState obbState) {
mObbState = obbState;
}
public void execute(ObbActionHandler handler) {
try {
if (DEBUG_OBB)
Slog.i(TAG, "Starting to execute action: " + this.toString());
mRetries++;
if (mRetries > MAX_RETRIES) {
Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
mObbActionHandler.sendEmptyMessage(OBB_MCS_GIVE_UP);
handleError();
return;
} else {
handleExecute();
if (DEBUG_OBB)
Slog.i(TAG, "Posting install MCS_UNBIND");
mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
}
} catch (RemoteException e) {
if (DEBUG_OBB)
Slog.i(TAG, "Posting install MCS_RECONNECT");
mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
} catch (Exception e) {
if (DEBUG_OBB)
Slog.d(TAG, "Error handling OBB action", e);
handleError();
}
}
abstract void handleExecute() throws RemoteException;
abstract void handleError();
}
class MountObbAction extends ObbAction {
private String mKey;
MountObbAction(ObbState obbState, String key) {
super(obbState);
mKey = key;
}
public void handleExecute() throws RemoteException {
ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
}
if (mKey == null) {
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;
}
}
if (rc == StorageResultCode.OperationSucceeded) {
try {
mObbState.token.onObbResult(mObbState.filename, "mounted");
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
} else {
rc = StorageResultCode.OperationFailedInternalError;
Slog.e(TAG, "Couldn't mount OBB file");
// We didn't succeed, so remove this from the mount-set.
removeObbState(mObbState);
}
}
if (rc == StorageResultCode.OperationSucceeded) {
synchronized (mObbMountSet) {
mObbMountSet.remove(filename);
public void handleError() {
removeObbState(mObbState);
try {
mObbState.token.onObbResult(mObbState.filename, "error");
} catch (RemoteException e) {
Slog.e(TAG, "Couldn't send back OBB mount error for " + mObbState.filename);
}
}
return rc;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("MountObbAction{");
sb.append("filename=");
sb.append(mObbState.filename);
sb.append(",callerUid=");
sb.append(mObbState.callerUid);
sb.append(",token=");
sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL");
sb.append('}');
return sb.toString();
}
}
class UnmountObbAction extends ObbAction {
private boolean mForceUnmount;
UnmountObbAction(ObbState obbState, boolean force) {
super(obbState);
mForceUnmount = force;
}
public void handleExecute() throws RemoteException {
ObbInfo obbInfo = mContainerService.getObbInfo(mObbState.filename);
if (!isCallerOwnerOfPackageOrSystem(obbInfo.packageName)) {
throw new IllegalArgumentException("Caller package does not match OBB file");
}
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) {
removeObbState(mObbState);
try {
mObbState.token.onObbResult(mObbState.filename, "unmounted");
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
} else {
try {
mObbState.token.onObbResult(mObbState.filename, "error");
} catch (RemoteException e) {
Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
}
}
}
public void handleError() {
removeObbState(mObbState);
try {
mObbState.token.onObbResult(mObbState.filename, "error");
} catch (RemoteException e) {
Slog.e(TAG, "Couldn't send back OBB unmount error for " + mObbState.filename);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("UnmountObbAction{");
sb.append("filename=");
sb.append(mObbState.filename != null ? mObbState.filename : "null");
sb.append(",force=");
sb.append(mForceUnmount);
sb.append(",callerUid=");
sb.append(mObbState.callerUid);
sb.append(",token=");
sb.append(mObbState.token != null ? mObbState.token.toString() : "null");
sb.append('}');
return sb.toString();
}
}
}