diff options
author | Kenny Root <kroot@google.com> | 2010-10-11 17:24:54 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-10-11 17:24:54 -0700 |
commit | b4de3dca96b9ff18562062e181dcd8b83e641e45 (patch) | |
tree | b2e8b6060e1dbea173de867e5258add9b08ef8f3 /core | |
parent | 1169f420f6df5cf5254fed883efa7e6780473c08 (diff) | |
parent | af9d667ccf3e24058214cf4cc0a8aa8bc5100e3c (diff) | |
download | frameworks_base-b4de3dca96b9ff18562062e181dcd8b83e641e45.zip frameworks_base-b4de3dca96b9ff18562062e181dcd8b83e641e45.tar.gz frameworks_base-b4de3dca96b9ff18562062e181dcd8b83e641e45.tar.bz2 |
Merge "OBB: rearrange to be entirely asynchronous" into gingerbread
Diffstat (limited to 'core')
5 files changed, 261 insertions, 110 deletions
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index 60ea95c..467a0ac 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -484,7 +484,7 @@ public interface IMountService extends IInterface { * IObbActionListener to inform it of the terminal state of the * call. */ - public void mountObb(String filename, String key, IObbActionListener token) + public void mountObb(String filename, String key, IObbActionListener token, int nonce) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); @@ -493,6 +493,7 @@ public interface IMountService extends IInterface { _data.writeString(filename); _data.writeString(key); _data.writeStrongBinder((token != null ? token.asBinder() : null)); + _data.writeInt(nonce); mRemote.transact(Stub.TRANSACTION_mountObb, _data, _reply, 0); _reply.readException(); } finally { @@ -508,8 +509,8 @@ public interface IMountService extends IInterface { * IObbActionListener to inform it of the terminal state of the * call. */ - public void unmountObb(String filename, boolean force, IObbActionListener token) - throws RemoteException { + public void unmountObb(String filename, boolean force, IObbActionListener token, + int nonce) throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { @@ -517,6 +518,7 @@ public interface IMountService extends IInterface { _data.writeString(filename); _data.writeInt((force ? 1 : 0)); _data.writeStrongBinder((token != null ? token.asBinder() : null)); + _data.writeInt(nonce); mRemote.transact(Stub.TRANSACTION_unmountObb, _data, _reply, 0); _reply.readException(); } finally { @@ -855,7 +857,9 @@ public interface IMountService extends IInterface { key = data.readString(); IObbActionListener observer; observer = IObbActionListener.Stub.asInterface(data.readStrongBinder()); - mountObb(filename, key, observer); + int nonce; + nonce = data.readInt(); + mountObb(filename, key, observer, nonce); reply.writeNoException(); return true; } @@ -867,7 +871,9 @@ public interface IMountService extends IInterface { force = 0 != data.readInt(); IObbActionListener observer; observer = IObbActionListener.Stub.asInterface(data.readStrongBinder()); - unmountObb(filename, force, observer); + int nonce; + nonce = data.readInt(); + unmountObb(filename, force, observer, nonce); reply.writeNoException(); return true; } @@ -979,7 +985,7 @@ public interface IMountService extends IInterface { * MountService will call back to the supplied IObbActionListener to inform * it of the terminal state of the call. */ - public void mountObb(String filename, String key, IObbActionListener token) + public void mountObb(String filename, String key, IObbActionListener token, int nonce) throws RemoteException; /* @@ -1023,7 +1029,7 @@ public interface IMountService extends IInterface { * MountService will call back to the supplied IObbActionListener to inform * it of the terminal state of the call. */ - public void unmountObb(String filename, boolean force, IObbActionListener token) + public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce) throws RemoteException; /* diff --git a/core/java/android/os/storage/IObbActionListener.java b/core/java/android/os/storage/IObbActionListener.java index 2c098ac..d6fa58a 100644 --- a/core/java/android/os/storage/IObbActionListener.java +++ b/core/java/android/os/storage/IObbActionListener.java @@ -69,9 +69,11 @@ public interface IObbActionListener extends IInterface { data.enforceInterface(DESCRIPTOR); String filename; filename = data.readString(); - String status; - status = data.readString(); - this.onObbResult(filename, status); + int nonce; + nonce = data.readInt(); + int status; + status = data.readInt(); + this.onObbResult(filename, nonce, status); reply.writeNoException(); return true; } @@ -101,13 +103,15 @@ public interface IObbActionListener extends IInterface { * on * @param returnCode status of the operation */ - public void onObbResult(String filename, String status) throws RemoteException { + public void onObbResult(String filename, int nonce, int status) + throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(filename); - _data.writeString(status); + _data.writeInt(nonce); + _data.writeInt(status); mRemote.transact(Stub.TRANSACTION_onObbResult, _data, _reply, 0); _reply.readException(); } finally { @@ -124,7 +128,8 @@ public interface IObbActionListener extends IInterface { * Return from an OBB action result. * * @param filename the path to the OBB the operation was performed on - * @param returnCode status of the operation + * @param nonce identifier that is meaningful to the receiver + * @param status status code as defined in {@link OnObbStateChangeListener} */ - public void onObbResult(String filename, String status) throws RemoteException; + public void onObbResult(String filename, int nonce, int status) throws RemoteException; } diff --git a/core/java/android/os/storage/OnObbStateChangeListener.java b/core/java/android/os/storage/OnObbStateChangeListener.java index a2d0a56..950195b 100644 --- a/core/java/android/os/storage/OnObbStateChangeListener.java +++ b/core/java/android/os/storage/OnObbStateChangeListener.java @@ -17,15 +17,69 @@ package android.os.storage; /** - * Used for receiving notifications from {@link StorageManager}. + * Used for receiving notifications from {@link StorageManager} about OBB file + * states. */ public abstract class OnObbStateChangeListener { + + /** + * The OBB container is now mounted and ready for use. Returned in status + * messages from calls made via {@link StorageManager} + */ + public static final int MOUNTED = 1; + + /** + * The OBB container is now unmounted and not usable. Returned in status + * messages from calls made via {@link StorageManager} + */ + public static final int UNMOUNTED = 2; + + /** + * There was an internal system error encountered while trying to mount the + * OBB. Returned in status messages from calls made via + * {@link StorageManager} + */ + public static final int ERROR_INTERNAL = 20; + + /** + * The OBB could not be mounted by the system. Returned in status messages + * from calls made via {@link StorageManager} + */ + public static final int ERROR_COULD_NOT_MOUNT = 21; + + /** + * The OBB could not be unmounted. This most likely indicates that a file is + * in use on the OBB. Returned in status messages from calls made via + * {@link StorageManager} + */ + public static final int ERROR_COULD_NOT_UNMOUNT = 22; + + /** + * A call was made to unmount the OBB when it was not mounted. Returned in + * status messages from calls made via {@link StorageManager} + */ + public static final int ERROR_NOT_MOUNTED = 23; + + /** + * The OBB has already been mounted. Returned in status messages from calls + * made via {@link StorageManager} + */ + public static final int ERROR_ALREADY_MOUNTED = 24; + + /** + * The current application does not have permission to use this OBB because + * the OBB indicates it's owned by a different package or the key used to + * open it is incorrect. Returned in status messages from calls made via + * {@link StorageManager} + */ + public static final int ERROR_PERMISSION_DENIED = 25; + /** * Called when an OBB has changed states. * * @param path path to the OBB file the state change has happened on * @param state the current state of the OBB */ - public void onObbStateChange(String path, String state) { + public void onObbStateChange(String path, int state) { } } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 2ebd049..73ac79f 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -22,12 +22,13 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import android.util.Slog; +import android.util.SparseArray; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * StorageManager is the interface to the systems storage service. The storage @@ -69,7 +70,12 @@ public class StorageManager /* * List of our listeners */ - private ArrayList<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>(); + private List<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>(); + + /* + * Next available nonce + */ + final private AtomicInteger mNextNonce = new AtomicInteger(0); private class MountServiceBinderListener extends IMountServiceListener.Stub { public void onUsbMassStorageConnectionChanged(boolean available) { @@ -93,57 +99,38 @@ public class StorageManager private final ObbActionListener mObbActionListener = new ObbActionListener(); private class ObbActionListener extends IObbActionListener.Stub { - private List<WeakReference<ObbListenerDelegate>> mListeners = new LinkedList<WeakReference<ObbListenerDelegate>>(); + private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>(); @Override - public void onObbResult(String filename, String status) throws RemoteException { + public void onObbResult(String filename, int nonce, int status) throws RemoteException { + final ObbListenerDelegate delegate; synchronized (mListeners) { - final Iterator<WeakReference<ObbListenerDelegate>> iter = mListeners.iterator(); - while (iter.hasNext()) { - final WeakReference<ObbListenerDelegate> ref = iter.next(); - - final ObbListenerDelegate delegate = (ref == null) ? null : ref.get(); - if (delegate == null) { - iter.remove(); - continue; - } - - delegate.sendObbStateChanged(filename, status); + delegate = mListeners.get(nonce); + if (delegate != null) { + mListeners.remove(nonce); } } - } - public void addListener(OnObbStateChangeListener listener) { - if (listener == null) { - return; + if (delegate != null) { + delegate.sendObbStateChanged(filename, status); } + } - synchronized (mListeners) { - final Iterator<WeakReference<ObbListenerDelegate>> iter = mListeners.iterator(); - while (iter.hasNext()) { - final WeakReference<ObbListenerDelegate> ref = iter.next(); - - final ObbListenerDelegate delegate = (ref == null) ? null : ref.get(); - if (delegate == null) { - iter.remove(); - continue; - } - - /* - * If we're already in the listeners, we don't need to be in - * there again. - */ - if (listener.equals(delegate.getListener())) { - return; - } - } + public int addListener(OnObbStateChangeListener listener) { + final ObbListenerDelegate delegate = new ObbListenerDelegate(listener); - final ObbListenerDelegate delegate = new ObbListenerDelegate(listener); - mListeners.add(new WeakReference<ObbListenerDelegate>(delegate)); + synchronized (mListeners) { + mListeners.put(delegate.nonce, delegate); } + + return delegate.nonce; } } + private int getNextNonce() { + return mNextNonce.getAndIncrement(); + } + /** * Private class containing sender and receiver code for StorageEvents. */ @@ -151,7 +138,10 @@ public class StorageManager private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef; private final Handler mHandler; + private final int nonce; + ObbListenerDelegate(OnObbStateChangeListener listener) { + nonce = getNextNonce(); mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener); mHandler = new Handler(mTgtLooper) { @Override @@ -180,7 +170,7 @@ public class StorageManager return mObbEventListenerRef.get(); } - void sendObbStateChanged(String path, String state) { + void sendObbStateChanged(String path, int state) { ObbStateChangedStorageEvent e = new ObbStateChangedStorageEvent(path, state); mHandler.sendMessage(e.getMessage()); } @@ -191,9 +181,10 @@ public class StorageManager */ private class ObbStateChangedStorageEvent extends StorageEvent { public final String path; - public final String state; - public ObbStateChangedStorageEvent(String path, String state) { + public final int state; + + public ObbStateChangedStorageEvent(String path, int state) { super(EVENT_OBB_STATE_CHANGED); this.path = path; this.state = state; @@ -420,10 +411,8 @@ public class StorageManager * <p> * The OBB will remain mounted for as long as the StorageManager reference * is held by the application. As soon as this reference is lost, the OBBs - * in use will be unmounted. The {@link OnObbStateChangeListener} registered with - * this call will receive all further OBB-related events until it goes out - * of scope. If the caller is not interested in whether the call succeeds, - * the <code>listener</code> may be specified as <code>null</code>. + * in use will be unmounted. The {@link OnObbStateChangeListener} registered + * with this call will receive the success or failure of this operation. * <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. @@ -433,12 +422,21 @@ public class StorageManager * @param filename the path to the OBB file * @param key secret used to encrypt the OBB; may be <code>null</code> if no * encryption was used on the OBB. + * @param listener will receive the success or failure of the operation * @return whether the mount call was successfully queued or not */ public boolean mountObb(String filename, String key, OnObbStateChangeListener listener) { + if (filename == null) { + throw new IllegalArgumentException("filename cannot be null"); + } + + if (listener == null) { + throw new IllegalArgumentException("listener cannot be null"); + } + try { - mObbActionListener.addListener(listener); - mMountService.mountObb(filename, key, mObbActionListener); + final int nonce = mObbActionListener.addListener(listener); + mMountService.mountObb(filename, key, mObbActionListener, nonce); return true; } catch (RemoteException e) { Log.e(TAG, "Failed to mount OBB", e); @@ -452,10 +450,8 @@ public class StorageManager * <code>force</code> flag is true, it will kill any application needed to * unmount the given OBB (even the calling application). * <p> - * The {@link OnObbStateChangeListener} registered with this call will receive all - * further OBB-related events until it goes out of scope. If the caller is - * not interested in whether the call succeeded, the listener may be - * specified as <code>null</code>. + * The {@link OnObbStateChangeListener} registered with this call will + * receive the success or failure of this operation. * <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. @@ -466,12 +462,21 @@ public class StorageManager * @param filename path to the OBB file * @param force whether to kill any programs using this in order to unmount * it + * @param listener will receive the success or failure of the operation * @return whether the unmount call was successfully queued or not */ public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener) { + if (filename == null) { + throw new IllegalArgumentException("filename cannot be null"); + } + + if (listener == null) { + throw new IllegalArgumentException("listener cannot be null"); + } + try { - mObbActionListener.addListener(listener); - mMountService.unmountObb(filename, force, mObbActionListener); + final int nonce = mObbActionListener.addListener(listener); + mMountService.unmountObb(filename, force, mObbActionListener, nonce); return true; } catch (RemoteException e) { Log.e(TAG, "Failed to mount OBB", e); @@ -486,7 +491,11 @@ public class StorageManager * @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 { + public boolean isObbMounted(String filename) { + if (filename == null) { + throw new IllegalArgumentException("filename cannot be null"); + } + try { return mMountService.isObbMounted(filename); } catch (RemoteException e) { @@ -506,12 +515,14 @@ public class StorageManager * not mounted or exception encountered trying to read status */ public String getMountedObbPath(String filename) { + if (filename == null) { + throw new IllegalArgumentException("filename cannot be null"); + } + 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; diff --git a/core/tests/coretests/src/com/android/server/MountServiceTests.java b/core/tests/coretests/src/com/android/server/MountServiceTests.java index 83e9d18..1f8c92e 100644 --- a/core/tests/coretests/src/com/android/server/MountServiceTests.java +++ b/core/tests/coretests/src/com/android/server/MountServiceTests.java @@ -21,7 +21,6 @@ import com.android.frameworks.coretests.R; import android.content.Context; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; -import android.os.Environment; import android.os.FileUtils; import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageManager; @@ -57,17 +56,15 @@ public class MountServiceTests extends AndroidTestCase { } } - private interface CompletableTask { - public boolean isDone(); - } + private static class ObbObserver extends OnObbStateChangeListener { + private String path; - private static class ObbObserver extends OnObbStateChangeListener implements CompletableTask { - public String path; - public String state; + public int state = -1; boolean done = false; @Override - public void onObbStateChange(String path, String state) { + public void onObbStateChange(String path, int state) { + Log.d(TAG, "Received message. path=" + path + ", state=" + state); synchronized (this) { this.path = path; this.state = state; @@ -76,32 +73,43 @@ public class MountServiceTests extends AndroidTestCase { } } + public String getPath() { + assertTrue("Expected ObbObserver to have received a state change.", done); + return path; + } + + public int getState() { + assertTrue("Expected ObbObserver to have received a state change.", done); + return state; + } + public void reset() { this.path = null; - this.state = null; + this.state = -1; done = false; } public boolean isDone() { return done; } - } - private boolean waitForCompletion(CompletableTask task) { - long waitTime = 0; - synchronized (task) { - while (!task.isDone() && waitTime < MAX_WAIT_TIME) { - try { - task.wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; - } catch (InterruptedException e) { - Log.i(TAG, "Interrupted during sleep", e); + public boolean waitForCompletion() { + long waitTime = 0; + synchronized (this) { + while (!isDone() && waitTime < MAX_WAIT_TIME) { + try { + wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } catch (InterruptedException e) { + Log.i(TAG, "Interrupted during sleep", e); + } } } - } - return task.isDone(); + return isDone(); + } } + private File getFilePath(String name) { final File filesDir = mContext.getFilesDir(); final File outFile = new File(filesDir, name); @@ -128,23 +136,52 @@ public class MountServiceTests extends AndroidTestCase { } private void mountObb(StorageManager sm, final int resource, final File file, - String expectedState) { + int expectedState) { copyRawToFile(resource, file); - ObbObserver observer = new ObbObserver(); + final ObbObserver observer = new ObbObserver(); assertTrue("mountObb call on " + file.getPath() + " should succeed", sm.mountObb(file.getPath(), null, observer)); assertTrue("Mount should have completed", - waitForCompletion(observer)); + observer.waitForCompletion()); + + if (expectedState == OnObbStateChangeListener.MOUNTED) { + assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath())); + } assertEquals("Actual file and resolved file should be the same", - file.getPath(), observer.path); + file.getPath(), observer.getPath()); + + assertEquals(expectedState, observer.getState()); + } + + private ObbObserver mountObbWithoutWait(final StorageManager sm, final int resource, + final File file) { + copyRawToFile(resource, file); + + final ObbObserver observer = new ObbObserver(); + assertTrue("mountObb call on " + file.getPath() + " should succeed", sm.mountObb(file + .getPath(), null, observer)); + + return observer; + } - assertEquals(expectedState, observer.state); + private void waitForObbActionCompletion(final StorageManager sm, final File file, + final ObbObserver observer, int expectedState, boolean checkPath) { + assertTrue("Mount should have completed", observer.waitForCompletion()); + + assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath())); + + if (checkPath) { + assertEquals("Actual file and resolved file should be the same", file.getPath(), + observer.getPath()); + } + + assertEquals(expectedState, observer.getState()); } - private String checkMountedPath(StorageManager sm, File file) { + private String checkMountedPath(final StorageManager sm, final File file) { final String mountPath = sm.getMountedObbPath(file.getPath()); assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX, OBB_MOUNT_PREFIX, @@ -152,13 +189,21 @@ public class MountServiceTests extends AndroidTestCase { return mountPath; } - private void unmountObb(StorageManager sm, final File outFile) { - ObbObserver observer = new ObbObserver(); + private void unmountObb(final StorageManager sm, final File file, int expectedState) { + final ObbObserver observer = new ObbObserver(); + assertTrue("unmountObb call on test1.obb should succeed", - sm.unmountObb(outFile.getPath(), false, observer)); + sm.unmountObb(file.getPath(), + false, observer)); assertTrue("Unmount should have completed", - waitForCompletion(observer)); + observer.waitForCompletion()); + + assertEquals(expectedState, observer.getState()); + + if (expectedState == OnObbStateChangeListener.UNMOUNTED) { + assertFalse("OBB should not be mounted", sm.isObbMounted(file.getPath())); + } } @LargeTest @@ -167,7 +212,9 @@ public class MountServiceTests extends AndroidTestCase { final File outFile = getFilePath("test1.obb"); - mountObb(sm, R.raw.test1, outFile, Environment.MEDIA_MOUNTED); + mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.MOUNTED); + + mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); final String mountPath = checkMountedPath(sm, outFile); final File mountDir = new File(mountPath); @@ -175,7 +222,7 @@ public class MountServiceTests extends AndroidTestCase { assertTrue("OBB mounted path should be a directory", mountDir.isDirectory()); - unmountObb(sm, outFile); + unmountObb(sm, outFile, OnObbStateChangeListener.UNMOUNTED); } @LargeTest @@ -184,7 +231,7 @@ public class MountServiceTests extends AndroidTestCase { final File outFile = getFilePath("test1_nosig.obb"); - mountObb(sm, R.raw.test1_nosig, outFile, Environment.MEDIA_BAD_REMOVAL); + mountObb(sm, R.raw.test1_nosig, outFile, OnObbStateChangeListener.ERROR_INTERNAL); assertFalse("OBB should not be mounted", sm.isObbMounted(outFile.getPath())); @@ -199,7 +246,8 @@ public class MountServiceTests extends AndroidTestCase { final File outFile = getFilePath("test1_wrongpackage.obb"); - mountObb(sm, R.raw.test1_wrongpackage, outFile, Environment.MEDIA_BAD_REMOVAL); + mountObb(sm, R.raw.test1_wrongpackage, outFile, + OnObbStateChangeListener.ERROR_PERMISSION_DENIED); assertFalse("OBB should not be mounted", sm.isObbMounted(outFile.getPath())); @@ -207,4 +255,31 @@ public class MountServiceTests extends AndroidTestCase { assertNull("OBB's mounted path should be null", sm.getMountedObbPath(outFile.getPath())); } + + @LargeTest + public void testMountAndUnmountTwoObbs() { + StorageManager sm = getStorageManager(); + + final File file1 = getFilePath("test1.obb"); + final File file2 = getFilePath("test2.obb"); + + ObbObserver oo1 = mountObbWithoutWait(sm, R.raw.test1, file1); + ObbObserver oo2 = mountObbWithoutWait(sm, R.raw.test1, file2); + + Log.d(TAG, "Waiting for OBB #1 to complete mount"); + waitForObbActionCompletion(sm, file1, oo1, OnObbStateChangeListener.MOUNTED, false); + Log.d(TAG, "Waiting for OBB #2 to complete mount"); + waitForObbActionCompletion(sm, file2, oo2, OnObbStateChangeListener.MOUNTED, false); + + final String mountPath1 = checkMountedPath(sm, file1); + final File mountDir1 = new File(mountPath1); + assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory()); + + final String mountPath2 = checkMountedPath(sm, file2); + final File mountDir2 = new File(mountPath2); + assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory()); + + unmountObb(sm, file1, OnObbStateChangeListener.UNMOUNTED); + unmountObb(sm, file2, OnObbStateChangeListener.UNMOUNTED); + } } |