Implement IOmxStore

Separate out MediaCodecsXmlParser and implement IOmxStore and IOMXStore.

Test: make cts -j123 && cts-tradefed run cts-dev -m \
CtsMediaTestCases --compatibility:module-arg \
CtsMediaTestCases:include-annotation:\
android.platform.test.annotations.RequiresDevice

Test: make cts -j123 && cts-tradefed run cts -m \
CtsMediaTestCases -t android.media.cts.MediaCodecListTest

Bug: 37657124

Change-Id: I8c5a3a8fe6defab4f17c8a49bce57452879193dc
diff --git a/media/libmedia/IMediaCodecService.cpp b/media/libmedia/IMediaCodecService.cpp
index 2d62419..adfa93d 100644
--- a/media/libmedia/IMediaCodecService.cpp
+++ b/media/libmedia/IMediaCodecService.cpp
@@ -27,7 +27,8 @@
 namespace android {
 
 enum {
-    GET_OMX = IBinder::FIRST_CALL_TRANSACTION
+    GET_OMX = IBinder::FIRST_CALL_TRANSACTION,
+    GET_OMX_STORE
 };
 
 class BpMediaCodecService : public BpInterface<IMediaCodecService>
@@ -45,6 +46,13 @@
         return interface_cast<IOMX>(reply.readStrongBinder());
     }
 
+    virtual sp<IOMXStore> getOMXStore() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaCodecService::getInterfaceDescriptor());
+        remote()->transact(GET_OMX_STORE, data, &reply);
+        return interface_cast<IOMXStore>(reply.readStrongBinder());
+    }
+
 };
 
 IMPLEMENT_META_INTERFACE(MediaCodecService, "android.media.IMediaCodecService");
@@ -62,6 +70,12 @@
             reply->writeStrongBinder(IInterface::asBinder(omx));
             return NO_ERROR;
         }
+        case GET_OMX_STORE: {
+            CHECK_INTERFACE(IMediaCodecService, data, reply);
+            sp<IOMXStore> omxStore = getOMXStore();
+            reply->writeStrongBinder(IInterface::asBinder(omxStore));
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 2a74512..a570ffe 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -101,42 +101,46 @@
     return OK;
 }
 
-void MediaCodecInfo::CapabilitiesBuilder::addProfileLevel(uint32_t profile, uint32_t level) {
+void MediaCodecInfo::CapabilitiesWriter::addDetail(
+        const char* key, const char* value) {
+    mCap->mDetails->setString(key, value);
+}
+
+void MediaCodecInfo::CapabilitiesWriter::addDetail(
+        const char* key, int32_t value) {
+    mCap->mDetails->setInt32(key, value);
+}
+
+void MediaCodecInfo::CapabilitiesWriter::addProfileLevel(
+        uint32_t profile, uint32_t level) {
     ProfileLevel profileLevel;
     profileLevel.mProfile = profile;
     profileLevel.mLevel = level;
-    if (mProfileLevelsSorted.indexOf(profileLevel) < 0) {
-        mProfileLevels.push_back(profileLevel);
-        mProfileLevelsSorted.add(profileLevel);
+    if (mCap->mProfileLevelsSorted.indexOf(profileLevel) < 0) {
+        mCap->mProfileLevels.push_back(profileLevel);
+        mCap->mProfileLevelsSorted.add(profileLevel);
     }
 }
 
-void MediaCodecInfo::CapabilitiesBuilder::addColorFormat(uint32_t format) {
-    if (mColorFormatsSorted.indexOf(format) < 0) {
-        mColorFormats.push(format);
-        mColorFormatsSorted.add(format);
+void MediaCodecInfo::CapabilitiesWriter::addColorFormat(uint32_t format) {
+    if (mCap->mColorFormatsSorted.indexOf(format) < 0) {
+        mCap->mColorFormats.push(format);
+        mCap->mColorFormatsSorted.add(format);
     }
 }
 
-void MediaCodecInfo::CapabilitiesBuilder::addFlags(uint32_t flags) {
-    mFlags |= flags;
+void MediaCodecInfo::CapabilitiesWriter::addFlags(uint32_t flags) {
+    mCap->mFlags |= flags;
+}
+
+MediaCodecInfo::CapabilitiesWriter::CapabilitiesWriter(
+        MediaCodecInfo::Capabilities* cap) : mCap(cap) {
 }
 
 bool MediaCodecInfo::isEncoder() const {
     return mIsEncoder;
 }
 
-bool MediaCodecInfo::hasQuirk(const char *name) const {
-    if (name) {
-        for (size_t ix = 0; ix < mQuirks.size(); ix++) {
-            if (mQuirks.itemAt(ix).equalsIgnoreCase(name)) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
 void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
     mimes->clear();
     for (size_t ix = 0; ix < mCaps.size(); ix++) {
@@ -157,20 +161,21 @@
     return mName.c_str();
 }
 
+const char *MediaCodecInfo::getOwnerName() const {
+    return mOwner.c_str();
+}
+
 // static
 sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
     AString name = AString::FromParcel(parcel);
+    AString owner = AString::FromParcel(parcel);
     bool isEncoder = static_cast<bool>(parcel.readInt32());
-    sp<MediaCodecInfo> info = new MediaCodecInfo(name, isEncoder, NULL);
+    sp<MediaCodecInfo> info = new MediaCodecInfo;
+    info->mName = name;
+    info->mOwner = owner;
+    info->mIsEncoder = isEncoder;
     size_t size = static_cast<size_t>(parcel.readInt32());
     for (size_t i = 0; i < size; i++) {
-        AString quirk = AString::FromParcel(parcel);
-        if (info != NULL) {
-            info->mQuirks.push_back(quirk);
-        }
-    }
-    size = static_cast<size_t>(parcel.readInt32());
-    for (size_t i = 0; i < size; i++) {
         AString mime = AString::FromParcel(parcel);
         sp<Capabilities> caps = Capabilities::FromParcel(parcel);
         if (caps == NULL)
@@ -184,11 +189,8 @@
 
 status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
     mName.writeToParcel(parcel);
+    mOwner.writeToParcel(parcel);
     parcel->writeInt32(mIsEncoder);
-    parcel->writeInt32(mQuirks.size());
-    for (size_t i = 0; i < mQuirks.size(); i++) {
-        mQuirks.itemAt(i).writeToParcel(parcel);
-    }
     parcel->writeInt32(mCaps.size());
     for (size_t i = 0; i < mCaps.size(); i++) {
         mCaps.keyAt(i).writeToParcel(parcel);
@@ -208,86 +210,46 @@
     return -1;
 }
 
-MediaCodecInfo::MediaCodecInfo(AString name, bool encoder, const char *mime)
-    : mName(name),
-      mIsEncoder(encoder),
-      mHasSoleMime(false) {
-    if (mime != NULL) {
-        addMime(mime);
-        mHasSoleMime = true;
-    }
+MediaCodecInfo::MediaCodecInfo() {
 }
 
-status_t MediaCodecInfo::addMime(const char *mime) {
-    if (mHasSoleMime) {
-        ALOGE("Codec '%s' already had its type specified", mName.c_str());
-        return -EINVAL;
-    }
-    ssize_t ix = getCapabilityIndex(mime);
+void MediaCodecInfoWriter::setName(const char* name) {
+    mInfo->mName = name;
+}
+
+void MediaCodecInfoWriter::setOwner(const char* owner) {
+    mInfo->mOwner = owner;
+}
+
+void MediaCodecInfoWriter::setEncoder(bool isEncoder) {
+    mInfo->mIsEncoder = isEncoder;
+}
+
+std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>
+        MediaCodecInfoWriter::addMime(const char *mime) {
+    ssize_t ix = mInfo->getCapabilityIndex(mime);
     if (ix >= 0) {
-        mCurrentCaps = mCaps.valueAt(ix);
-    } else {
-        mCurrentCaps = new Capabilities();
-        mCaps.add(AString(mime), mCurrentCaps);
+        return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
+                new MediaCodecInfo::CapabilitiesWriter(
+                mInfo->mCaps.valueAt(ix).get()));
     }
-    return OK;
+    sp<MediaCodecInfo::Capabilities> caps = new MediaCodecInfo::Capabilities();
+    mInfo->mCaps.add(AString(mime), caps);
+    return std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>(
+            new MediaCodecInfo::CapabilitiesWriter(caps.get()));
 }
 
-status_t MediaCodecInfo::updateMime(const char *mime) {
-    ssize_t ix = getCapabilityIndex(mime);
-    if (ix < 0) {
-        ALOGE("updateMime mime not found %s", mime);
-        return -EINVAL;
-    }
-
-    mCurrentCaps = mCaps.valueAt(ix);
-    return OK;
-}
-
-void MediaCodecInfo::removeMime(const char *mime) {
-    ssize_t ix = getCapabilityIndex(mime);
+bool MediaCodecInfoWriter::removeMime(const char *mime) {
+    ssize_t ix = mInfo->getCapabilityIndex(mime);
     if (ix >= 0) {
-        mCaps.removeItemsAt(ix);
-        // mCurrentCaps will be removed when completed
+        mInfo->mCaps.removeItemsAt(ix);
+        return true;
     }
+    return false;
 }
 
-status_t MediaCodecInfo::initializeCapabilities(const sp<Capabilities> &caps) {
-    // TRICKY: copy data to mCurrentCaps as it is a reference to
-    // an element of the capabilites map.
-    mCurrentCaps->mColorFormats.clear();
-    mCurrentCaps->mColorFormats.appendVector(caps->mColorFormats);
-    mCurrentCaps->mProfileLevels.clear();
-    mCurrentCaps->mProfileLevels.appendVector(caps->mProfileLevels);
-    mCurrentCaps->mFlags = caps->mFlags;
-    mCurrentCaps->mDetails = caps->mDetails;
-    return OK;
-}
-
-void MediaCodecInfo::addQuirk(const char *name) {
-    if (!hasQuirk(name)) {
-        mQuirks.push(name);
-    }
-}
-
-void MediaCodecInfo::complete() {
-    mCurrentCaps = NULL;
-}
-
-void MediaCodecInfo::addDetail(const AString &key, const AString &value) {
-    mCurrentCaps->mDetails->setString(key.c_str(), value.c_str());
-}
-
-void MediaCodecInfo::addFeature(const AString &key, int32_t value) {
-    AString tag = "feature-";
-    tag.append(key);
-    mCurrentCaps->mDetails->setInt32(tag.c_str(), value);
-}
-
-void MediaCodecInfo::addFeature(const AString &key, const char *value) {
-    AString tag = "feature-";
-    tag.append(key);
-    mCurrentCaps->mDetails->setString(tag.c_str(), value);
+MediaCodecInfoWriter::MediaCodecInfoWriter(MediaCodecInfo* info) :
+    mInfo(info) {
 }
 
 }  // namespace android
diff --git a/media/libmedia/include/media/IMediaCodecService.h b/media/libmedia/include/media/IMediaCodecService.h
index da3c5a03..59fb1c0 100644
--- a/media/libmedia/include/media/IMediaCodecService.h
+++ b/media/libmedia/include/media/IMediaCodecService.h
@@ -22,6 +22,7 @@
 #include <binder/Parcel.h>
 #include <media/IDataSource.h>
 #include <media/IOMX.h>
+#include <media/IOMXStore.h>
 
 namespace android {
 
@@ -31,6 +32,7 @@
     DECLARE_META_INTERFACE(MediaCodecService);
 
     virtual sp<IOMX> getOMX() = 0;
+    virtual sp<IOMXStore> getOMXStore() = 0;
 };
 
 class BnMediaCodecService: public BnInterface<IMediaCodecService>
diff --git a/media/libmedia/include/media/IOMXStore.h b/media/libmedia/include/media/IOMXStore.h
index f739c3b..628db70 100644
--- a/media/libmedia/include/media/IOMXStore.h
+++ b/media/libmedia/include/media/IOMXStore.h
@@ -27,11 +27,6 @@
 #include <vector>
 #include <string>
 
-/*
-#include <OMX_Core.h>
-#include <OMX_Video.h>
-*/
-
 namespace android {
 
 using hardware::media::omx::V1_0::IOmxStore;
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index ef641d2..ab2cd24 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -18,6 +18,7 @@
 
 #define MEDIA_CODEC_INFO_H_
 
+#include <android-base/macros.h>
 #include <binder/Parcel.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AString.h>
@@ -36,6 +37,9 @@
 
 typedef KeyedVector<AString, AString> CodecSettings;
 
+struct MediaCodecInfoWriter;
+struct MediaCodecListWriter;
+
 struct MediaCodecInfo : public RefBase {
     struct ProfileLevel {
         uint32_t mProfile;
@@ -45,6 +49,8 @@
         }
     };
 
+    struct CapabilitiesWriter;
+
     struct Capabilities : public RefBase {
         enum {
             // decoder flags
@@ -77,72 +83,191 @@
         static sp<Capabilities> FromParcel(const Parcel &parcel);
         status_t writeToParcel(Parcel *parcel) const;
 
-        DISALLOW_EVIL_CONSTRUCTORS(Capabilities);
+        DISALLOW_COPY_AND_ASSIGN(Capabilities);
 
         friend struct MediaCodecInfo;
+        friend struct MediaCodecInfoWriter;
+        friend struct CapabilitiesWriter;
     };
 
-    // Use a subclass to allow setting fields on construction without allowing
-    // to do the same throughout the framework.
-    struct CapabilitiesBuilder : public Capabilities {
+    /**
+     * This class is used for modifying information inside a `Capabilities`
+     * object. An object of type `CapabilitiesWriter` can be obtained by calling
+     * `MediaCodecInfoWriter::addMime()` or
+     * `MediaCodecInfoWriter::updateMime()`.
+     */
+    struct CapabilitiesWriter {
+        /**
+         * Add a key-value pair to the list of details. If the key already
+         * exists, the old value will be replaced.
+         *
+         * A pair added by this function will be accessible by
+         * `Capabilities::getDetails()`. Call `AMessage::getString()` with the
+         * same key to retrieve the value.
+         *
+         * @param key The key.
+         * @param value The string value.
+         */
+        void addDetail(const char* key, const char* value);
+        /**
+         * Add a key-value pair to the list of details. If the key already
+         * exists, the old value will be replaced.
+         *
+         * A pair added by this function will be accessible by
+         * `Capabilities::getDetails()`. Call `AMessage::getInt32()` with the
+         * same key to retrieve the value.
+         *
+         * @param key The key.
+         * @param value The `int32_t` value.
+         */
+        void addDetail(const char* key, int32_t value);
+        /**
+         * Add a profile-level pair. If this profile-level pair already exists,
+         * it will be ignored.
+         *
+         * @param profile The "profile" component.
+         * @param level The "level" component.
+         */
         void addProfileLevel(uint32_t profile, uint32_t level);
+        /**
+         * Add a color format. If this color format already exists, it will be
+         * ignored.
+         *
+         * @param format The color format.
+         */
         void addColorFormat(uint32_t format);
+        /**
+         * Add flags. The underlying operation is bitwise-or. In other words,
+         * bits that have already been set will be ignored.
+         *
+         * @param flags The additional flags.
+         */
         void addFlags(uint32_t flags);
+    private:
+        /**
+         * The associated `Capabilities` object.
+         */
+        Capabilities* mCap;
+        /**
+         * Construct a writer for the given `Capabilities` object.
+         *
+         * @param cap The `Capabilities` object to be written to.
+         */
+        CapabilitiesWriter(Capabilities* cap);
+
+        friend MediaCodecInfoWriter;
     };
 
     bool isEncoder() const;
-    bool hasQuirk(const char *name) const;
     void getSupportedMimes(Vector<AString> *mimes) const;
     const sp<Capabilities> getCapabilitiesFor(const char *mime) const;
     const char *getCodecName() const;
 
     /**
+     * Return the name of the service that hosts the codec. This value is not
+     * visible at the Java level.
+     *
+     * Currently, this is the "instance name" of the IOmx service.
+     */
+    const char *getOwnerName() const;
+
+    /**
      * Serialization over Binder
      */
     static sp<MediaCodecInfo> FromParcel(const Parcel &parcel);
     status_t writeToParcel(Parcel *parcel) const;
 
 private:
-    // variable set only in constructor - these are accessed by MediaCodecList
-    // to avoid duplication of same variables
     AString mName;
+    AString mOwner;
     bool mIsEncoder;
-    bool mHasSoleMime; // was initialized with mime
-
-    Vector<AString> mQuirks;
     KeyedVector<AString, sp<Capabilities> > mCaps;
 
-    sp<Capabilities> mCurrentCaps; // currently initalized capabilities
-
     ssize_t getCapabilityIndex(const char *mime) const;
 
-    /* Methods used by MediaCodecList to construct the info
-     * object from XML.
-     *
-     * After info object is created:
-     * - additional quirks can be added
-     * - additional mimes can be added
-     *   - OMX codec capabilities can be set for the current mime-type
-     *   - a capability detail can be set for the current mime-type
-     *   - a feature can be set for the current mime-type
-     *   - info object can be completed when parsing of a mime-type is done
+    /**
+     * Construct an `MediaCodecInfo` object. After the construction, its
+     * information can be set via an `MediaCodecInfoWriter` object obtained from
+     * `MediaCodecListWriter::addMediaCodecInfo()`.
      */
-    MediaCodecInfo(AString name, bool encoder, const char *mime);
-    void addQuirk(const char *name);
-    status_t addMime(const char *mime);
-    status_t updateMime(const char *mime);
+    MediaCodecInfo();
 
-    status_t initializeCapabilities(const sp<Capabilities> &caps);
-    void addDetail(const AString &key, const AString &value);
-    void addFeature(const AString &key, int32_t value);
-    void addFeature(const AString &key, const char *value);
-    void removeMime(const char *mime);
-    void complete();
+    DISALLOW_COPY_AND_ASSIGN(MediaCodecInfo);
 
-    DISALLOW_EVIL_CONSTRUCTORS(MediaCodecInfo);
-
-    friend struct MediaCodecList;
     friend class MediaCodecListOverridesTest;
+    friend struct MediaCodecInfoWriter;
+    friend struct MediaCodecListWriter;
+};
+
+/**
+ * This class is to be used by a `MediaCodecListBuilderBase` instance to
+ * populate information inside the associated `MediaCodecInfo` object.
+ *
+ * The only place where an instance of `MediaCodecInfoWriter` can be constructed
+ * is `MediaCodecListWriter::addMediaCodecInfo()`. A `MediaCodecListBuilderBase`
+ * instance should call `MediaCodecListWriter::addMediaCodecInfo()` on the given
+ * `MediaCodecListWriter` object given as an input to
+ * `MediaCodecListBuilderBase::buildMediaCodecList()`.
+ */
+struct MediaCodecInfoWriter {
+    /**
+     * Set the name of the codec.
+     *
+     * @param name The new name.
+     */
+    void setName(const char* name);
+    /**
+     * Set the owner name of the codec.
+     *
+     * This "owner name" is the name of the `IOmx` instance that supports this
+     * codec.
+     *
+     * @param owner The new owner name.
+     */
+    void setOwner(const char* owner);
+    /**
+     * Set whether this codec is an encoder or a decoder.
+     *
+     * @param isEncoder Whether this codec is an encoder or a decoder.
+     */
+    void setEncoder(bool isEncoder = true);
+    /**
+     * Add a mime to an indexed list and return a `CapabilitiesWriter` object
+     * that can be used for modifying the associated `Capabilities`.
+     *
+     * If the mime already exists, this function will return the
+     * `CapabilitiesWriter` associated with the mime.
+     *
+     * @param[in] mime The name of a new mime to add.
+     * @return writer The `CapabilitiesWriter` object for modifying the
+     * `Capabilities` associated with the mime. `writer` will be valid
+     * regardless of whether `mime` already exists or not.
+     */
+    std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> addMime(
+            const char* mime);
+    /**
+     * Remove a mime.
+     *
+     * @param mime The name of the mime to remove.
+     * @return `true` if `mime` is removed; `false` if `mime` is not found.
+     */
+    bool removeMime(const char* mime);
+private:
+    /**
+     * The associated `MediaCodecInfo`.
+     */
+    MediaCodecInfo* mInfo;
+    /**
+     * Construct the `MediaCodecInfoWriter` object associated with the given
+     * `MediaCodecInfo` object.
+     *
+     * @param info The underlying `MediaCodecInfo` object.
+     */
+    MediaCodecInfoWriter(MediaCodecInfo* info);
+
+    DISALLOW_COPY_AND_ASSIGN(MediaCodecInfoWriter);
+
+    friend struct MediaCodecListWriter;
 };
 
 }  // namespace android