Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6ce5f60c authored by Kenny Root's avatar Kenny Root Committed by Android Git Automerger
Browse files

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

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

* commit '38cf8867':
  Remove OBBs from state list when volume unmounted
parents 9af6b536 38cf8867
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -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>
+7 −0
Original line number Diff line number Diff line
@@ -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();
+5 −0
Original line number Diff line number Diff line
@@ -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;
+1 −4
Original line number Diff line number Diff line
@@ -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);
+230 −60
Original line number Diff line number Diff line
@@ -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,9 +1543,15 @@ 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) {
        waitForReady();
@@ -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,7 +1912,15 @@ class MountService extends IMountService.Stub
                mKey = "none";
            }

            int rc = StorageResultCode.OperationSucceeded;
            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 {
@@ -1797,29 +1933,26 @@ class MountService extends IMountService.Stub
                }

                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");
                    mObbState.mounted = mounted = true;
                }
            }

            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,10 +1978,31 @@ 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();

            /*
             * 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);
                }
            }

            boolean unmounted = false;
            synchronized (mObbState) {
                if (!mObbState.mounted) {
                    sendNewStatusOrIgnore(obbInfo.filename, Environment.MEDIA_UNMOUNTED);
                    return;
                }

                int rc = StorageResultCode.OperationSucceeded;
@@ -1866,30 +2020,24 @@ class MountService extends IMountService.Stub
                }

                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());
                }
            }
        }
    }
}