Merge "audio: Add presubmit tests for APM"
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index 60c9f85..d96f403 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -137,6 +137,7 @@
     shared_libs: [
         "libhwbinder",
         "libcamera2ndk_vendor",
+        "libcamera_metadata",
         "libmediandk",
         "libnativewindow",
         "libutils",
@@ -144,6 +145,9 @@
         "libcutils",
         "liblog",
     ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
     cflags: [
         "-D__ANDROID_VNDK__",
     ],
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index f395b44..575ee9d 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -34,7 +34,10 @@
 namespace android {
 namespace acam {
 
-using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using frameworks::cameraservice::common::V2_0::ProviderIdAndVendorTagSections;
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
 
 // Static member definitions
 const char* CameraManagerGlobal::kCameraIdKey   = "CameraId";
@@ -43,6 +46,104 @@
 Mutex                CameraManagerGlobal::sLock;
 CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
 
+/**
+ * The vendor tag descriptor class that takes HIDL vendor tag information as
+ * input. Not part of vendor available VendorTagDescriptor class because that class is used by
+ * default HAL implementation code as well.
+ */
+class HidlVendorTagDescriptor : public VendorTagDescriptor {
+public:
+    /**
+     * Create a VendorTagDescriptor object from the HIDL VendorTagSection
+     * vector.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    static status_t createDescriptorFromHidl(const hidl_vec<VendorTagSection>& vts,
+                                             /*out*/ sp<VendorTagDescriptor> *descriptor);
+};
+
+status_t HidlVendorTagDescriptor::createDescriptorFromHidl(const hidl_vec<VendorTagSection> &vts,
+                                                           sp<VendorTagDescriptor> *descriptor) {
+    int tagCount = 0;
+
+    for (size_t s = 0; s < vts.size(); s++) {
+        tagCount += vts[s].tags.size();
+    }
+
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    Vector<uint32_t> tagArray;
+    LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+            "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+    sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    KeyedVector<uint32_t, String8> tagToSectionMap;
+
+    int idx = 0;
+    for (size_t s = 0; s < vts.size(); s++) {
+        const VendorTagSection& section = vts[s];
+        const char *sectionName = section.sectionName.c_str();
+        if (sectionName == NULL) {
+            ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
+            return BAD_VALUE;
+        }
+        String8 sectionString(sectionName);
+        desc->mSections.add(sectionString);
+
+        for (size_t j = 0; j < section.tags.size(); j++) {
+            uint32_t tag = section.tags[j].tagId;
+            if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+                ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+                return BAD_VALUE;
+            }
+
+            tagArray.editItemAt(idx++) = section.tags[j].tagId;
+
+            const char *tagName = section.tags[j].tagName.c_str();
+            if (tagName == NULL) {
+                ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+                return BAD_VALUE;
+            }
+            desc->mTagToNameMap.add(tag, String8(tagName));
+            tagToSectionMap.add(tag, sectionString);
+
+            int tagType = (int) section.tags[j].tagType;
+            if (tagType < 0 || tagType >= NUM_TYPES) {
+                ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+                return BAD_VALUE;
+            }
+            desc->mTagToTypeMap.emplace(tag, tagType);
+        }
+    }
+
+    for (size_t i = 0; i < tagArray.size(); ++i) {
+        uint32_t tag = tagArray[i];
+        String8 sectionString = tagToSectionMap.valueFor(tag);
+
+        // Set up tag to section index map
+        ssize_t index = desc->mSections.indexOf(sectionString);
+        LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+        desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+        // Set up reverse mapping
+        ssize_t reverseIndex = -1;
+        if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+            KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+            reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+        }
+        desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+    }
+
+    *descriptor = std::move(desc);
+    return OK;
+}
+
 CameraManagerGlobal&
 CameraManagerGlobal::getInstance() {
     Mutex::Autolock _l(sLock);
@@ -80,8 +181,34 @@
     return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0);
 }
 
-// TODO: Add back when vendor tags are supported for libcamera2ndk_vendor when
-//       the HIDL interface supports querying by vendor id.
+bool CameraManagerGlobal::setupVendorTags() {
+    sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
+    Status status = Status::NO_ERROR;
+    std::vector<ProviderIdAndVendorTagSections> providerIdsAndVts;
+    auto remoteRet = mCameraService->getCameraVendorTagSections([&status, &providerIdsAndVts]
+                                                                 (Status s,
+                                                                  auto &IdsAndVts) {
+                                                         status = s;
+                                                         providerIdsAndVts = IdsAndVts; });
+
+    if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+        ALOGE("Failed to retrieve VendorTagSections %s", remoteRet.description().c_str());
+        return false;
+    }
+    // Convert each providers VendorTagSections into a VendorTagDescriptor and
+    // add it to the cache
+    for (auto &providerIdAndVts : providerIdsAndVts) {
+        sp<VendorTagDescriptor> vendorTagDescriptor;
+        if (HidlVendorTagDescriptor::createDescriptorFromHidl(providerIdAndVts.vendorTagSections,
+                                                              &vendorTagDescriptor) != OK) {
+            ALOGE("Failed to convert from Hidl: VendorTagDescriptor");
+            return false;
+        }
+        tagCache->addVendorDescriptor(providerIdAndVts.providerId, vendorTagDescriptor);
+    }
+    VendorTagDescriptorCache::setAsGlobalVendorTagCache(tagCache);
+    return true;
+}
 
 sp<ICameraService> CameraManagerGlobal::getCameraService() {
     Mutex::Autolock _l(mLock);
@@ -140,6 +267,13 @@
         if (!remoteRet.isOk() || status != Status::NO_ERROR) {
             ALOGE("Failed to add listener to camera service %s", remoteRet.description().c_str());
         }
+
+        // Setup vendor tags
+        if (!setupVendorTags()) {
+            ALOGE("Unable to set up vendor tags");
+            return nullptr;
+        }
+
         for (auto& c : cameraStatuses) {
             onStatusChangedLocked(c);
         }
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index c8d640f..6b1365a 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -142,6 +142,8 @@
 
     void onStatusChanged(const CameraStatusAndId &statusAndId);
     void onStatusChangedLocked(const CameraStatusAndId &statusAndId);
+    bool setupVendorTags();
+
     // Utils for status
     static bool validStatus(CameraDeviceStatus status);
     static bool isStatusAvailable(CameraDeviceStatus status);
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index f9bb3ac..93108b0 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -37,12 +37,7 @@
 #include <media/NdkImage.h>
 #include <media/NdkImageReader.h>
 #include <cutils/native_handle.h>
-
-//#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
-//#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
-#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
-#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#include <VendorTagDescriptor.h>
 
 namespace {
 
@@ -53,6 +48,8 @@
 static constexpr int kTestImageHeight = 480;
 static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
 
+using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
+
 class CameraHelper {
    public:
     CameraHelper(const char* id, ACameraManager *manager) :
@@ -527,6 +524,8 @@
             ALOGE("Failed to get cameraIdList: ret=%d", ret);
             return;
         }
+        // TODO: Add more rigorous tests for vendor tags
+        ASSERT_NE(VendorTagDescriptorCache::getGlobalVendorTagCache(), nullptr);
         if (mCameraIdList->numCameras < 1) {
             ALOGW("Device has no camera on board.");
             return;
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index fc847ff..f4c0341 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -24,7 +24,7 @@
 #include <binder/IServiceManager.h>
 
 #include <android/hardware/drm/1.2/types.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 
 #include <media/EventMetric.h>
@@ -353,10 +353,10 @@
 Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
     Vector<sp<IDrmFactory>> factories;
 
-    auto manager = hardware::defaultServiceManager();
+    auto manager = hardware::defaultServiceManager1_2();
 
     if (manager != NULL) {
-        manager->listByInterface(drm::V1_0::IDrmFactory::descriptor,
+        manager->listManifestByInterface(drm::V1_0::IDrmFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_0::IDrmFactory::getService(instance);
@@ -366,7 +366,7 @@
                     }
                 }
             );
-        manager->listByInterface(drm::V1_1::IDrmFactory::descriptor,
+        manager->listManifestByInterface(drm::V1_1::IDrmFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_1::IDrmFactory::getService(instance);
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 590358c..596c1c8 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -515,10 +515,10 @@
         ALOGV("failed to read %zu bytes at offset %#016llx, got %zd bytes",
                 sizeof(header), (long long)offset, n);
 
-        if (n < 0) {
-            return n;
-        } else if (n == 0) {
+        if (n == 0 || n == ERROR_END_OF_STREAM) {
             return AMEDIA_ERROR_END_OF_STREAM;
+        } else if (n < 0) {
+            return AMEDIA_ERROR_UNKNOWN;
         } else {
             return AMEDIA_ERROR_IO;
         }
@@ -872,7 +872,7 @@
 
             ALOGV("readPage returned %zd", n);
 
-            return n < 0 ? (media_status_t) n : AMEDIA_ERROR_END_OF_STREAM;
+            return (media_status_t) n;
         }
 
         // Prevent a harmless unsigned integer overflow by clamping to 0
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 984c23d..c06c288 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -31,6 +31,21 @@
 constexpr int32_t AVCProfileConstrainedBaseline = 0x10000;
 constexpr int32_t AVCProfileConstrainedHigh     = 0x80000;
 
+inline static const char *asString_AVCProfile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AVCProfileBaseline:            return "Baseline";
+        case AVCProfileMain:                return "Main";
+        case AVCProfileExtended:            return "Extended";
+        case AVCProfileHigh:                return "High";
+        case AVCProfileHigh10:              return "High10";
+        case AVCProfileHigh422:             return "High422";
+        case AVCProfileHigh444:             return "High444";
+        case AVCProfileConstrainedBaseline: return "ConstrainedBaseline";
+        case AVCProfileConstrainedHigh:     return "ConstrainedHigh";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t AVCLevel1       = 0x01;
 constexpr int32_t AVCLevel1b      = 0x02;
 constexpr int32_t AVCLevel11      = 0x04;
@@ -48,6 +63,35 @@
 constexpr int32_t AVCLevel5       = 0x4000;
 constexpr int32_t AVCLevel51      = 0x8000;
 constexpr int32_t AVCLevel52      = 0x10000;
+constexpr int32_t AVCLevel6       = 0x20000;
+constexpr int32_t AVCLevel61      = 0x40000;
+constexpr int32_t AVCLevel62      = 0x80000;
+
+inline static const char *asString_AVCLevel(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AVCLevel1:     return "1";
+        case AVCLevel1b:    return "1b";
+        case AVCLevel11:    return "1.1";
+        case AVCLevel12:    return "1.2";
+        case AVCLevel13:    return "1.3";
+        case AVCLevel2:     return "2";
+        case AVCLevel21:    return "2.1";
+        case AVCLevel22:    return "2.2";
+        case AVCLevel3:     return "3";
+        case AVCLevel31:    return "3.1";
+        case AVCLevel32:    return "3.2";
+        case AVCLevel4:     return "4";
+        case AVCLevel41:    return "4.1";
+        case AVCLevel42:    return "4.2";
+        case AVCLevel5:     return "5";
+        case AVCLevel51:    return "5.1";
+        case AVCLevel52:    return "5.2";
+        case AVCLevel6:     return "6";
+        case AVCLevel61:    return "6.1";
+        case AVCLevel62:    return "6.2";
+        default:            return def;
+    }
+}
 
 constexpr int32_t H263ProfileBaseline             = 0x01;
 constexpr int32_t H263ProfileH320Coding           = 0x02;
@@ -59,6 +103,21 @@
 constexpr int32_t H263ProfileInterlace            = 0x80;
 constexpr int32_t H263ProfileHighLatency          = 0x100;
 
+inline static const char *asString_H263Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case H263ProfileBaseline:           return "Baseline";
+        case H263ProfileH320Coding:         return "H320Coding";
+        case H263ProfileBackwardCompatible: return "BackwardCompatible";
+        case H263ProfileISWV2:              return "ISWV2";
+        case H263ProfileISWV3:              return "ISWV3";
+        case H263ProfileHighCompression:    return "HighCompression";
+        case H263ProfileInternet:           return "Internet";
+        case H263ProfileInterlace:          return "Interlace";
+        case H263ProfileHighLatency:        return "HighLatency";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t H263Level10      = 0x01;
 constexpr int32_t H263Level20      = 0x02;
 constexpr int32_t H263Level30      = 0x04;
@@ -68,6 +127,20 @@
 constexpr int32_t H263Level60      = 0x40;
 constexpr int32_t H263Level70      = 0x80;
 
+inline static const char *asString_H263Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case H263Level10:   return "10";
+        case H263Level20:   return "20";
+        case H263Level30:   return "30";
+        case H263Level40:   return "40";
+        case H263Level45:   return "45";
+        case H263Level50:   return "50";
+        case H263Level60:   return "60";
+        case H263Level70:   return "70";
+        default:            return def;
+    }
+}
+
 constexpr int32_t MPEG4ProfileSimple              = 0x01;
 constexpr int32_t MPEG4ProfileSimpleScalable      = 0x02;
 constexpr int32_t MPEG4ProfileCore                = 0x04;
@@ -85,6 +158,28 @@
 constexpr int32_t MPEG4ProfileAdvancedScalable    = 0x4000;
 constexpr int32_t MPEG4ProfileAdvancedSimple      = 0x8000;
 
+inline static const char *asString_MPEG4Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG4ProfileSimple:            return "Simple";
+        case MPEG4ProfileSimpleScalable:    return "SimpleScalable";
+        case MPEG4ProfileCore:              return "Core";
+        case MPEG4ProfileMain:              return "Main";
+        case MPEG4ProfileNbit:              return "Nbit";
+        case MPEG4ProfileScalableTexture:   return "ScalableTexture";
+        case MPEG4ProfileSimpleFace:        return "SimpleFace";
+        case MPEG4ProfileSimpleFBA:         return "SimpleFBA";
+        case MPEG4ProfileBasicAnimated:     return "BasicAnimated";
+        case MPEG4ProfileHybrid:            return "Hybrid";
+        case MPEG4ProfileAdvancedRealTime:  return "AdvancedRealTime";
+        case MPEG4ProfileCoreScalable:      return "CoreScalable";
+        case MPEG4ProfileAdvancedCoding:    return "AdvancedCoding";
+        case MPEG4ProfileAdvancedCore:      return "AdvancedCore";
+        case MPEG4ProfileAdvancedScalable:  return "AdvancedScalable";
+        case MPEG4ProfileAdvancedSimple:    return "AdvancedSimple";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t MPEG4Level0      = 0x01;
 constexpr int32_t MPEG4Level0b     = 0x02;
 constexpr int32_t MPEG4Level1      = 0x04;
@@ -96,6 +191,22 @@
 constexpr int32_t MPEG4Level5      = 0x80;
 constexpr int32_t MPEG4Level6      = 0x100;
 
+inline static const char *asString_MPEG4Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG4Level0:   return "0";
+        case MPEG4Level0b:  return "0b";
+        case MPEG4Level1:   return "1";
+        case MPEG4Level2:   return "2";
+        case MPEG4Level3:   return "3";
+        case MPEG4Level3b:  return "3b";
+        case MPEG4Level4:   return "4";
+        case MPEG4Level4a:  return "4a";
+        case MPEG4Level5:   return "5";
+        case MPEG4Level6:   return "6";
+        default:            return def;
+    }
+}
+
 constexpr int32_t MPEG2ProfileSimple              = 0x00;
 constexpr int32_t MPEG2ProfileMain                = 0x01;
 constexpr int32_t MPEG2Profile422                 = 0x02;
@@ -103,12 +214,35 @@
 constexpr int32_t MPEG2ProfileSpatial             = 0x04;
 constexpr int32_t MPEG2ProfileHigh                = 0x05;
 
+inline static const char *asString_MPEG2Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG2ProfileSimple:    return "Simple";
+        case MPEG2ProfileMain:      return "Main";
+        case MPEG2Profile422:       return "422";
+        case MPEG2ProfileSNR:       return "SNR";
+        case MPEG2ProfileSpatial:   return "Spatial";
+        case MPEG2ProfileHigh:      return "High";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t MPEG2LevelLL     = 0x00;
 constexpr int32_t MPEG2LevelML     = 0x01;
 constexpr int32_t MPEG2LevelH14    = 0x02;
 constexpr int32_t MPEG2LevelHL     = 0x03;
 constexpr int32_t MPEG2LevelHP     = 0x04;
 
+inline static const char *asString_MPEG2Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case MPEG2LevelLL:  return "LL";
+        case MPEG2LevelML:  return "ML";
+        case MPEG2LevelH14: return "H14";
+        case MPEG2LevelHL:  return "HL";
+        case MPEG2LevelHP:  return "HP";
+        default:            return def;
+    }
+}
+
 constexpr int32_t AACObjectMain       = 1;
 constexpr int32_t AACObjectLC         = 2;
 constexpr int32_t AACObjectSSR        = 3;
@@ -122,13 +256,48 @@
 constexpr int32_t AACObjectELD        = 39;
 constexpr int32_t AACObjectXHE        = 42;
 
+inline static const char *asString_AACObject(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AACObjectMain:         return "Main";
+        case AACObjectLC:           return "LC";
+        case AACObjectSSR:          return "SSR";
+        case AACObjectLTP:          return "LTP";
+        case AACObjectHE:           return "HE";
+        case AACObjectScalable:     return "Scalable";
+        case AACObjectERLC:         return "ERLC";
+        case AACObjectERScalable:   return "ERScalable";
+        case AACObjectLD:           return "LD";
+        case AACObjectHE_PS:        return "HE_PS";
+        case AACObjectELD:          return "ELD";
+        case AACObjectXHE:          return "XHE";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t VP8Level_Version0 = 0x01;
 constexpr int32_t VP8Level_Version1 = 0x02;
 constexpr int32_t VP8Level_Version2 = 0x04;
 constexpr int32_t VP8Level_Version3 = 0x08;
 
+inline static const char *asString_VP8Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP8Level_Version0: return "V0";
+        case VP8Level_Version1: return "V1";
+        case VP8Level_Version2: return "V2";
+        case VP8Level_Version3: return "V3";
+        default:                return def;
+    }
+}
+
 constexpr int32_t VP8ProfileMain = 0x01;
 
+inline static const char *asString_VP8Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP8ProfileMain:    return "Main";
+        default:                return def;
+    }
+}
+
 constexpr int32_t VP9Profile0 = 0x01;
 constexpr int32_t VP9Profile1 = 0x02;
 constexpr int32_t VP9Profile2 = 0x04;
@@ -138,6 +307,20 @@
 constexpr int32_t VP9Profile2HDR10Plus = 0x4000;
 constexpr int32_t VP9Profile3HDR10Plus = 0x8000;
 
+inline static const char *asString_VP9Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP9Profile0:           return "0";
+        case VP9Profile1:           return "1";
+        case VP9Profile2:           return "2";
+        case VP9Profile3:           return "3";
+        case VP9Profile2HDR:        return "2HDR";
+        case VP9Profile3HDR:        return "3HDR";
+        case VP9Profile2HDR10Plus:  return "2HDRPlus";
+        case VP9Profile3HDR10Plus:  return "3HDRPlus";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t VP9Level1  = 0x1;
 constexpr int32_t VP9Level11 = 0x2;
 constexpr int32_t VP9Level2  = 0x4;
@@ -153,10 +336,39 @@
 constexpr int32_t VP9Level61 = 0x1000;
 constexpr int32_t VP9Level62 = 0x2000;
 
+inline static const char *asString_VP9Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case VP9Level1:     return "1";
+        case VP9Level11:    return "1.1";
+        case VP9Level2:     return "2";
+        case VP9Level21:    return "2.1";
+        case VP9Level3:     return "3";
+        case VP9Level31:    return "3.1";
+        case VP9Level4:     return "4";
+        case VP9Level41:    return "4.1";
+        case VP9Level5:     return "5";
+        case VP9Level51:    return "5.1";
+        case VP9Level52:    return "5.2";
+        case VP9Level6:     return "6";
+        case VP9Level61:    return "6.1";
+        case VP9Level62:    return "6.2";
+        default:            return def;
+    }
+}
+
 constexpr int32_t AV1Profile0 = 0x01;
 constexpr int32_t AV1Profile1 = 0x02;
 constexpr int32_t AV1Profile2 = 0x04;
 
+inline static const char *asString_AV1Profile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AV1Profile0:       return "0";
+        case AV1Profile1:       return "1";
+        case AV1Profile2:       return "2";
+        default:                return def;
+    }
+}
+
 constexpr int32_t AV1Level2  = 0x1;
 constexpr int32_t AV1Level21 = 0x2;
 constexpr int32_t AV1Level22 = 0x4;
@@ -182,12 +394,53 @@
 constexpr int32_t AV1Level72 = 0x400000;
 constexpr int32_t AV1Level73 = 0x800000;
 
+inline static const char *asString_AV1Level(int32_t i, const char *def = "??") {
+    switch (i) {
+        case AV1Level2:     return "2";
+        case AV1Level21:    return "2.1";
+        case AV1Level22:    return "2.2";
+        case AV1Level23:    return "2.3";
+        case AV1Level3:     return "3";
+        case AV1Level31:    return "3.1";
+        case AV1Level32:    return "3.2";
+        case AV1Level33:    return "3.3";
+        case AV1Level4:     return "4";
+        case AV1Level41:    return "4.1";
+        case AV1Level42:    return "4.2";
+        case AV1Level43:    return "4.3";
+        case AV1Level5:     return "5";
+        case AV1Level51:    return "5.1";
+        case AV1Level52:    return "5.2";
+        case AV1Level53:    return "5.3";
+        case AV1Level6:     return "6";
+        case AV1Level61:    return "6.1";
+        case AV1Level62:    return "6.2";
+        case AV1Level63:    return "6.3";
+        case AV1Level7:     return "7";
+        case AV1Level71:    return "7.1";
+        case AV1Level72:    return "7.2";
+        case AV1Level73:    return "7.3";
+        default:            return def;
+    }
+}
+
 constexpr int32_t HEVCProfileMain        = 0x01;
 constexpr int32_t HEVCProfileMain10      = 0x02;
 constexpr int32_t HEVCProfileMainStill   = 0x04;
 constexpr int32_t HEVCProfileMain10HDR10 = 0x1000;
 constexpr int32_t HEVCProfileMain10HDR10Plus = 0x2000;
 
+inline static const char *asString_HEVCProfile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case HEVCProfileMain:               return "Main";
+        case HEVCProfileMain10:             return "Main10";
+        case HEVCProfileMainStill:          return "MainStill";
+        case HEVCProfileMain10HDR10:        return "Main10HDR10";
+        case HEVCProfileMain10HDR10Plus:    return "Main10HDR10Plus";
+        default:                            return def;
+    }
+}
+
 constexpr int32_t HEVCMainTierLevel1  = 0x1;
 constexpr int32_t HEVCHighTierLevel1  = 0x2;
 constexpr int32_t HEVCMainTierLevel2  = 0x4;
@@ -215,6 +468,38 @@
 constexpr int32_t HEVCMainTierLevel62 = 0x1000000;
 constexpr int32_t HEVCHighTierLevel62 = 0x2000000;
 
+inline static const char *asString_HEVCTierLevel(int32_t i, const char *def = "??") {
+    switch (i) {
+        case HEVCMainTierLevel1:    return "Main 1";
+        case HEVCHighTierLevel1:    return "High 1";
+        case HEVCMainTierLevel2:    return "Main 2";
+        case HEVCHighTierLevel2:    return "High 2";
+        case HEVCMainTierLevel21:   return "Main 2.1";
+        case HEVCHighTierLevel21:   return "High 2.1";
+        case HEVCMainTierLevel3:    return "Main 3";
+        case HEVCHighTierLevel3:    return "High 3";
+        case HEVCMainTierLevel31:   return "Main 3.1";
+        case HEVCHighTierLevel31:   return "High 3.1";
+        case HEVCMainTierLevel4:    return "Main 4";
+        case HEVCHighTierLevel4:    return "High 4";
+        case HEVCMainTierLevel41:   return "Main 4.1";
+        case HEVCHighTierLevel41:   return "High 4.1";
+        case HEVCMainTierLevel5:    return "Main 5";
+        case HEVCHighTierLevel5:    return "High 5";
+        case HEVCMainTierLevel51:   return "Main 5.1";
+        case HEVCHighTierLevel51:   return "High 5.1";
+        case HEVCMainTierLevel52:   return "Main 5.2";
+        case HEVCHighTierLevel52:   return "High 5.2";
+        case HEVCMainTierLevel6:    return "Main 6";
+        case HEVCHighTierLevel6:    return "High 6";
+        case HEVCMainTierLevel61:   return "Main 6.1";
+        case HEVCHighTierLevel61:   return "High 6.1";
+        case HEVCMainTierLevel62:   return "Main 6.2";
+        case HEVCHighTierLevel62:   return "High 6.2";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t DolbyVisionProfileDvavPer = 0x1;
 constexpr int32_t DolbyVisionProfileDvavPen = 0x2;
 constexpr int32_t DolbyVisionProfileDvheDer = 0x4;
@@ -226,6 +511,22 @@
 constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
 constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
 
+inline static const char *asString_DolbyVisionProfile(int32_t i, const char *def = "??") {
+    switch (i) {
+        case DolbyVisionProfileDvavPer: return "DvavPer";
+        case DolbyVisionProfileDvavPen: return "DvavPen";
+        case DolbyVisionProfileDvheDer: return "DvheDer";
+        case DolbyVisionProfileDvheDen: return "DvheDen";
+        case DolbyVisionProfileDvheDtr: return "DvheDtr";
+        case DolbyVisionProfileDvheStn: return "DvheStn";
+        case DolbyVisionProfileDvheDth: return "DvheDth";
+        case DolbyVisionProfileDvheDtb: return "DvheDtb";
+        case DolbyVisionProfileDvheSt:  return "DvheSt";
+        case DolbyVisionProfileDvavSe:  return "DvavSe";
+        default:                        return def;
+    }
+}
+
 constexpr int32_t DolbyVisionLevelHd24    = 0x1;
 constexpr int32_t DolbyVisionLevelHd30    = 0x2;
 constexpr int32_t DolbyVisionLevelFhd24   = 0x4;
@@ -236,10 +537,34 @@
 constexpr int32_t DolbyVisionLevelUhd48   = 0x80;
 constexpr int32_t DolbyVisionLevelUhd60   = 0x100;
 
+inline static const char *asString_DolbyVisionLevel(int32_t i, const char *def = "??") {
+    switch (i) {
+        case DolbyVisionLevelHd24:  return "Hd24";
+        case DolbyVisionLevelHd30:  return "Hd30";
+        case DolbyVisionLevelFhd24: return "Fhd24";
+        case DolbyVisionLevelFhd30: return "Fhd30";
+        case DolbyVisionLevelFhd60: return "Fhd60";
+        case DolbyVisionLevelUhd24: return "Uhd24";
+        case DolbyVisionLevelUhd30: return "Uhd30";
+        case DolbyVisionLevelUhd48: return "Uhd48";
+        case DolbyVisionLevelUhd60: return "Uhd60";
+        default:                    return def;
+    }
+}
+
 constexpr int32_t BITRATE_MODE_CBR = 2;
 constexpr int32_t BITRATE_MODE_CQ = 0;
 constexpr int32_t BITRATE_MODE_VBR = 1;
 
+inline static const char *asString_BitrateMode(int32_t i, const char *def = "??") {
+    switch (i) {
+        case BITRATE_MODE_CBR:  return "CBR";
+        case BITRATE_MODE_CQ:   return "CQ";
+        case BITRATE_MODE_VBR:  return "VBR";
+        default:                return def;
+    }
+}
+
 constexpr int32_t COLOR_Format12bitRGB444             = 3;
 constexpr int32_t COLOR_Format16bitARGB1555           = 5;
 constexpr int32_t COLOR_Format16bitARGB4444           = 4;
@@ -293,6 +618,64 @@
 constexpr int32_t COLOR_QCOM_FormatYUV420SemiPlanar   = 0x7fa30c00;
 constexpr int32_t COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
 
+inline static const char *asString_ColorFormat(int32_t i, const char *def = "??") {
+    switch (i) {
+        case COLOR_Format12bitRGB444:               return "12bitRGB444";
+        case COLOR_Format16bitARGB1555:             return "16bitARGB1555";
+        case COLOR_Format16bitARGB4444:             return "16bitARGB4444";
+        case COLOR_Format16bitBGR565:               return "16bitBGR565";
+        case COLOR_Format16bitRGB565:               return "16bitRGB565";
+        case COLOR_Format18bitARGB1665:             return "18bitARGB1665";
+        case COLOR_Format18BitBGR666:               return "18BitBGR666";
+        case COLOR_Format18bitRGB666:               return "18bitRGB666";
+        case COLOR_Format19bitARGB1666:             return "19bitARGB1666";
+        case COLOR_Format24BitABGR6666:             return "24BitABGR6666";
+        case COLOR_Format24bitARGB1887:             return "24bitARGB1887";
+        case COLOR_Format24BitARGB6666:             return "24BitARGB6666";
+        case COLOR_Format24bitBGR888:               return "24bitBGR888";
+        case COLOR_Format24bitRGB888:               return "24bitRGB888";
+        case COLOR_Format25bitARGB1888:             return "25bitARGB1888";
+        case COLOR_Format32bitABGR8888:             return "32bitABGR8888";
+        case COLOR_Format32bitARGB8888:             return "32bitARGB8888";
+        case COLOR_Format32bitBGRA8888:             return "32bitBGRA8888";
+        case COLOR_Format8bitRGB332:                return "8bitRGB332";
+        case COLOR_FormatCbYCrY:                    return "CbYCrY";
+        case COLOR_FormatCrYCbY:                    return "CrYCbY";
+        case COLOR_FormatL16:                       return "L16";
+        case COLOR_FormatL2:                        return "L2";
+        case COLOR_FormatL24:                       return "L24";
+        case COLOR_FormatL32:                       return "L32";
+        case COLOR_FormatL4:                        return "L4";
+        case COLOR_FormatL8:                        return "L8";
+        case COLOR_FormatMonochrome:                return "Monochrome";
+        case COLOR_FormatRawBayer10bit:             return "RawBayer10bit";
+        case COLOR_FormatRawBayer8bit:              return "RawBayer8bit";
+        case COLOR_FormatRawBayer8bitcompressed:    return "RawBayer8bitcompressed";
+        case COLOR_FormatRGBAFlexible:              return "RGBAFlexible";
+        case COLOR_FormatRGBFlexible:               return "RGBFlexible";
+        case COLOR_FormatSurface:                   return "Surface";
+        case COLOR_FormatYCbYCr:                    return "YCbYCr";
+        case COLOR_FormatYCrYCb:                    return "YCrYCb";
+        case COLOR_FormatYUV411PackedPlanar:        return "YUV411PackedPlanar";
+        case COLOR_FormatYUV411Planar:              return "YUV411Planar";
+        case COLOR_FormatYUV420Flexible:            return "YUV420Flexible";
+        case COLOR_FormatYUV420PackedPlanar:        return "YUV420PackedPlanar";
+        case COLOR_FormatYUV420PackedSemiPlanar:    return "YUV420PackedSemiPlanar";
+        case COLOR_FormatYUV420Planar:              return "YUV420Planar";
+        case COLOR_FormatYUV420SemiPlanar:          return "YUV420SemiPlanar";
+        case COLOR_FormatYUV422Flexible:            return "YUV422Flexible";
+        case COLOR_FormatYUV422PackedPlanar:        return "YUV422PackedPlanar";
+        case COLOR_FormatYUV422PackedSemiPlanar:    return "YUV422PackedSemiPlanar";
+        case COLOR_FormatYUV422Planar:              return "YUV422Planar";
+        case COLOR_FormatYUV422SemiPlanar:          return "YUV422SemiPlanar";
+        case COLOR_FormatYUV444Flexible:            return "YUV444Flexible";
+        case COLOR_FormatYUV444Interleaved:         return "YUV444Interleaved";
+        case COLOR_QCOM_FormatYUV420SemiPlanar:     return "QCOM_YUV420SemiPlanar";
+        case COLOR_TI_FormatYUV420PackedSemiPlanar: return "TI_YUV420PackedSemiPlanar";
+        default:                                    return def;
+    }
+}
+
 constexpr char FEATURE_AdaptivePlayback[]       = "adaptive-playback";
 constexpr char FEATURE_IntraRefresh[] = "intra-refresh";
 constexpr char FEATURE_PartialFrame[] = "partial-frame";
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 538a0eb..63a9ec4 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -322,6 +322,13 @@
                         }
                     }
                     status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+                    // remove stale audio patch with same input as sink if any
+                    for (auto& iter : mPatches) {
+                        if (iter.second.mAudioPatch.sinks[0].ext.mix.handle == thread->id()) {
+                            mPatches.erase(iter.first);
+                            break;
+                        }
+                    }
                 } else {
                     sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
                     status = hwDevice->createAudioPatch(patch->num_sources,
@@ -376,6 +383,14 @@
             }
 
             status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+
+            // remove stale audio patch with same output as source if any
+            for (auto& iter : mPatches) {
+                if (iter.second.mAudioPatch.sources[0].ext.mix.handle == thread->id()) {
+                    mPatches.erase(iter.first);
+                    break;
+                }
+            }
         } break;
         default:
             status = BAD_VALUE;
diff --git a/services/mediacodec/MediaCodecUpdateService.cpp b/services/mediacodec/MediaCodecUpdateService.cpp
index aee890d..0e6892d 100644
--- a/services/mediacodec/MediaCodecUpdateService.cpp
+++ b/services/mediacodec/MediaCodecUpdateService.cpp
@@ -18,14 +18,10 @@
 //#define LOG_NDEBUG 0
 
 #include <android/dlext.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <dirent.h>
 #include <dlfcn.h>
 #include <media/CodecServiceRegistrant.h>
 #include <utils/Log.h>
-#include <ziparchive/zip_archive.h>
-#include <cutils/properties.h>
+#include <utils/String8.h>
 
 #include "MediaCodecUpdateService.h"
 
@@ -47,90 +43,53 @@
 }
 
 namespace android {
-namespace media {
 
-binder::Status MediaCodecUpdateService::loadPlugins(const ::std::string& apkPath) {
-    ALOGV("loadPlugins %s", apkPath.c_str());
+void loadFromApex(const char *libDirPath) {
+    ALOGV("loadFromApex: path=%s", libDirPath);
 
-    ZipArchiveHandle zipHandle;
-    void *registrantLib = NULL;
-    int32_t ret = OpenArchive(apkPath.c_str(), &zipHandle);
+    String8 libPath = String8(libDirPath) + "/libmedia_codecserviceregistrant.so";
 
-    if (ret == 0) {
-        char abilist32[PROPERTY_VALUE_MAX];
-        property_get("ro.product.cpu.abilist32", abilist32, "armeabi-v7a");
+    android_namespace_t *codecNs = android_create_namespace("codecs",
+            nullptr,  // ld_library_path
+            libDirPath,
+            ANDROID_NAMESPACE_TYPE_ISOLATED,
+            nullptr,  // permitted_when_isolated_path
+            nullptr); // parent
 
-        auto abis = base::Split(abilist32, ",");
-        if (abis.empty()) {
-            ALOGW("abilist is empty, trying armeabi-v7a ...");
-            abis.push_back("armeabi-v7a");
-        }
-
-        // TODO: Only try the first entry in abilist32 for now.
-        // We probably should try the next if it fails.
-        String8 libPathInApk = String8("lib/") + String8(abis[0].c_str());
-        String8 defaultLibPath = String8(apkPath.c_str()) + "!/" + libPathInApk;
-        String8 libPath = defaultLibPath + "/libmedia_codecserviceregistrant.so";
-        String8 zipEntryPath = libPathInApk + "/libmedia_codecserviceregistrant.so";
-
-        ZipEntry entry;
-        ret = FindEntry(zipHandle, ZipString(zipEntryPath), &entry);
-
-        if (ret == 0) {
-            android_namespace_t *codecNs = android_create_namespace("codecs",
-                    nullptr,  // ld_library_path
-                    defaultLibPath.c_str(),
-                    ANDROID_NAMESPACE_TYPE_ISOLATED,
-                    nullptr,  // permitted_when_isolated_path
-                    nullptr); // parent
-
-            if (codecNs != nullptr) {
-                String8 linked_libraries(LINKED_LIBRARIES);
-                if (android_link_namespaces(
-                        codecNs, nullptr, linked_libraries.c_str())) {
-                    const android_dlextinfo dlextinfo = {
-                            .flags = ANDROID_DLEXT_USE_NAMESPACE,
-                            .library_namespace = codecNs,
-                    };
-
-                    registrantLib = android_dlopen_ext(
-                            libPath.string(),
-                            RTLD_NOW | RTLD_LOCAL, &dlextinfo);
-
-                    if (registrantLib == NULL) {
-                        ALOGE("Failed to load lib from archive: %s", dlerror());
-                    }
-                } else {
-                    ALOGE("Failed to link namespace");
-                }
-            } else {
-                ALOGE("Failed to create codec namespace");
-            }
-        } else {
-            ALOGE("Failed to find entry (ret=%d)", ret);
-        }
-
-        CloseArchive(zipHandle);
-    } else {
-        ALOGE("Failed to open archive (ret=%d)", ret);
+    if (codecNs == nullptr) {
+        ALOGE("Failed to create codec namespace");
+        return;
     }
 
-    if (registrantLib) {
-        RegisterCodecServicesFunc registerCodecServices =
-                reinterpret_cast<RegisterCodecServicesFunc>(
-                dlsym(registrantLib, "RegisterCodecServices"));
-        if (registerCodecServices) {
-            registerCodecServices();
-        } else {
-            LOG(WARNING) << "Cannot register codec services "
-                    "-- corrupted library.";
-        }
-    } else {
-        LOG(ERROR) << "Cannot find codec service registrant.";
+    String8 linked_libraries(LINKED_LIBRARIES);
+    if (!android_link_namespaces(codecNs, nullptr, linked_libraries.c_str())) {
+        ALOGE("Failed to link namespace");
+        return;
     }
 
-    return binder::Status::ok();
+    const android_dlextinfo dlextinfo = {
+            .flags = ANDROID_DLEXT_USE_NAMESPACE,
+            .library_namespace = codecNs,
+    };
+
+    void *registrantLib = android_dlopen_ext(
+            libPath.string(),
+            RTLD_NOW | RTLD_LOCAL, &dlextinfo);
+
+    if (registrantLib == nullptr) {
+        ALOGE("Failed to load lib from archive: %s", dlerror());
+    }
+
+    RegisterCodecServicesFunc registerCodecServices =
+            reinterpret_cast<RegisterCodecServicesFunc>(
+            dlsym(registrantLib, "RegisterCodecServices"));
+
+    if (registerCodecServices == nullptr) {
+        ALOGE("Cannot register codec services -- corrupted library.");
+        return;
+    }
+
+    registerCodecServices();
 }
 
-}   // namespace media
 }   // namespace android
diff --git a/services/mediacodec/MediaCodecUpdateService.h b/services/mediacodec/MediaCodecUpdateService.h
index 7b7cee9..09d6dbe 100644
--- a/services/mediacodec/MediaCodecUpdateService.h
+++ b/services/mediacodec/MediaCodecUpdateService.h
@@ -17,24 +17,10 @@
 #ifndef ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
 #define ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
 
-#include <binder/BinderService.h>
-#include <android/media/BnMediaUpdateService.h>
-
 namespace android {
-namespace media {
 
-class MediaCodecUpdateService
-    : public BinderService<MediaCodecUpdateService>, public BnMediaUpdateService
-{
-    friend class BinderService<MediaCodecUpdateService>;
-public:
-    MediaCodecUpdateService() : BnMediaUpdateService() { }
-    virtual ~MediaCodecUpdateService() { }
-    static const char* getServiceName() { return "media.codec.update"; }
-    binder::Status loadPlugins(const ::std::string& apkPath);
-};
+void loadFromApex(const char *libDirPath);
 
-}   // namespace media
 }   // namespace android
 
 #endif  // ANDROID_MEDIA_CODEC_UPDATE_SERVICE_H
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index 79fea25..1168825 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -20,11 +20,7 @@
 // from LOCAL_C_INCLUDES
 #include "minijail.h"
 
-#include <android-base/properties.h>
-#include <binder/ProcessState.h>
-#include <dlfcn.h>
 #include <hidl/HidlTransportSupport.h>
-#include <media/CodecServiceRegistrant.h>
 
 #include "MediaCodecUpdateService.h"
 
@@ -49,32 +45,10 @@
     signal(SIGPIPE, SIG_IGN);
     SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
 
-    std::string value = base::GetProperty("ro.build.type", "unknown");
-    if (value == "userdebug" || value == "eng") {
-        media::MediaCodecUpdateService::instantiate();
-    }
-
-    android::ProcessState::self()->startThreadPool();
-
     ::android::hardware::configureRpcThreadpool(64, false);
 
-    // Registration of customized codec services
-    void *registrantLib = dlopen(
-            "libmedia_codecserviceregistrant.so",
-            RTLD_NOW | RTLD_LOCAL);
-    if (registrantLib) {
-        RegisterCodecServicesFunc registerCodecServices =
-                reinterpret_cast<RegisterCodecServicesFunc>(
-                dlsym(registrantLib, "RegisterCodecServices"));
-        if (registerCodecServices) {
-            registerCodecServices();
-        } else {
-            LOG(WARNING) << "Cannot register codec services "
-                    "-- corrupted library.";
-        }
-    } else {
-        LOG(ERROR) << "Cannot find codec service registrant.";
-    }
+    // codec libs are currently 32-bit only
+    loadFromApex("/apex/com.android.media.swcodec/lib");
 
     ::android::hardware::joinRpcThreadpool();
 }