Merge "stagefright: distinguish HAL name from name in MediaCodecInfo" into main
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 1a6e5e8..5acd35c 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -737,9 +737,10 @@
                 }
 
                 printf("    owner: \"%s\"\n", info->getOwnerName());
+                printf("    hal name: \"%s\"\n", info->getHalName());
                 printf("    rank: %u\n", info->getRank());
             } else {
-                printf("    aliases, attributes, owner, rank: see above\n");
+                printf("    aliases, attributes, owner, hal name, rank: see above\n");
             }
 
             {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 5578ead..99f0f53 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1043,11 +1043,12 @@
         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
         return;
     }
-    ALOGD("allocate(%s)", codecInfo->getCodecName());
     mClientListener.reset(new ClientListener(this));
 
     AString componentName = codecInfo->getCodecName();
+    AString halName = codecInfo->getHalName();
     std::shared_ptr<Codec2Client> client;
+    ALOGD("allocate(%s)", componentName.c_str());
 
     // set up preferred component store to access vendor store parameters
     client = Codec2Client::CreateFromService("default");
@@ -1059,12 +1060,12 @@
 
     std::shared_ptr<Codec2Client::Component> comp;
     c2_status_t status = Codec2Client::CreateComponentByName(
-            componentName.c_str(),
+            halName.c_str(),
             mClientListener,
             &comp,
             &client);
     if (status != C2_OK) {
-        ALOGE("Failed Create component: %s, error=%d", componentName.c_str(), status);
+        ALOGE("Failed Create component: %s, error=%d", halName.c_str(), status);
         Mutexed<State>::Locked state(mState);
         state->set(RELEASED);
         state.unlock();
@@ -1072,7 +1073,7 @@
         state.lock();
         return;
     }
-    ALOGI("Created component [%s]", componentName.c_str());
+    ALOGI("Created component [%s] for [%s]", halName.c_str(), componentName.c_str());
     mChannel->setComponent(comp);
     auto setAllocated = [this, comp, client] {
         Mutexed<State>::Locked state(mState);
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 3834278..db83a42 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -22,6 +22,7 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include "media/stagefright/foundation/AString.h"
 #include <binder/Parcel.h>
 
 namespace android {
@@ -185,6 +186,10 @@
     return mName.c_str();
 }
 
+const char *MediaCodecInfo::getHalName() const {
+    return mHalName.c_str();
+}
+
 const char *MediaCodecInfo::getOwnerName() const {
     return mOwner.c_str();
 }
@@ -193,11 +198,13 @@
 sp<MediaCodecInfo> MediaCodecInfo::FromParcel(const Parcel &parcel) {
     sMaxSupportedInstances = parcel.readInt32();
     AString name = AString::FromParcel(parcel);
+    AString halName = AString::FromParcel(parcel);
     AString owner = AString::FromParcel(parcel);
     Attributes attributes = static_cast<Attributes>(parcel.readInt32());
     uint32_t rank = parcel.readUint32();
     sp<MediaCodecInfo> info = new MediaCodecInfo;
     info->mName = name;
+    info->mHalName = halName;
     info->mOwner = owner;
     info->mAttributes = attributes;
     info->mRank = rank;
@@ -226,6 +233,7 @@
 status_t MediaCodecInfo::writeToParcel(Parcel *parcel) const {
     parcel->writeInt32(sMaxSupportedInstances);
     mName.writeToParcel(parcel);
+    mHalName.writeToParcel(parcel);
     mOwner.writeToParcel(parcel);
     parcel->writeInt32(mAttributes);
     parcel->writeUint32(mRank);
@@ -278,6 +286,9 @@
 
 void MediaCodecInfoWriter::setName(const char* name) {
     mInfo->mName = name;
+    // Upon creation, we use the same name for HAL and info and
+    // only distinguish them during collision resolution.
+    mInfo->mHalName = name;
 }
 
 void MediaCodecInfoWriter::addAlias(const char* name) {
@@ -331,6 +342,24 @@
     }
 }
 
+sp<MediaCodecInfo> MediaCodecInfo::splitOutType(const char *mediaType,
+        const char *newName) const {
+    sp<MediaCodecInfo> newInfo = new MediaCodecInfo;
+    newInfo->mName = newName;
+    newInfo->mHalName = mHalName;
+    newInfo->mOwner = mOwner;
+    newInfo->mAttributes = mAttributes;
+    newInfo->mRank = mRank;
+    newInfo->mAliases = mAliases;
+    // allow an alias from the (old) HAL name. If there is a collision, this will be ignored.
+    newInfo->mAliases.add(mHalName);
+
+    // note: mediaType is always a supported type. valueAt() will abort otherwise.
+    newInfo->mCaps.add(AString(mediaType), mCaps.valueAt(getCapabilityIndex(mediaType)));
+    newInfo->mCodecCaps.add(AString(mediaType), mCodecCaps.valueAt(getCodecCapIndex(mediaType)));
+    return newInfo;
+}
+
 // static
 std::shared_ptr<CodecCapabilities> MediaCodecInfoWriter::BuildCodecCapabilities(
         const char *mediaType, sp<MediaCodecInfo::Capabilities> caps, bool isEncoder,
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index 60e383a..4d74a67 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -193,7 +193,11 @@
     void getSupportedMediaTypes(Vector<AString> *mediaTypes) const;
     const sp<Capabilities> getCapabilitiesFor(const char *mediaType) const;
     const std::shared_ptr<CodecCapabilities> getCodecCapsFor(const char *mediaType) const;
+
+    /// returns the codec name used by this info
     const char *getCodecName() const;
+    /// returns the codec name as used by the HAL
+    const char *getHalName() const;
 
     /**
      * Returns a vector containing alternate names for the codec.
@@ -229,14 +233,24 @@
     static sp<MediaCodecInfo> FromParcel(const Parcel &parcel);
     status_t writeToParcel(Parcel *parcel) const;
 
+    /**
+     * Create a copy of this MediaCodecInfo supporting a single media type.
+     *
+     * \param mediaType the media type for the new MediaCodecInfo. This must be
+     *                  one of the media types supported by this MediaCodecInfo.
+     * \param newName the new codec name for the new MediaCodecInfo.
+     */
+    sp<MediaCodecInfo> splitOutType(const char *mediaType, const char *newName) const;
+
 private:
     /**
      * Max supported instances setting from MediaCodecList global setting.
      */
     static int32_t sMaxSupportedInstances;
 
-    AString mName;
-    AString mOwner;
+    AString mName;     // codec name for this info
+    AString mHalName;  // codec name at the HAL level
+    AString mOwner;    // owning HAL name
     Attributes mAttributes;
     KeyedVector<AString, sp<Capabilities> > mCaps;
     KeyedVector<AString, std::shared_ptr<CodecCapabilities>> mCodecCaps;
@@ -283,7 +297,13 @@
     /**
      * Set the name of the codec.
      *
-     * @param name The new name.
+     * This sets both the name used internally and the HAL name, as during
+     * creation, they are the same. A new internal name will only be created
+     * during name collision resolution while splitting out media types.
+     *
+     * @param name The new name (from XML).
+     *
+     * @see MediaCodecInfo::splitOutType
      */
     void setName(const char* name);
     /**
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 0067344..b28513e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -359,10 +359,12 @@
 
                 snprintf(buffer, SIZE - 1, "    owner: \"%s\"\n", info->getOwnerName());
                 result.append(buffer);
+                snprintf(buffer, SIZE - 1, "    hal name: \"%s\"\n", info->getHalName());
+                result.append(buffer);
                 snprintf(buffer, SIZE - 1, "    rank: %u\n", info->getRank());
                 result.append(buffer);
             } else {
-                result.append("    aliases, attributes, owner, rank: see above\n");
+                result.append("    aliases, attributes, owner, hal name, rank: see above\n");
             }
 
             {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e06efac..bacf758 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -7084,8 +7084,10 @@
     }
     AString owner = (info->getOwnerName() == nullptr) ? "default" : info->getOwnerName();
 
-    AString componentName;
-    CHECK(msg->findString("componentName", &componentName));
+    AString componentName = info->getCodecName();
+    // we are no longer using "componentName" as we always pass the codec info for owner.
+    // CHECK(msg->findString("componentName", &componentName));
+    AString halName = info->getHalName();
 
     sp<CodecObserver> observer = new CodecObserver(notify);
     sp<IOMX> omx;
@@ -7102,11 +7104,12 @@
     pid_t tid = gettid();
     int prevPriority = androidGetThreadPriority(tid);
     androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
-    err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
+    err = omx->allocateNode(halName.c_str(), observer, &omxNode);
     androidSetThreadPriority(tid, prevPriority);
 
     if (err != OK) {
-        ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);
+        ALOGE("Unable to instantiate codec '%s' for '%s' with err %#x.",
+                halName.c_str(), componentName.c_str(), err);
 
         mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));
         return false;
diff --git a/media/libstagefright/MediaCodecListWriter.cpp b/media/libstagefright/MediaCodecListWriter.cpp
index c4fb199..2048f3b 100644
--- a/media/libstagefright/MediaCodecListWriter.cpp
+++ b/media/libstagefright/MediaCodecListWriter.cpp
@@ -19,9 +19,12 @@
 #include <utils/Log.h>
 
 #include <media/stagefright/foundation/AMessage.h>
+#include "media/stagefright/foundation/AString.h"
 #include <media/stagefright/MediaCodecListWriter.h>
 #include <media/MediaCodecInfo.h>
 
+#include <string>
+
 namespace android {
 
 void MediaCodecListWriter::addGlobalSetting(
@@ -56,8 +59,52 @@
 
 void MediaCodecListWriter::writeCodecInfos(
         std::vector<sp<MediaCodecInfo>> *codecInfos) const {
+    // Since the introduction of the NDK MediaCodecList API, each
+    // MediaCodecInfo object can only support a single media type, so infos that
+    // support multiple media types are split into multiple infos.
+    // This process may result in name collisions that are handled here.
+
+    // Prefer codec names that already support a single media type
+    // and also any existing aliases. If an alias matches an existing
+    // codec name, it is ignored, which is the right behavior.
+    std::set<std::string> reservedNames;
     for (const sp<MediaCodecInfo> &info : mCodecInfos) {
-        codecInfos->push_back(info);
+        Vector<AString> mediaTypes;
+        info->getSupportedMediaTypes(&mediaTypes);
+        if (mediaTypes.size() == 1) {
+            reservedNames.insert(info->getCodecName());
+        }
+        Vector<AString> aliases;
+        info->getAliases(&aliases);
+        for (const AString &alias : aliases) {
+            reservedNames.insert(alias.c_str());
+        }
+    }
+
+    for (const sp<MediaCodecInfo> &info : mCodecInfos) {
+        Vector<AString> mediaTypes;
+        info->getSupportedMediaTypes(&mediaTypes);
+        if (mediaTypes.size() == 1) {
+            codecInfos->push_back(info);
+        } else {
+            // disambiguate each type
+            for (const AString &mediaType : mediaTypes) {
+                // get the type name after the first slash (if exists)
+                ssize_t slashPosition = mediaType.find("/");
+                const char *typeName = mediaType.c_str() + (slashPosition + 1);
+
+                // find a unique name for the split codec info starting with "<name>.<type>"
+                AString newName = AStringPrintf("%s.%s", info->getCodecName(), typeName);
+                std::string newNameStr = newName.c_str();
+                // append increasing suffix of the form ".<number>" until a unique name is found
+                for (size_t ix = 1; reservedNames.count(newNameStr) > 0; ++ix) {
+                    newNameStr = AStringPrintf("%s.%zu", newName.c_str(), ix).c_str();
+                }
+
+                codecInfos->push_back(info->splitOutType(mediaType.c_str(), newNameStr.c_str()));
+                reservedNames.insert(newNameStr);
+            }
+        }
     }
 }
 
diff --git a/media/module/foundation/include/media/stagefright/foundation/AString.h b/media/module/foundation/include/media/stagefright/foundation/AString.h
index 517774b..7ab6b7c 100644
--- a/media/module/foundation/include/media/stagefright/foundation/AString.h
+++ b/media/module/foundation/include/media/stagefright/foundation/AString.h
@@ -67,6 +67,9 @@
     void insert(const AString &from, size_t insertionPos);
     void insert(const char *from, size_t size, size_t insertionPos);
 
+    // Returns the index of the first occurrence of substring in the string, or -1 if not found.
+    // If start is specified, the search is limited to the substring starting at that position.
+    // The start parameter MUST NOT be greater than the string size.
     ssize_t find(const char *substring, size_t start = 0) const;
 
     size_t hash() const;