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

Commit 05105f7a authored by Kenny Root's avatar Kenny Root
Browse files

Update OBB API to include callbacks

Add a callback for users of the StorageManager API to be able to receive
notifications when the requested operation completes for mountObb and
unmountObb.

Add NDK API to get to ObbInfo like the Java API has.

Also update the docs for the API and remove the "STOPSHIP" comments.

Change-Id: I23a4409c7f8b74d3169614beba920b4d667990a4
parent ea2cf2f9
Loading
Loading
Loading
Loading
+148 −0
Original line number Diff line number Diff line
@@ -52619,6 +52619,118 @@
>
</field>
</class>
<class name="ObbInfo"
 extends="java.lang.Object"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<implements name="android.os.Parcelable">
</implements>
<method name="describeContents"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="writeToParcel"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="dest" type="android.os.Parcel">
</parameter>
<parameter name="parcelableFlags" type="int">
</parameter>
</method>
<field name="CREATOR"
 type="android.os.Parcelable.Creator"
 transient="false"
 volatile="false"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="OBB_OVERLAY"
 type="int"
 transient="false"
 volatile="false"
 value="1"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="flags"
 type="int"
 transient="false"
 volatile="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="packageName"
 type="java.lang.String"
 transient="false"
 volatile="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</field>
<field name="version"
 type="int"
 transient="false"
 volatile="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</field>
</class>
<class name="ObbScanner"
 extends="java.lang.Object"
 abstract="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<method name="getObbInfo"
 return="android.content.res.ObbInfo"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="filePath" type="java.lang.String">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</class>
<class name="Resources"
 extends="java.lang.Object"
 abstract="false"
@@ -129032,6 +129144,38 @@
</package>
<package name="android.os.storage"
>
<class name="OnObbStateChangeListener"
 extends="java.lang.Object"
 abstract="true"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<constructor name="OnObbStateChangeListener"
 type="android.os.storage.OnObbStateChangeListener"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</constructor>
<method name="onObbStateChange"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="path" type="java.lang.String">
</parameter>
<parameter name="state" type="java.lang.String">
</parameter>
</method>
</class>
<class name="StorageManager"
 extends="java.lang.Object"
 abstract="false"
@@ -129082,6 +129226,8 @@
</parameter>
<parameter name="key" type="java.lang.String">
</parameter>
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
</method>
<method name="unmountObb"
 return="boolean"
@@ -129097,6 +129243,8 @@
</parameter>
<parameter name="force" type="boolean">
</parameter>
<parameter name="listener" type="android.os.storage.OnObbStateChangeListener">
</parameter>
<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
</exception>
</method>
+5 −4
Original line number Diff line number Diff line
@@ -20,9 +20,9 @@ import android.os.Parcel;
import android.os.Parcelable;

/**
 * Basic information about a Opaque Binary Blob (OBB) that reflects
 * the info from the footer on the OBB file.
 * @hide
 * Basic information about a Opaque Binary Blob (OBB) that reflects the info
 * from the footer on the OBB file. This information may be manipulated by a
 * developer with the <code>obbtool</code> program in the Android SDK.
 */
public class ObbInfo implements Parcelable {
    /** Flag noting that this OBB is an overlay patch for a base OBB. */
@@ -43,7 +43,8 @@ public class ObbInfo implements Parcelable {
     */
    public int flags;

    public ObbInfo() {
    // Only allow things in this package to instantiate.
    /* package */ ObbInfo() {
    }

    public String toString() {
+26 −8
Original line number Diff line number Diff line
@@ -16,25 +16,43 @@

package android.content.res;

import java.io.File;
import java.io.IOException;

/**
 * Class to scan Opaque Binary Blob (OBB) files.
 * @hide
 * Class to scan Opaque Binary Blob (OBB) files. Use this to get information
 * about an OBB file for use in a program via {@link ObbInfo}.
 */
public class ObbScanner {
    // Don't allow others to instantiate this class
    private ObbScanner() {}

    public static ObbInfo getObbInfo(String filePath) {
    /**
     * Scan a file for OBB information.
     * 
     * @param filePath path to the OBB file to be scanned.
     * @return ObbInfo object information corresponding to the file path
     * @throws IllegalArgumentException if the OBB file couldn't be found
     * @throws IOException if the OBB file couldn't be read
     */
    public static ObbInfo getObbInfo(String filePath) throws IOException {
        if (filePath == null) {
            return null;
            throw new IllegalArgumentException("file path cannot be null");
        }

        ObbInfo obbInfo = new ObbInfo();
        if (!getObbInfo_native(filePath, obbInfo)) {
            throw new IllegalArgumentException("Could not read OBB file: " + filePath);
        final File obbFile = new File(filePath);
        if (!obbFile.exists()) {
            throw new IllegalArgumentException("OBB file does nto exist: " + filePath);
        }

        final String canonicalFilePath = obbFile.getCanonicalPath();

        ObbInfo obbInfo = new ObbInfo();
        getObbInfo_native(canonicalFilePath, obbInfo);

        return obbInfo;
    }

    private native static boolean getObbInfo_native(String filePath, ObbInfo obbInfo);
    private native static void getObbInfo_native(String filePath, ObbInfo obbInfo)
            throws IOException;
}
+31 −0
Original line number Diff line number Diff line
/*
 * 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;

/**
 * Used for receiving notifications from {@link StorageManager}.
 */
public abstract class OnObbStateChangeListener {
    /**
     * 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) {
    }
}
+150 −17
Original line number Diff line number Diff line
@@ -23,13 +23,28 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * StorageManager is the interface to the systems storage service.
 * StorageManager is the interface to the systems storage service. The storage
 * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
 * <p>
 * OBBs contain a filesystem that maybe be encrypted on disk and mounted
 * on-demand from an application. OBBs are a good way of providing large amounts
 * of binary assets without packaging them into APKs as they may be multiple
 * gigabytes in size. However, due to their size, they're most likely stored in
 * a shared storage pool accessible from all programs. The system does not
 * guarantee the security of the OBB file itself: if any program modifies the
 * OBB, there is no guarantee that a read from that OBB will produce the
 * expected output.
 * <p>
 * Get an instance of this class by calling
 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
 * of {@link android.content.Context#STORAGE_SERVICE}.
 * {@link android.content.Context#getSystemService(java.lang.String)} with an
 * argument of {@link android.content.Context#STORAGE_SERVICE}.
 */

public class StorageManager
@@ -75,11 +90,113 @@ public class StorageManager
    /**
     * Binder listener for OBB action results.
     */
    private final ObbActionBinderListener mObbActionListener = new ObbActionBinderListener();
    private class ObbActionBinderListener extends IObbActionListener.Stub {
    private final ObbActionListener mObbActionListener = new ObbActionListener();

    private class ObbActionListener extends IObbActionListener.Stub {
        private List<WeakReference<ObbListenerDelegate>> mListeners = new LinkedList<WeakReference<ObbListenerDelegate>>();

        @Override
        public void onObbResult(String filename, String status) throws RemoteException {
            Log.i(TAG, "filename = " + filename + ", result = " + 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;
                    }

                    delegate.sendObbStateChanged(filename, status);
                }
            }
        }

        public void addListener(OnObbStateChangeListener listener) {
            if (listener == null) {
                return;
            }

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

                final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
                mListeners.add(new WeakReference<ObbListenerDelegate>(delegate));
            }
        }
    }

    /**
     * Private class containing sender and receiver code for StorageEvents.
     */
    private class ObbListenerDelegate {
        private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
        private final Handler mHandler;

        ObbListenerDelegate(OnObbStateChangeListener listener) {
            mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
            mHandler = new Handler(mTgtLooper) {
                @Override
                public void handleMessage(Message msg) {
                    final OnObbStateChangeListener listener = getListener();
                    if (listener == null) {
                        return;
                    }

                    StorageEvent e = (StorageEvent) msg.obj;

                    if (msg.what == StorageEvent.EVENT_OBB_STATE_CHANGED) {
                        ObbStateChangedStorageEvent ev = (ObbStateChangedStorageEvent) e;
                        listener.onObbStateChange(ev.path, ev.state);
                    } else {
                        Log.e(TAG, "Unsupported event " + msg.what);
                    }
                }
            };
        }

        OnObbStateChangeListener getListener() {
            if (mObbEventListenerRef == null) {
                return null;
            }
            return mObbEventListenerRef.get();
        }

        void sendObbStateChanged(String path, String state) {
            ObbStateChangedStorageEvent e = new ObbStateChangedStorageEvent(path, state);
            mHandler.sendMessage(e.getMessage());
        }
    }

    /**
     * Message sent during an OBB status change event.
     */
    private class ObbStateChangedStorageEvent extends StorageEvent {
        public final String path;
        public final String state;

        public ObbStateChangedStorageEvent(String path, String state) {
            super(EVENT_OBB_STATE_CHANGED);
            this.path = path;
            this.state = state;
        }
    }

@@ -88,8 +205,9 @@ public class StorageManager
     * and the target looper handler.
     */
    private class StorageEvent {
        public static final int EVENT_UMS_CONNECTION_CHANGED = 1;
        public static final int EVENT_STORAGE_STATE_CHANGED   = 2;
        static final int EVENT_UMS_CONNECTION_CHANGED = 1;
        static final int EVENT_STORAGE_STATE_CHANGED = 2;
        static final int EVENT_OBB_STATE_CHANGED = 3;

        private Message mMessage;

@@ -300,19 +418,27 @@ public class StorageManager
     * specified, it is supplied to the mounting process to be used in any
     * encryption used in the OBB.
     * <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>.
     * <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
     * That is, shared UID applications can attempt to mount any other
     * application's OBB that shares its UID.
     * <p>
     * STOPSHIP document more; discuss lack of guarantees of security
     * 
     * @param filename the path to the OBB file
     * @param key decryption key
     * @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) {
    public boolean mountObb(String filename, String key, OnObbStateChangeListener listener) {
        try {
            mObbActionListener.addListener(listener);
            mMountService.mountObb(filename, key, mObbActionListener);
            return true;
        } catch (RemoteException e) {
@@ -323,15 +449,20 @@ public class StorageManager
    }

    /**
     * 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.
     * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
     * <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>.
     * <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.
     * <p>
     * STOPSHIP document more; discuss lack of guarantees of security
     * 
     * @param filename path to the OBB file
     * @param force whether to kill any programs using this in order to unmount
@@ -339,8 +470,10 @@ public class StorageManager
     * @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) throws IllegalArgumentException {
    public boolean unmountObb(String filename, boolean force, OnObbStateChangeListener listener)
            throws IllegalArgumentException {
        try {
            mObbActionListener.addListener(listener);
            mMountService.unmountObb(filename, force, mObbActionListener);
            return true;
        } catch (RemoteException e) {
Loading