Merge "cameraserver: rename getConcurrentStreamingCameraIds -> getConcurrentCameraIds." into rvc-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index 140a2e8..259558c 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -14,6 +14,7 @@
 
 apex_defaults {
     name: "com.android.media-defaults",
+    updatable: true,
     java_libs: ["updatable-media"],
     multilib: {
         first: {
@@ -43,7 +44,7 @@
 
     // Use a custom AndroidManifest.xml used for API targeting.
     androidManifest: ":com.android.media-androidManifest",
-
+    min_sdk_version: "29",
     legacy_android10_support: true,
 }
 
@@ -65,6 +66,7 @@
 
 apex_defaults {
     name: "com.android.media.swcodec-defaults",
+    updatable: true,
     binaries: [
         "mediaswcodec",
     ],
@@ -82,7 +84,7 @@
 
     // Use a custom AndroidManifest.xml used for API targeting.
     androidManifest: ":com.android.media.swcodec-androidManifest",
-
+    min_sdk_version: "29",
     legacy_android10_support: true,
 }
 
diff --git a/camera/aidl/android/hardware/ICameraServiceListener.aidl b/camera/aidl/android/hardware/ICameraServiceListener.aidl
index 81657fd..c54813c 100644
--- a/camera/aidl/android/hardware/ICameraServiceListener.aidl
+++ b/camera/aidl/android/hardware/ICameraServiceListener.aidl
@@ -89,4 +89,12 @@
      * can retry after receiving this callback.
      */
     oneway void onCameraAccessPrioritiesChanged();
+
+    /**
+     * Notify registered clients about cameras being opened/closed.
+     * Only clients with android.permission.CAMERA_OPEN_CLOSE_LISTENER permission
+     * will receive such callbacks.
+     */
+    oneway void onCameraOpened(String cameraId, String clientPackageId);
+    oneway void onCameraClosed(String cameraId);
 }
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 836e037..7fba188 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -97,6 +97,12 @@
         }
 
         virtual binder::Status onCameraAccessPrioritiesChanged();
+        virtual binder::Status onCameraOpened(const String16&, const String16&) {
+            return binder::Status::ok();
+        }
+        virtual binder::Status onCameraClosed(const String16&) {
+            return binder::Status::ok();
+        }
 
       private:
         const wp<CameraManagerGlobal> mCameraManager;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index a95fe2a..e2097b5 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -735,9 +735,8 @@
 
     if (!serviceRet.isOk() || status != Status::NO_ERROR) {
         ALOGE("%s: connect camera device failed", __FUNCTION__);
-        // TODO: Convert serviceRet to camera_status_t
         delete device;
-        return ACAMERA_ERROR_UNKNOWN;
+        return utils::convertFromHidl(status);
     }
     if (deviceRemote == nullptr) {
         ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 571cf59..8ccded2 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -101,6 +101,17 @@
         return binder::Status::ok();
     }
 
+    virtual binder::Status onCameraOpened(const String16& /*cameraId*/,
+            const String16& /*clientPackageName*/) {
+        // No op
+        return binder::Status::ok();
+    }
+
+    virtual binder::Status onCameraClosed(const String16& /*cameraId*/) {
+        // No op
+        return binder::Status::ok();
+    }
+
     bool waitForNumCameras(size_t num) const {
         Mutex::Autolock l(mLock);
 
diff --git a/media/codec2/OWNERS b/media/codec2/OWNERS
new file mode 100644
index 0000000..46a9fca
--- /dev/null
+++ b/media/codec2/OWNERS
@@ -0,0 +1,5 @@
+set noparent
+wonsik@google.com
+lajos@google.com
+pawin@google.com
+taklee@google.com
diff --git a/media/codec2/components/vorbis/Android.bp b/media/codec2/components/vorbis/Android.bp
index a5f485d..bc1c380 100644
--- a/media/codec2/components/vorbis/Android.bp
+++ b/media/codec2/components/vorbis/Android.bp
@@ -7,5 +7,5 @@
 
     srcs: ["C2SoftVorbisDec.cpp"],
 
-    shared_libs: ["libvorbisidec"],
+    static_libs: ["libvorbisidec"],
 }
diff --git a/media/codec2/core/OWNERS b/media/codec2/core/OWNERS
new file mode 100644
index 0000000..31ecca5
--- /dev/null
+++ b/media/codec2/core/OWNERS
@@ -0,0 +1,2 @@
+set noparent
+lajos@google.com
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 74fdc8b..9fc0e17 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -59,7 +59,6 @@
     enum drc_compression_mode_t : int32_t;  ///< DRC compression mode
     enum drc_effect_type_t : int32_t;       ///< DRC effect type
     enum drc_album_mode_t : int32_t;        ///< DRC album mode
-    enum drc_output_loudness : int32_t;     ///< DRC output loudness
     enum intra_refresh_mode_t : uint32_t;   ///< intra refresh modes
     enum level_t : uint32_t;                ///< coding level
     enum ordinal_key_t : uint32_t;          ///< work ordering keys
@@ -248,7 +247,7 @@
 
     kParamIndexSurfaceAllocator, // u32
 
-    // low latency mode for decoders
+    // low latency mode
     kParamIndexLowLatencyMode, // bool
 };
 
@@ -812,9 +811,10 @@
 constexpr char C2_PARAMKEY_PIPELINE_DELAY[] = "algo.delay";
 
 /**
- * Enable/disable low latency decoding mode.
- * If true, low latency decoding mode is enabled, and the decoder doesn't hold input and output
- * data more than required by the codec standards.
+ * Enable/disable low latency mode.
+ * If true, low latency is preferred over low power. Disable power optimizations that
+ * may result in increased latency. For decoders, this means that the decoder does not
+ * hold input and output data more than required by the codec standards.
  */
 typedef C2GlobalParam<C2Tuning, C2EasyBoolValue, kParamIndexLowLatencyMode>
         C2GlobalLowLatencyModeTuning;
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 9656eb4..20f4665 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -71,7 +71,8 @@
         mDisableTest = false;
         ALOGV("Codec2AudioDecHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str());
+            gEnv->getInstance().c_str(),
+            !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
         mListener.reset(new CodecListener(
             [this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index 01baf7e..ab6bfb2 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -65,7 +65,8 @@
         mDisableTest = false;
         ALOGV("Codec2AudioEncHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str());
+            gEnv->getInstance().c_str(),
+            !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
         mListener.reset(new CodecListener(
             [this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 9404aa8..256603c 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -78,7 +78,8 @@
         mDisableTest = false;
         ALOGV("Codec2VideoDecHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str());
+            gEnv->getInstance().c_str(),
+            !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
         mListener.reset(new CodecListener(
             [this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index c1f5a92..15f6acd 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -64,7 +64,8 @@
         mDisableTest = false;
         ALOGV("Codec2VideoEncHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str());
+            gEnv->getInstance().c_str(),
+            !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
         mListener.reset(new CodecListener(
             [this](std::list<std::unique_ptr<C2Work>>& workItems) {
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 199a99c..0acab49 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -93,6 +93,69 @@
     return i;
 }
 
+class Client2Store : public C2ComponentStore {
+    std::shared_ptr<Codec2Client> mClient;
+
+public:
+    Client2Store(std::shared_ptr<Codec2Client> const& client)
+        : mClient(client) { }
+
+    virtual ~Client2Store() = default;
+
+    virtual c2_status_t config_sm(
+            std::vector<C2Param*> const &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
+        return mClient->config(params, C2_MAY_BLOCK, failures);
+    };
+
+    virtual c2_status_t copyBuffer(
+            std::shared_ptr<C2GraphicBuffer>,
+            std::shared_ptr<C2GraphicBuffer>) {
+        return C2_OMITTED;
+    }
+
+    virtual c2_status_t createComponent(
+            C2String, std::shared_ptr<C2Component>* const component) {
+        component->reset();
+        return C2_OMITTED;
+    }
+
+    virtual c2_status_t createInterface(
+            C2String, std::shared_ptr<C2ComponentInterface>* const interface) {
+        interface->reset();
+        return C2_OMITTED;
+    }
+
+    virtual c2_status_t query_sm(
+            std::vector<C2Param*> const& stackParams,
+            std::vector<C2Param::Index> const& heapParamIndices,
+            std::vector<std::unique_ptr<C2Param>>* const heapParams) const {
+        return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
+    }
+
+    virtual c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
+        return mClient->querySupportedParams(params);
+    }
+
+    virtual c2_status_t querySupportedValues_sm(
+            std::vector<C2FieldSupportedValuesQuery>& fields) const {
+        return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
+    }
+
+    virtual C2String getName() const {
+        return mClient->getName();
+    }
+
+    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
+        return mClient->getParamReflector();
+    }
+
+    virtual std::vector<std::shared_ptr<C2Component::Traits const>> listComponents() {
+        return std::vector<std::shared_ptr<C2Component::Traits const>>();
+    }
+};
+
 }  // unnamed namespace
 
 // This class caches a Codec2Client object and its component traits. The client
@@ -615,8 +678,13 @@
                    << ") -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     } else if (status != C2_OK) {
-        LOG(ERROR) << "createComponent(" << name.c_str()
-                   << ") -- call failed: " << status << ".";
+        if (status == C2_NOT_FOUND) {
+            LOG(VERBOSE) << "createComponent(" << name.c_str()
+                         << ") -- component not found.";
+        } else {
+            LOG(ERROR) << "createComponent(" << name.c_str()
+                       << ") -- call failed: " << status << ".";
+        }
         return status;
     } else if (!*component) {
         LOG(ERROR) << "createComponent(" << name.c_str()
@@ -655,8 +723,13 @@
                    << ") -- transaction failed.";
         return C2_TRANSACTION_FAILED;
     } else if (status != C2_OK) {
-        LOG(ERROR) << "createComponent(" << name.c_str()
-                   << ") -- call failed: " << status << ".";
+        if (status == C2_NOT_FOUND) {
+            LOG(VERBOSE) << "createInterface(" << name.c_str()
+                         << ") -- component not found.";
+        } else {
+            LOG(ERROR) << "createInterface(" << name.c_str()
+                       << ") -- call failed: " << status << ".";
+        }
         return status;
     }
 
@@ -850,10 +923,24 @@
 }
 
 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
-        const char* name) {
+        const char* name,
+        bool setAsPreferredCodec2ComponentStore) {
     size_t index = getServiceIndex(name);
-    return index == GetServiceNames().size() ?
-            nullptr : _CreateFromIndex(index);
+    if (index == GetServiceNames().size()) {
+        if (setAsPreferredCodec2ComponentStore) {
+            LOG(WARNING) << "CreateFromService(" << name
+                         << ") -- preferred C2ComponentStore not set.";
+        }
+        return nullptr;
+    }
+    std::shared_ptr<Codec2Client> client = _CreateFromIndex(index);
+    if (setAsPreferredCodec2ComponentStore) {
+        SetPreferredCodec2ComponentStore(
+                std::make_shared<Client2Store>(client));
+        LOG(INFO) << "CreateFromService(" << name
+                  << ") -- service set as preferred C2ComponentStore.";
+    }
+    return client;
 }
 
 std::vector<std::shared_ptr<Codec2Client>> Codec2Client::
@@ -869,11 +956,11 @@
 
 std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
     std::string const& name = GetServiceNames()[index];
-    LOG(INFO) << "Creating a Codec2 client to service \"" << name << "\"";
+    LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
     sp<Base> baseStore = Base::getService(name);
     CHECK(baseStore) << "Codec2 service \"" << name << "\""
                         " inaccessible for unknown reasons.";
-    LOG(INFO) << "Client to Codec2 service \"" << name << "\" created";
+    LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
     return std::make_shared<Codec2Client>(baseStore, index);
 }
 
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 649dffd..ffd194a 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -184,8 +184,15 @@
     // Note: A software service will have "_software" as a suffix.
     static std::vector<std::string> const& GetServiceNames();
 
-    // Create a service with a given service name.
-    static std::shared_ptr<Codec2Client> CreateFromService(char const* name);
+    // Create a client to a service with a given name.
+    //
+    // After a client to the service is successfully created, if
+    // setAsPreferredCodec2ComponentStore is true, the component store that the
+    // service hosts will be set as the preferred C2ComponentStore for this
+    // process. (See SetPreferredCodec2ComponentStore() for more information.)
+    static std::shared_ptr<Codec2Client> CreateFromService(
+            char const* name,
+            bool setAsPreferredCodec2ComponentStore = false);
 
     // Get clients to all services.
     static std::vector<std::shared_ptr<Codec2Client>> CreateFromAllServices();
diff --git a/media/codec2/hidl/services/Android.bp b/media/codec2/hidl/services/Android.bp
index 46bea2e..a16b106 100644
--- a/media/codec2/hidl/services/Android.bp
+++ b/media/codec2/hidl/services/Android.bp
@@ -47,6 +47,11 @@
         "libbinder",
     ],
     required: ["android.hardware.media.c2@1.1-default-seccomp_policy"],
+
+    // The content in manifest_media_c2_V1_1_default.xml can be included
+    // directly in the main device manifest.xml file or via vintf_fragments.
+    // (Remove the line below if the entry is already in the main manifest.)
+    vintf_fragments: ["manifest_media_c2_V1_1_default.xml"],
 }
 
 // seccomp policy file.
diff --git a/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml b/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml
new file mode 100644
index 0000000..e97c3ce
--- /dev/null
+++ b/media/codec2/hidl/services/manifest_media_c2_V1_0_default.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal>
+        <name>android.hardware.media.c2</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+            <name>IComponentStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml b/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml
new file mode 100644
index 0000000..bf0d72f
--- /dev/null
+++ b/media/codec2/hidl/services/manifest_media_c2_V1_1_default.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal>
+        <name>android.hardware.media.c2</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IComponentStore</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index 78d221e..c7588e9 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -62,7 +62,7 @@
             android::base::unique_fd &&fd0,
             android::base::unique_fd &&fd1) {
         Mutexed<Jobs>::Locked jobs(mJobs);
-        auto it = jobs->queues.try_emplace(comp, comp, systemTime()).first;
+        auto it = jobs->queues.try_emplace(comp, comp).first;
         it->second.workList.emplace_back(
                 std::move(work), fenceFd, std::move(fd0), std::move(fd1));
         jobs->cond.broadcast();
@@ -79,7 +79,8 @@
             for (auto it = jobs->queues.begin(); it != jobs->queues.end(); ) {
                 Queue &queue = it->second;
                 if (queue.workList.empty()
-                        || nowNs - queue.lastQueuedTimestampNs < kIntervalNs) {
+                        || (queue.lastQueuedTimestampNs != 0 &&
+                            nowNs - queue.lastQueuedTimestampNs < kIntervalNs)) {
                     ++it;
                     continue;
                 }
@@ -104,6 +105,7 @@
                     sp<Fence> fence(new Fence(fenceFd));
                     fence->waitForever(LOG_TAG);
                 }
+                queue.lastQueuedTimestampNs = nowNs;
                 comp->queue(&items);
                 for (android::base::unique_fd &ufd : uniqueFds) {
                     (void)ufd.release();
@@ -143,8 +145,8 @@
         android::base::unique_fd fd1;
     };
     struct Queue {
-        Queue(const std::shared_ptr<Codec2Client::Component> &comp, nsecs_t timestamp)
-            : component(comp), lastQueuedTimestampNs(timestamp) {}
+        Queue(const std::shared_ptr<Codec2Client::Component> &comp)
+            : component(comp), lastQueuedTimestampNs(0) {}
         Queue(const Queue &) = delete;
         Queue &operator =(const Queue &) = delete;
 
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 0d093da..cc132de 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1320,7 +1320,8 @@
         Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
         const std::unique_ptr<Config> &config = *configLocked;
         inputFormat = config->mInputFormat;
-        outputFormat = config->mOutputFormat;
+        // start triggers format dup
+        outputFormat = config->mOutputFormat = config->mOutputFormat->dup();
         if (config->mInputSurface) {
             err2 = config->mInputSurface->start();
         }
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index b869bd9..6b389d5 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -604,7 +604,12 @@
 
     ssize_t result = -1;
     ssize_t codecDataOffset = 0;
-    if (mCrypto != nullptr) {
+    if (numSubSamples == 1
+            && subSamples[0].mNumBytesOfClearData == 0
+            && subSamples[0].mNumBytesOfEncryptedData == 0) {
+        // We don't need to go through crypto or descrambler if the input is empty.
+        result = 0;
+    } else if (mCrypto != nullptr) {
         hardware::drm::V1_0::DestinationBuffer destination;
         if (secure) {
             destination.type = DrmBufferType::NATIVE_HANDLE;
@@ -620,6 +625,7 @@
                 key, iv, mode, pattern, source, buffer->offset(),
                 subSamples, numSubSamples, destination, errorDetailMsg);
         if (result < 0) {
+            ALOGI("[%s] decrypt failed: result=%zd", mName, result);
             return result;
         }
         if (destination.type == DrmBufferType::SHARED_MEMORY) {
@@ -1251,7 +1257,7 @@
         } else {
             output->buffers.reset(new LinearOutputBuffers(mName));
         }
-        output->buffers->setFormat(outputFormat->dup());
+        output->buffers->setFormat(outputFormat);
 
 
         // Try to set output surface to created block pool if given.
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 51d6ffa..f3e37e0 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -95,6 +95,10 @@
     name: "libcodec2-internal-defaults",
     defaults: ["libcodec2-impl-defaults"],
 
+    header_libs: [
+        "libcodec2_internal",
+    ],
+
     shared_libs: [
         "libcutils", // for properties
     ],
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 5d00d94..8f60f6b 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -181,6 +181,8 @@
 }
 
 AACExtractor::~AACExtractor() {
+    mOffsetVector.clear();
+    delete mDataSource;
     if (mMeta != nullptr) {
         AMediaFormat_delete(mMeta);
     }
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index ca721df..bdb724b 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -13,6 +13,9 @@
         "libsonivox",
         "libstagefright_foundation",
         "libwatchdog",
+    ],
+
+    shared_libs: [
         "libbase",
-    ]
+    ],
 }
diff --git a/media/extractors/mp4/AC4Parser.cpp b/media/extractors/mp4/AC4Parser.cpp
index 13d60c8..25fc4cd 100644
--- a/media/extractors/mp4/AC4Parser.cpp
+++ b/media/extractors/mp4/AC4Parser.cpp
@@ -600,6 +600,10 @@
         if (ac4_dsi_version == 1) {
             uint64_t end = (mDSISize - mBitReader.numBitsLeft()) / 8;
             uint64_t presentation_bytes = end - start;
+            if (pres_bytes < presentation_bytes) {
+                ALOGE("pres_bytes is smaller than presentation_bytes.");
+                return false;
+            }
             uint64_t skip_bytes = pres_bytes - presentation_bytes;
             ALOGV("skipping = %" PRIu64 " bytes", skip_bytes);
             CHECK_BITS_LEFT(skip_bytes * 8);
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index d7c4b5c..bc8632c 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -10,6 +10,7 @@
     ],
 
     shared_libs: [
+        "libbase",
         "libcgrouprc#29",
         "libvndksupport#29",
     ],
@@ -28,7 +29,6 @@
         "android.hidl.memory@1.0",
         "android.hidl.token@1.0",
         "android.hidl.token@1.0-utils",
-        "libbase",
         "libcutils",
         "libhidlbase",
         "libhidlmemory",
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 3638d2c..65afc8d 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -51,6 +51,7 @@
         // AIDL files for audioclient interfaces
         // The headers for these interfaces will be available to any modules that
         // include libaudioclient, at the path "aidl/package/path/BnFoo.h"
+        ":libaudioclient_aidl_callback",
         ":libaudioclient_aidl_private",
         ":libaudioclient_aidl",
 
@@ -138,3 +139,12 @@
     ],
     path: "aidl",
 }
+
+// AIDL interface for audio track callback
+filegroup {
+    name: "libaudioclient_aidl_callback",
+    srcs: [
+        "aidl/android/media/IAudioTrackCallback.aidl",
+    ],
+    path: "aidl",
+}
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 2f67a18..f030ab0 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -792,6 +792,13 @@
 
 // ---------------------------------------------------------------------------
 
+void AudioSystem::onNewAudioModulesAvailable()
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return;
+    aps->onNewAudioModulesAvailable();
+}
+
 status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
                                                audio_policy_dev_state_t state,
                                                const char *device_address,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index d5690fb..2f95886 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -217,7 +217,8 @@
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
       mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mAudioTrackCallback(new AudioTrackCallback())
 {
     mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
     mAttributes.usage = AUDIO_USAGE_UNKNOWN;
@@ -248,7 +249,8 @@
       mState(STATE_STOPPED),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
-      mPausedPosition(0)
+      mPausedPosition(0),
+      mAudioTrackCallback(new AudioTrackCallback())
 {
     mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
 
@@ -281,7 +283,8 @@
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
       mPreviousSchedulingGroup(SP_DEFAULT),
       mPausedPosition(0),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mAudioTrackCallback(new AudioTrackCallback())
 {
     mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
 
@@ -1527,6 +1530,7 @@
     input.notificationFrameCount = mNotificationFramesReq;
     input.selectedDeviceId = mSelectedDeviceId;
     input.sessionId = mSessionId;
+    input.audioTrackCallback = mAudioTrackCallback;
 
     IAudioFlinger::CreateTrackOutput output;
 
@@ -3376,4 +3380,23 @@
     mPausedNs = ns;
 }
 
+binder::Status AudioTrack::AudioTrackCallback::onCodecFormatChanged(
+        const std::vector<uint8_t>& audioMetadata)
+{
+    AutoMutex _l(mAudioTrackCbLock);
+    sp<media::IAudioTrackCallback> callback = mCallback.promote();
+    if (callback.get() != nullptr) {
+        callback->onCodecFormatChanged(audioMetadata);
+    } else {
+        mCallback.clear();
+    }
+    return binder::Status::ok();
+}
+
+void AudioTrack::AudioTrackCallback::setAudioTrackCallback(
+        const sp<media::IAudioTrackCallback> &callback) {
+    AutoMutex lock(mAudioTrackCbLock);
+    mCallback = callback;
+}
+
 } // namespace android
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index cccb131..f1213a3 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -113,6 +113,7 @@
     REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
     GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
     GET_DEVICES_FOR_ATTRIBUTES,
+    AUDIO_MODULES_UPDATED,  // oneway
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -1451,6 +1452,13 @@
         }
         return NO_ERROR;
     }
+
+    virtual void onNewAudioModulesAvailable()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        remote()->transact(AUDIO_MODULES_UPDATED, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1522,7 +1530,8 @@
         case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
         case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
         case GET_DEVICES_FOR_ATTRIBUTES:
-        case SET_ALLOWED_CAPTURE_POLICY: {
+        case SET_ALLOWED_CAPTURE_POLICY:
+        case AUDIO_MODULES_UPDATED: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -2672,6 +2681,12 @@
             return NO_ERROR;
         }
 
+        case AUDIO_MODULES_UPDATED: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            onNewAudioModulesAvailable();
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
new file mode 100644
index 0000000..21553b5
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/IAudioTrackCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 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.media;
+
+/**
+ * @hide
+ */
+interface IAudioTrackCallback {
+    oneway void onCodecFormatChanged(in byte[] audioMetadata);
+}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 07a2292..aebc875 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -221,6 +221,7 @@
     //
     // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
     //
+    static void onNewAudioModulesAvailable();
     static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state,
                                              const char *device_address, const char *device_name,
                                              audio_format_t encodedFormat);
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 95cad0a..4adaaea 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -26,6 +26,9 @@
 #include <media/Modulo.h>
 #include <utils/threads.h>
 
+#include "android/media/BnAudioTrackCallback.h"
+#include "android/media/IAudioTrackCallback.h"
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -885,8 +888,6 @@
             virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                              audio_port_handle_t deviceId);
 
-
-
     /* Obtain the pending duration in milliseconds for playback of pure PCM
      * (mixable without embedded timing) data remaining in AudioTrack.
      *
@@ -933,6 +934,10 @@
      */
             audio_port_handle_t getPortId() const { return mPortId; };
 
+            void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback) {
+                mAudioTrackCallback->setAudioTrackCallback(callback);
+            }
+
  protected:
     /* copying audio tracks is not allowed */
                         AudioTrack(const AudioTrack& other);
@@ -1254,6 +1259,18 @@
     };
     MediaMetrics mMediaMetrics;
     std::string mMetricsId;  // GUARDED_BY(mLock), could change in createTrack_l().
+
+private:
+    class AudioTrackCallback : public media::BnAudioTrackCallback {
+    public:
+        binder::Status onCodecFormatChanged(const std::vector<uint8_t>& audioMetadata) override;
+
+        void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback);
+    private:
+        Mutex mAudioTrackCbLock;
+        wp<media::IAudioTrackCallback> mCallback;
+    };
+    sp<AudioTrackCallback> mAudioTrackCallback;
 };
 
 }; // namespace android
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 8658cfa..f4ce5d7 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -40,6 +40,7 @@
 #include <vector>
 
 #include "android/media/IAudioRecord.h"
+#include "android/media/IAudioTrackCallback.h"
 
 namespace android {
 
@@ -83,6 +84,8 @@
             }
             notificationsPerBuffer = parcel->readInt32();
             speed = parcel->readFloat();
+            audioTrackCallback = interface_cast<media::IAudioTrackCallback>(
+                    parcel->readStrongBinder());
 
             /* input/output arguments*/
             (void)parcel->read(&flags, sizeof(audio_output_flags_t));
@@ -107,6 +110,7 @@
             }
             (void)parcel->writeInt32(notificationsPerBuffer);
             (void)parcel->writeFloat(speed);
+            (void)parcel->writeStrongBinder(IInterface::asBinder(audioTrackCallback));
 
             /* input/output arguments*/
             (void)parcel->write(&flags, sizeof(audio_output_flags_t));
@@ -125,6 +129,7 @@
         sp<IMemory> sharedBuffer;
         uint32_t notificationsPerBuffer;
         float speed;
+        sp<media::IAudioTrackCallback> audioTrackCallback;
 
         /* input/output */
         audio_output_flags_t flags;
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 779ca43..ec3461e 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -42,6 +42,7 @@
     //
     // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions)
     //
+    virtual void onNewAudioModulesAvailable() = 0;
     virtual status_t setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
                                               const char *device_address,
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index e6e9688..1c0eacb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -15,12 +15,13 @@
  */
 
 #include <string.h>
-#include <vector>
+#include <set>
 
 #define LOG_TAG "DevicesFactoryHalHidl"
 //#define LOG_NDEBUG 0
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.0/IServiceNotification.h>
 #include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
 #include <media/audiohal/hidl/HalDeathHandler.h>
 #include <utils/Log.h>
@@ -29,33 +30,57 @@
 #include "DeviceHalHidl.h"
 #include "DevicesFactoryHalHidl.h"
 
-#include <set>
-
 using ::android::hardware::audio::CPP_VERSION::IDevice;
 using ::android::hardware::audio::CPP_VERSION::Result;
 using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
 
 namespace android {
 namespace CPP_VERSION {
 
-DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
-    ALOG_ASSERT(devicesFactory != nullptr, "Provided IDevicesFactory service is NULL");
+class ServiceNotificationListener : public IServiceNotification {
+  public:
+    explicit ServiceNotificationListener(sp<DevicesFactoryHalHidl> factory)
+            : mFactory(factory) {}
 
-    mDeviceFactories.push_back(devicesFactory);
-    if (MAJOR_VERSION >= 4) {
-        // The MSD factory is optional and only available starting at HAL 4.0
-        sp<IDevicesFactory> msdFactory{IDevicesFactory::getService(AUDIO_HAL_SERVICE_NAME_MSD)};
-        if (msdFactory) {
-            mDeviceFactories.push_back(msdFactory);
+    Return<void> onRegistration(const hidl_string& /*fully_qualified_name*/,
+            const hidl_string& instance_name,
+            bool /*pre_existing*/) override {
+        if (static_cast<std::string>(instance_name) == "default") return Void();
+        sp<DevicesFactoryHalHidl> factory = mFactory.promote();
+        if (!factory) return Void();
+        sp<IDevicesFactory> halFactory = IDevicesFactory::getService(instance_name);
+        if (halFactory) {
+            factory->addDeviceFactory(halFactory, true /*needToNotify*/);
         }
+        return Void();
     }
-    for (const auto& factory : mDeviceFactories) {
-        // It is assumed that the DevicesFactoryHalInterface instance is owned
-        // by AudioFlinger and thus have the same lifespan.
-        factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
-    }
+
+  private:
+    wp<DevicesFactoryHalHidl> mFactory;
+};
+
+DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
+    ALOG_ASSERT(devicesFactory != nullptr, "Provided default IDevicesFactory service is NULL");
+    addDeviceFactory(devicesFactory, false /*needToNotify*/);
 }
 
+void DevicesFactoryHalHidl::onFirstRef() {
+    sp<IServiceManager> sm = IServiceManager::getService();
+    ALOG_ASSERT(sm != nullptr, "Hardware service manager is not running");
+    sp<ServiceNotificationListener> listener = new ServiceNotificationListener(this);
+    Return<bool> result = sm->registerForNotifications(
+            IDevicesFactory::descriptor, "", listener);
+    if (result.isOk()) {
+        ALOGE_IF(!static_cast<bool>(result),
+                "Hardware service manager refused to register listener");
+    } else {
+        ALOGE("Failed to register for hardware service manager notifications: %s",
+                result.description().c_str());
+    }
+}
 
 #if MAJOR_VERSION == 2
 static IDevicesFactory::Device idFromHal(const char *name, status_t* status) {
@@ -83,12 +108,13 @@
 #endif
 
 status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
-    if (mDeviceFactories.empty()) return NO_INIT;
+    auto factories = copyDeviceFactories();
+    if (factories.empty()) return NO_INIT;
     status_t status;
     auto hidlId = idFromHal(name, &status);
     if (status != OK) return status;
     Result retval = Result::NOT_INITIALIZED;
-    for (const auto& factory : mDeviceFactories) {
+    for (const auto& factory : factories) {
         Return<void> ret = factory->openDevice(
                 hidlId,
                 [&](Result r, const sp<IDevice>& result) {
@@ -113,10 +139,9 @@
 
 status_t DevicesFactoryHalHidl::getHalPids(std::vector<pid_t> *pids) {
     std::set<pid_t> pidsSet;
-
-    for (const auto& factory : mDeviceFactories) {
+    auto factories = copyDeviceFactories();
+    for (const auto& factory : factories) {
         using ::android::hidl::base::V1_0::DebugInfo;
-        using android::hidl::manager::V1_0::IServiceManager;
 
         DebugInfo debugInfo;
         auto ret = factory->getDebugInfo([&] (const auto &info) {
@@ -135,5 +160,48 @@
     return NO_ERROR;
 }
 
+status_t DevicesFactoryHalHidl::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+    ALOG_ASSERT(callback != nullptr);
+    bool needToCallCallback = false;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        if (mCallback.unsafe_get()) return INVALID_OPERATION;
+        mCallback = callback;
+        if (mHaveUndeliveredNotifications) {
+            needToCallCallback = true;
+            mHaveUndeliveredNotifications = false;
+        }
+    }
+    if (needToCallCallback) {
+        callback->onNewDevicesAvailable();
+    }
+    return NO_ERROR;
+}
+
+void DevicesFactoryHalHidl::addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify) {
+    // It is assumed that the DevicesFactoryHalInterface instance is owned
+    // by AudioFlinger and thus have the same lifespan.
+    factory->linkToDeath(HalDeathHandler::getInstance(), 0 /*cookie*/);
+    sp<DevicesFactoryHalCallback> callback;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+        mDeviceFactories.push_back(factory);
+        if (needToNotify) {
+            callback = mCallback.promote();
+            if (!callback) {
+                mHaveUndeliveredNotifications = true;
+            }
+        }
+    }
+    if (callback) {
+        callback->onNewDevicesAvailable();
+    }
+}
+
+std::vector<sp<IDevicesFactory>> DevicesFactoryHalHidl::copyDeviceFactories() {
+    std::lock_guard<std::mutex> lock(mLock);
+    return mDeviceFactories;
+}
+
 } // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 52185c8..6f84efe 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
 #define ANDROID_HARDWARE_DEVICES_FACTORY_HAL_HIDL_H
 
+#include <mutex>
+#include <vector>
+
 #include PATH(android/hardware/audio/FILE_VERSION/IDevicesFactory.h)
 #include <media/audiohal/DevicesFactoryHalInterface.h>
 #include <utils/Errors.h>
@@ -32,16 +35,26 @@
 class DevicesFactoryHalHidl : public DevicesFactoryHalInterface
 {
   public:
-    DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+    explicit DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory);
+    void onFirstRef() override;
 
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
-    virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+    status_t openDevice(const char *name, sp<DeviceHalInterface> *device) override;
 
-            status_t getHalPids(std::vector<pid_t> *pids) override;
+    status_t getHalPids(std::vector<pid_t> *pids) override;
+
+    status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
 
   private:
-    std::vector<sp<IDevicesFactory>> mDeviceFactories;
+    friend class ServiceNotificationListener;
+    void addDeviceFactory(sp<IDevicesFactory> factory, bool needToNotify);
+    std::vector<sp<IDevicesFactory>> copyDeviceFactories();
+
+    std::mutex mLock;
+    std::vector<sp<IDevicesFactory>> mDeviceFactories;  // GUARDED_BY(mLock)
+    wp<DevicesFactoryHalCallback> mCallback;  // GUARDED_BY(mLock)
+    bool mHaveUndeliveredNotifications = false;  // GUARDED_BY(mLock)
 
     virtual ~DevicesFactoryHalHidl() = default;
 };
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index 52f150a..cde8d85 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -44,6 +44,13 @@
     return INVALID_OPERATION;
 }
 
+status_t DevicesFactoryHalHybrid::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
+    if (mHidlFactory) {
+        return mHidlFactory->setCallbackOnce(callback);
+    }
+    return INVALID_OPERATION;
+}
+
 } // namespace CPP_VERSION
 
 extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() {
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index 2189b36..568a1fb 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -38,6 +38,8 @@
 
             status_t getHalPids(std::vector<pid_t> *pids) override;
 
+            status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
+
   private:
     sp<DevicesFactoryHalInterface> mLocalFactory;
     sp<DevicesFactoryHalInterface> mHidlFactory;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
index 2b011f4..32bf362 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
@@ -37,6 +37,10 @@
                 return INVALID_OPERATION;
             }
 
+            status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback __unused) override {
+                return INVALID_OPERATION;
+            }
+
   private:
     friend class DevicesFactoryHalHybrid;
 
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index c08dddb..2726e36 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -299,10 +299,17 @@
         if (mCallback.unsafe_get()) {
             processReturn("clearCallback", mStream->clearCallback());
         }
+#if MAJOR_VERSION >= 6
+        if (mEventCallback.unsafe_get() != nullptr) {
+            processReturn("setEventCallback",
+                    mStream->setEventCallback(nullptr));
+        }
+#endif
         processReturn("close", mStream->close());
         mStream.clear();
     }
     mCallback.clear();
+    mEventCallback.clear();
     hardware::IPCThreadState::self()->flushCommands();
     if (mEfGroup) {
         EventFlag::deleteEventFlag(&mEfGroup);
@@ -614,6 +621,50 @@
 }
 #endif
 
+#if MAJOR_VERSION < 6
+status_t StreamOutHalHidl::setEventCallback(
+        const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
+    // Codec format callback is supported starting from audio HAL V6.0
+    return INVALID_OPERATION;
+}
+#else
+
+#include PATH(android/hardware/audio/FILE_VERSION/IStreamOutEventCallback.h)
+
+namespace {
+
+struct StreamOutEventCallback : public IStreamOutEventCallback {
+    StreamOutEventCallback(const wp<StreamOutHalHidl>& stream) : mStream(stream) {}
+
+    // IStreamOutEventCallback implementation
+    Return<void> onCodecFormatChanged(
+            const android::hardware::hidl_vec<uint8_t>& audioMetadata)  override {
+        sp<StreamOutHalHidl> stream = mStream.promote();
+        if (stream != nullptr) {
+            std::basic_string<uint8_t> metadataBs(audioMetadata.begin(), audioMetadata.end());
+            stream->onCodecFormatChanged(metadataBs);
+        }
+        return Void();
+    }
+
+  private:
+    wp<StreamOutHalHidl> mStream;
+};
+
+}  // namespace
+
+status_t StreamOutHalHidl::setEventCallback(
+        const sp<StreamOutHalInterfaceEventCallback>& callback) {
+    if (mStream == nullptr) return NO_INIT;
+    mEventCallback = callback;
+    status_t status = processReturn(
+            "setEventCallback",
+            mStream->setEventCallback(
+                    callback.get() == nullptr ? nullptr : new StreamOutEventCallback(this)));
+    return status;
+}
+#endif
+
 void StreamOutHalHidl::onWriteReady() {
     sp<StreamOutHalInterfaceCallback> callback = mCallback.promote();
     if (callback == 0) return;
@@ -635,6 +686,13 @@
     callback->onError();
 }
 
+void StreamOutHalHidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) {
+    sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.promote();
+    if (callback == nullptr) return;
+    ALOGV("asyncCodecFormatCallback %s", __func__);
+    callback->onCodecFormatChanged(metadataBs);
+}
+
 
 StreamInHalHidl::StreamInHalHidl(const sp<IStreamIn>& stream)
         : StreamHalHidl(stream.get()), mStream(stream), mReaderClient(0), mEfGroup(nullptr) {
diff --git a/media/libaudiohal/impl/StreamHalHidl.h b/media/libaudiohal/impl/StreamHalHidl.h
index f587889..88f8587 100644
--- a/media/libaudiohal/impl/StreamHalHidl.h
+++ b/media/libaudiohal/impl/StreamHalHidl.h
@@ -173,6 +173,11 @@
     void onDrainReady();
     void onError();
 
+    status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
+    // Methods used by StreamCodecFormatCallback (HIDL).
+    void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
+
   private:
     friend class DeviceHalHidl;
     typedef MessageQueue<WriteCommand, hardware::kSynchronizedReadWrite> CommandMQ;
@@ -180,6 +185,7 @@
     typedef MessageQueue<WriteStatus, hardware::kSynchronizedReadWrite> StatusMQ;
 
     wp<StreamOutHalInterfaceCallback> mCallback;
+    wp<StreamOutHalInterfaceEventCallback> mEventCallback;
     sp<IStreamOut> mStream;
     std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<DataMQ> mDataMQ;
diff --git a/media/libaudiohal/impl/StreamHalLocal.cpp b/media/libaudiohal/impl/StreamHalLocal.cpp
index 4818fd8..69be303 100644
--- a/media/libaudiohal/impl/StreamHalLocal.cpp
+++ b/media/libaudiohal/impl/StreamHalLocal.cpp
@@ -275,6 +275,43 @@
     return mStream->get_mmap_position(mStream, position);
 }
 
+status_t StreamOutHalLocal::setEventCallback(
+        const sp<StreamOutHalInterfaceEventCallback>& callback) {
+    if (mStream->set_event_callback == nullptr) {
+        return INVALID_OPERATION;
+    }
+    stream_event_callback_t asyncCallback =
+            callback == nullptr ? nullptr : StreamOutHalLocal::asyncEventCallback;
+    status_t result = mStream->set_event_callback(mStream, asyncCallback, this);
+    if (result == OK) {
+        mEventCallback = callback;
+    }
+    return result;
+}
+
+// static
+int StreamOutHalLocal::asyncEventCallback(
+        stream_event_callback_type_t event, void *param, void *cookie) {
+    // We act as if we gave a wp<StreamOutHalLocal> to HAL. This way we should handle
+    // correctly the case when the callback is invoked while StreamOutHalLocal's destructor is
+    // already running, because the destructor is invoked after the refcount has been atomically
+    // decremented.
+    wp<StreamOutHalLocal> weakSelf(static_cast<StreamOutHalLocal*>(cookie));
+    sp<StreamOutHalLocal> self = weakSelf.promote();
+    if (self == nullptr) return 0;
+    sp<StreamOutHalInterfaceEventCallback> callback = self->mEventCallback.promote();
+    if (callback.get() == nullptr) return 0;
+    switch (event) {
+        case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED:
+            callback->onCodecFormatChanged(std::basic_string<uint8_t>((uint8_t*)param));
+            break;
+        default:
+            ALOGW("%s unknown event %d", __func__, event);
+            break;
+    }
+    return 0;
+}
+
 StreamInHalLocal::StreamInHalLocal(audio_stream_in_t *stream, sp<DeviceHalLocal> device)
         : StreamHalLocal(&stream->common, device), mStream(stream) {
 }
diff --git a/media/libaudiohal/impl/StreamHalLocal.h b/media/libaudiohal/impl/StreamHalLocal.h
index 34f2bd8..d17f9f3 100644
--- a/media/libaudiohal/impl/StreamHalLocal.h
+++ b/media/libaudiohal/impl/StreamHalLocal.h
@@ -156,9 +156,12 @@
     // Called when the metadata of the stream's source has been changed.
     status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
 
+    status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
   private:
     audio_stream_out_t *mStream;
     wp<StreamOutHalInterfaceCallback> mCallback;
+    wp<StreamOutHalInterfaceEventCallback> mEventCallback;
 
     friend class DeviceHalLocal;
 
@@ -168,6 +171,8 @@
     virtual ~StreamOutHalLocal();
 
     static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
+
+    static int asyncEventCallback(stream_event_callback_type_t event, void *param, void *cookie);
 };
 
 class StreamInHalLocal : public StreamInHalInterface, public StreamHalLocal {
diff --git a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
index e9ac1ce..5091558 100644
--- a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -24,6 +24,12 @@
 
 namespace android {
 
+class DevicesFactoryHalCallback : public RefBase
+{
+  public:
+    virtual void onNewDevicesAvailable() = 0;
+};
+
 class DevicesFactoryHalInterface : public RefBase
 {
   public:
@@ -33,6 +39,10 @@
 
     virtual status_t getHalPids(std::vector<pid_t> *pids) = 0;
 
+    // Sets a DevicesFactoryHalCallback to notify the client.
+    // The callback can be only set once.
+    virtual status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) = 0;
+
     static sp<DevicesFactoryHalInterface> create();
 
   protected:
diff --git a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
index 6c3b21c..e30cb72 100644
--- a/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/StreamHalInterface.h
@@ -101,6 +101,15 @@
     virtual ~StreamOutHalInterfaceCallback() {}
 };
 
+class StreamOutHalInterfaceEventCallback : public virtual RefBase {
+public:
+    virtual void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs) = 0;
+
+protected:
+    StreamOutHalInterfaceEventCallback() {}
+    virtual ~StreamOutHalInterfaceEventCallback() {}
+};
+
 class StreamOutHalInterface : public virtual StreamHalInterface {
   public:
     // Return the audio hardware driver estimated latency in milliseconds.
@@ -157,6 +166,8 @@
      */
     virtual status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) = 0;
 
+    virtual status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) = 0;
+
   protected:
     virtual ~StreamOutHalInterface() {}
 };
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index c10e6e0..cf7f423 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -2009,6 +2009,9 @@
             (*meta)->setInt32(kKeyRotation, mRotationDegrees);
         }
     }
+    if (mOutputFormat == OUTPUT_FORMAT_MPEG_4 || mOutputFormat == OUTPUT_FORMAT_THREE_GPP) {
+        (*meta)->setInt32(kKeyEmptyTrackMalFormed, true);
+    }
 }
 
 status_t StagefrightRecorder::pause() {
diff --git a/media/libstagefright/FrameCaptureLayer.cpp b/media/libstagefright/FrameCaptureLayer.cpp
index 815057d..d2cfd41 100644
--- a/media/libstagefright/FrameCaptureLayer.cpp
+++ b/media/libstagefright/FrameCaptureLayer.cpp
@@ -67,7 +67,8 @@
 bool isHdrY410(const BufferItem &bi) {
     ui::Dataspace dataspace = translateDataspace(static_cast<ui::Dataspace>(bi.mDataSpace));
     // pixel format is HDR Y410 masquerading as RGBA_1010102
-    return (dataspace == ui::Dataspace::BT2020_ITU_PQ &&
+    return ((dataspace == ui::Dataspace::BT2020_ITU_PQ ||
+            dataspace == ui::Dataspace::BT2020_ITU_HLG) &&
             bi.mGraphicBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
 }
 
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 3c4524b..734f5bb 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -248,7 +248,8 @@
         transfer = 0;
     }
     return standard == ColorUtils::kColorStandardBT2020 &&
-            transfer == ColorUtils::kColorTransferST2084;
+            (transfer == ColorUtils::kColorTransferST2084 ||
+            transfer == ColorUtils::kColorTransferHLG);
 }
 
 status_t FrameDecoder::init(
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index dbbdd1b..af8096d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1131,8 +1131,8 @@
         err = writerErr;
     }
 
-    // Do not write out movie header on error.
-    if (err != OK) {
+    // Do not write out movie header on error except malformed track.
+    if (err != OK && err != ERROR_MALFORMED) {
         release();
         return err;
     }
@@ -2687,7 +2687,7 @@
 status_t MPEG4Writer::Track::stop(bool stopSource) {
     ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
     if (!mStarted) {
-        ALOGE("Stop() called but track is not started");
+        ALOGE("Stop() called but track is not started or stopped");
         return ERROR_END_OF_STREAM;
     }
 
@@ -2711,6 +2711,7 @@
     err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
     WARN_UNLESS(err == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err,
                 stopSource ? "Stop" : "Not Stop");
+    mStarted = false;
     return err;
 }
 
@@ -3108,6 +3109,7 @@
     int32_t nActualFrames = 0;        // frames containing non-CSD data (non-0 length)
     int32_t nZeroLengthFrames = 0;
     int64_t lastTimestampUs = 0;      // Previous sample time stamp
+    int64_t previousSampleTimestampWithoutFudgeUs = 0; // Timestamp received/without fudge for STTS
     int64_t lastDurationUs = 0;       // Between the previous two samples
     int64_t currDurationTicks = 0;    // Timescale based ticks
     int64_t lastDurationTicks = 0;    // Timescale based ticks
@@ -3120,6 +3122,8 @@
     int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
     int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
     uint32_t lastSamplesPerChunk = 0;
+    int64_t lastSampleDurationUs = -1;      // Duration calculated from EOS buffer and its timestamp
+    int64_t lastSampleDurationTicks = -1;   // Timescale based ticks
 
     if (mIsAudio) {
         prctl(PR_SET_NAME, (unsigned long)"AudioTrackWriterThread", 0, 0, 0);
@@ -3139,14 +3143,34 @@
     MediaBufferBase *buffer;
     const char *trackName = getTrackType();
     while (!mDone && (err = mSource->read(&buffer)) == OK) {
+        int32_t isEOS = false;
         if (buffer->range_length() == 0) {
-            buffer->release();
-            buffer = NULL;
-            ++nZeroLengthFrames;
-            continue;
+            if (buffer->meta_data().findInt32(kKeyIsEndOfStream, &isEOS) && isEOS) {
+                int64_t eosSampleTimestampUs = -1;
+                CHECK(buffer->meta_data().findInt64(kKeyTime, &eosSampleTimestampUs));
+                if (eosSampleTimestampUs > 0) {
+                    lastSampleDurationUs = eosSampleTimestampUs -
+                                           previousSampleTimestampWithoutFudgeUs -
+                                           previousPausedDurationUs;
+                    if (lastSampleDurationUs >= 0) {
+                        lastSampleDurationTicks = (lastSampleDurationUs * mTimeScale + 500000LL) /
+                                                  1000000LL;
+                    } else {
+                        ALOGW("lastSampleDurationUs %" PRId64 " is negative", lastSampleDurationUs);
+                    }
+                }
+                buffer->release();
+                buffer = nullptr;
+                mSource->stop();
+                break;
+            } else {
+                buffer->release();
+                buffer = nullptr;
+                ++nZeroLengthFrames;
+                continue;
+            }
         }
 
-
         // If the codec specific data has not been received yet, delay pause.
         // After the codec specific data is received, discard what we received
         // when the track is to be paused.
@@ -3470,6 +3494,8 @@
                 break;
             }
 
+            previousSampleTimestampWithoutFudgeUs = timestampUs;
+
             // if the duration is different for this sample, see if it is close enough to the previous
             // duration that we can fudge it and use the same value, to avoid filling the stts table
             // with lots of near-identical entries.
@@ -3567,47 +3593,61 @@
         }
     }
     if (isTrackMalFormed()) {
+        mIsMalformed = true;
         dumpTimeStamps();
         err = ERROR_MALFORMED;
     }
 
     mOwner->trackProgressStatus(mTrackId, -1, err);
 
-    if (mIsHeic) {
-        if (!mChunkSamples.empty()) {
-            bufferChunk(0);
-            ++nChunks;
-        }
-    } else {
-        // Last chunk
-        if (!hasMultipleTracks) {
-            addOneStscTableEntry(1, mStszTableEntries->count());
-        } else if (!mChunkSamples.empty()) {
-            addOneStscTableEntry(++nChunks, mChunkSamples.size());
-            bufferChunk(timestampUs);
-        }
-
-        // We don't really know how long the last frame lasts, since
-        // there is no frame time after it, just repeat the previous
-        // frame's duration.
-        if (mStszTableEntries->count() == 1) {
-            lastDurationUs = 0;  // A single sample's duration
-            lastDurationTicks = 0;
+    // Add final entries only for non-empty tracks.
+    if (mStszTableEntries->count() > 0) {
+        if (mIsHeic) {
+            if (!mChunkSamples.empty()) {
+                bufferChunk(0);
+                ++nChunks;
+            }
         } else {
-            ++sampleCount;  // Count for the last sample
-        }
+            // Last chunk
+            if (!hasMultipleTracks) {
+                addOneStscTableEntry(1, mStszTableEntries->count());
+            } else if (!mChunkSamples.empty()) {
+                addOneStscTableEntry(++nChunks, mChunkSamples.size());
+                bufferChunk(timestampUs);
+            }
 
-        addOneSttsTableEntry(sampleCount, lastDurationTicks);
+            // We don't really know how long the last frame lasts, since
+            // there is no frame time after it, just repeat the previous
+            // frame's duration.
+            if (mStszTableEntries->count() == 1) {
+                if (lastSampleDurationUs >= 0) {
+                    addOneSttsTableEntry(sampleCount, lastSampleDurationTicks);
+                } else {
+                    lastDurationUs = 0;  // A single sample's duration
+                    lastDurationTicks = 0;
+                    addOneSttsTableEntry(sampleCount, lastDurationTicks);
+                }
+            } else if (lastSampleDurationUs >= 0) {
+                addOneSttsTableEntry(sampleCount, lastDurationTicks);
+                addOneSttsTableEntry(1, lastSampleDurationTicks);
+            } else {
+                ++sampleCount;  // Count for the last sample
+                addOneSttsTableEntry(sampleCount, lastDurationTicks);
+            }
 
-        // The last ctts box entry may not have been written yet, and this
-        // is to make sure that we write out the last ctts box entry.
-        if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
-            if (cttsSampleCount > 0) {
-                addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+            // The last ctts box entry may not have been written yet, and this
+            // is to make sure that we write out the last ctts box entry.
+            if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
+                if (cttsSampleCount > 0) {
+                    addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
+                }
+            }
+            if (lastSampleDurationUs >= 0) {
+                mTrackDurationUs += lastSampleDurationUs;
+            } else {
+                mTrackDurationUs += lastDurationUs;
             }
         }
-
-        mTrackDurationUs += lastDurationUs;
     }
     mReachedEOS = true;
 
@@ -3630,14 +3670,24 @@
         return true;
     }
 
-    if (!mIsHeic && mStszTableEntries->count() == 0) {  // no samples written
-        ALOGE("The number of recorded samples is 0");
-        return true;
-    }
-
-    if (mIsVideo && mStssTableEntries->count() == 0) {  // no sync frames for video
-        ALOGE("There are no sync frames for video track");
-        return true;
+    int32_t emptyTrackMalformed = false;
+    if (mOwner->mStartMeta &&
+        mOwner->mStartMeta->findInt32(kKeyEmptyTrackMalFormed, &emptyTrackMalformed) &&
+        emptyTrackMalformed) {
+        if (!mIsHeic && mStszTableEntries->count() == 0) {  // no samples written
+            ALOGE("The number of recorded samples is 0");
+            return true;
+        }
+        if (mIsVideo && mStssTableEntries->count() == 0) {  // no sync frames for video
+            ALOGE("There are no sync frames for video track");
+            return true;
+        }
+    } else {
+        // No sync frames for video.
+        if (mIsVideo && mStszTableEntries->count() > 0 && mStssTableEntries->count() == 0) {
+            ALOGE("There are no sync frames for video track");
+            return true;
+        }
     }
 
     if (OK != checkCodecSpecificData()) {         // no codec specific data
@@ -3886,25 +3936,28 @@
 
 void MPEG4Writer::Track::writeStblBox() {
     mOwner->beginBox("stbl");
-    mOwner->beginBox("stsd");
-    mOwner->writeInt32(0);               // version=0, flags=0
-    mOwner->writeInt32(1);               // entry count
-    if (mIsAudio) {
-        writeAudioFourCCBox();
-    } else if (mIsVideo) {
-        writeVideoFourCCBox();
-    } else {
-        writeMetadataFourCCBox();
+    // Add subboxes only for non-empty tracks.
+    if (mStszTableEntries->count() > 0) {
+        mOwner->beginBox("stsd");
+        mOwner->writeInt32(0);               // version=0, flags=0
+        mOwner->writeInt32(1);               // entry count
+        if (mIsAudio) {
+            writeAudioFourCCBox();
+        } else if (mIsVideo) {
+            writeVideoFourCCBox();
+        } else {
+            writeMetadataFourCCBox();
+        }
+        mOwner->endBox();  // stsd
+        writeSttsBox();
+        if (mIsVideo) {
+            writeCttsBox();
+            writeStssBox();
+        }
+        writeStszBox();
+        writeStscBox();
+        writeCo64Box();
     }
-    mOwner->endBox();  // stsd
-    writeSttsBox();
-    if (mIsVideo) {
-        writeCttsBox();
-        writeStssBox();
-    }
-    writeStszBox();
-    writeStscBox();
-    writeCo64Box();
     mOwner->endBox();  // stbl
 }
 
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 3808d7e..1cb45ac 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -157,7 +157,6 @@
 
 status_t MediaMuxer::stop() {
     Mutex::Autolock autoLock(mMuxerLock);
-
     if (mState == STARTED || mState == ERROR) {
         mState = STOPPED;
         for (size_t i = 0; i < mTrackList.size(); i++) {
@@ -165,7 +164,10 @@
                 return INVALID_OPERATION;
             }
         }
+        // Unlock this mutex to allow notify to be called during stop process.
+        mMuxerLock.unlock();
         status_t err = mWriter->stop();
+        mMuxerLock.lock();
         if (err != OK || mError != OK) {
             ALOGE("stop err: %d, mError:%d", err, mError);
         }
@@ -217,6 +219,11 @@
         sampleMetaData.setInt32(kKeyIsMuxerData, 1);
     }
 
+    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+        sampleMetaData.setInt32(kKeyIsEndOfStream, 1);
+        ALOGV("BUFFER_FLAG_EOS");
+    }
+
     sp<MediaAdapter> currentTrack = mTrackList[trackIndex];
     // This pushBuffer will wait until the mediaBuffer is consumed.
     return currentTrack->pushBuffer(mediaBuffer);
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 9fe09fa..050d7c2 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -94,11 +94,16 @@
         return ERROR_UNSUPPORTED;
     }
 
+    status_t err = OK;
     if (!mCasToken.empty()) {
-        mImpl->setMediaCas(mCasToken);
+        err = mImpl->setMediaCas(mCasToken);
+        if (err != OK) {
+            ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+            return err;
+        }
     }
 
-    status_t err = updateDurationAndBitrate();
+    err = updateDurationAndBitrate();
     if (err == OK) {
         mDataSource = dataSource;
     }
@@ -131,7 +136,11 @@
     }
 
     if (!mCasToken.empty()) {
-        mImpl->setMediaCas(mCasToken);
+        err = mImpl->setMediaCas(mCasToken);
+        if (err != OK) {
+            ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+            return err;
+        }
     }
 
     err = updateDurationAndBitrate();
@@ -161,7 +170,11 @@
     }
 
     if (!mCasToken.empty()) {
-        mImpl->setMediaCas(mCasToken);
+        err = mImpl->setMediaCas(mCasToken);
+        if (err != OK) {
+            ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+            return err;
+        }
     }
 
     err = updateDurationAndBitrate();
@@ -195,8 +208,12 @@
     mCasToken = casToken;
 
     if (mImpl != NULL) {
-        mImpl->setMediaCas(casToken);
-        status_t err = updateDurationAndBitrate();
+        status_t err = mImpl->setMediaCas(casToken);
+        if (err != OK) {
+            ALOGE("%s: failed to setMediaCas (%d)", __FUNCTION__, err);
+            return err;
+        }
+        err = updateDurationAndBitrate();
         if (err != OK) {
             return err;
         }
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
index ea8b073..bcf63d5 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.bp
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -1,6 +1,7 @@
 cc_library {
     name: "libstagefright_amrnb_common",
     vendor_available: true,
+    host_supported: true,
 
     srcs: [
         "src/add.cpp",
@@ -73,6 +74,12 @@
         "-Werror",
     ],
 
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+
     //addressing b/25409744
     //sanitize: {
     //    misc_undefined: [
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.bp b/media/libstagefright/codecs/amrnb/dec/Android.bp
index e18117e..3381d2e 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.bp
+++ b/media/libstagefright/codecs/amrnb/dec/Android.bp
@@ -1,6 +1,7 @@
 cc_library_static {
     name: "libstagefright_amrnbdec",
     vendor_available: true,
+    host_supported: true,
 
     srcs: [
         "src/a_refl.cpp",
@@ -61,6 +62,12 @@
         "libstagefright_amrnb_common",
         "liblog",
     ],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 //###############################################################################
@@ -100,6 +107,7 @@
 cc_test {
     name: "libstagefright_amrnbdec_test",
     gtest: false,
+    host_supported: true,
 
     srcs: ["test/amrnbdec_test.cpp"],
 
@@ -118,6 +126,12 @@
         "liblog",
     ],
 
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+
     //sanitize: {
     //    misc_undefined: [
     //        "signed-integer-overflow",
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/Android.bp b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
new file mode 100644
index 0000000..54de1cc
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/Android.bp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+    name: "amrnb_dec_fuzzer",
+    host_supported: true,
+    srcs: [
+        "amrnb_dec_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libstagefright_amrnbdec",
+        "libstagefright_amrnb_common",
+        "liblog",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/README.md b/media/libstagefright/codecs/amrnb/fuzzer/README.md
new file mode 100644
index 0000000..7791b83
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/README.md
@@ -0,0 +1,62 @@
+# Fuzzer for libstagefright_amrnbdec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-NB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-NB supports the following parameters:
+1. Stream format (parameter name: `input_format`)
+2. 3GPP frame type (parameter name: `frame_type`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `input_format` | 0. `MIME_IETF` 1. `IF2` | Bit 0 (LSB) of 1st byte of data. |
+| `frame_type`   | 0. `AMR_475` 1. `AMR_515` 2. `AMR_59` 3. `AMR_67`  4. `AMR_74` 5. `AMR_795` 6. `AMR_102` 7. `AMR_122`  | Bits 3, 4 and 5 of 1st byte of data. |
+
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the decode operation was successful, the input is advanced by the frame size
+which is based on `input_format` and `frame_type` selected.
+If the decode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrnb_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) amrnb_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some amrnb files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/amrnb_dec_fuzzer/amrnb_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
new file mode 100644
index 0000000..d4e7e5c
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/fuzzer/amrnb_dec_fuzzer.cpp
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <string.h>
+#include <algorithm>
+#include "gsmamr_dec.h"
+
+// Constants for AMR-NB
+constexpr int32_t kSamplesPerFrame = L_FRAME;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const bitstream_format kBitStreamFormats[2] = {MIME_IETF, IF2};
+const int32_t kLocalWmfDecBytesPerFrame[8] = {12, 13, 15, 17, 19, 20, 26, 31};
+const int32_t kLocalIf2DecBytesPerFrame[8] = {13, 14, 16, 18, 19, 21, 26, 31};
+
+class Codec {
+ public:
+  Codec() = default;
+  ~Codec() { deInitDecoder(); }
+  int16_t initDecoder();
+  void deInitDecoder();
+  void decodeFrames(const uint8_t *data, size_t size);
+
+ private:
+  void *mAmrHandle = nullptr;
+};
+
+int16_t Codec::initDecoder() { return GSMInitDecode(&mAmrHandle, (Word8 *)"AMRNBDecoder"); }
+
+void Codec::deInitDecoder() { GSMDecodeFrameExit(&mAmrHandle); }
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+  while (size > 0) {
+    uint8_t mode = *data;
+    bool bit = mode & 0x01;
+    bitstream_format bitsreamFormat = kBitStreamFormats[bit];
+    int32_t frameSize = 0;
+    /* Find frame type */
+    Frame_Type_3GPP frameType = static_cast<Frame_Type_3GPP>((mode >> 3) & 0x07);
+    ++data;
+    --size;
+    if (bit) {
+      frameSize = kLocalIf2DecBytesPerFrame[frameType];
+    } else {
+      frameSize = kLocalWmfDecBytesPerFrame[frameType];
+    }
+    int16_t outputBuf[kOutputBufferSize];
+    uint8_t *inputBuf = new uint8_t[frameSize];
+    if (!inputBuf) {
+      return;
+    }
+    int32_t minSize = std::min((int32_t)size, frameSize);
+    memcpy(inputBuf, data, minSize);
+    AMRDecode(mAmrHandle, frameType, inputBuf, outputBuf, bitsreamFormat);
+    /* AMRDecode() decodes minSize number of bytes if decode is successful.
+     * AMRDecode() returns -1 if decode fails.
+     * Even if no bytes are decoded, increment by minSize to ensure fuzzer proceeds
+     * to feed next data */
+    data += minSize;
+    size -= minSize;
+    delete[] inputBuf;
+  }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 2) {
+    return 0;
+  }
+  Codec *codec = new Codec();
+  if (!codec) {
+    return 0;
+  }
+  if (codec->initDecoder() == 0) {
+    codec->decodeFrames(data, size);
+  }
+  delete codec;
+  return 0;
+}
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index 67d3f1a..dd2eed3 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -48,13 +48,13 @@
         </MediaCodec>
         <MediaCodec name="c2.android.g711.alaw.decoder" type="audio/g711-alaw">
             <Alias name="OMX.google.g711.alaw.decoder" />
-            <Limit name="channel-count" max="1" />
+            <Limit name="channel-count" max="6" />
             <Limit name="sample-rate" ranges="8000-48000" />
             <Limit name="bitrate" range="64000" />
         </MediaCodec>
         <MediaCodec name="c2.android.g711.mlaw.decoder" type="audio/g711-mlaw">
             <Alias name="OMX.google.g711.mlaw.decoder" />
-            <Limit name="channel-count" max="1" />
+            <Limit name="channel-count" max="6" />
             <Limit name="sample-rate" ranges="8000-48000" />
             <Limit name="bitrate" range="64000" />
         </MediaCodec>
@@ -67,7 +67,7 @@
         <MediaCodec name="c2.android.opus.decoder" type="audio/opus">
             <Alias name="OMX.google.opus.decoder" />
             <Limit name="channel-count" max="8" />
-            <Limit name="sample-rate" ranges="48000" />
+            <Limit name="sample-rate" ranges="8000,12000,16000,24000,48000" />
             <Limit name="bitrate" range="6000-510000" />
         </MediaCodec>
         <MediaCodec name="c2.android.raw.decoder" type="audio/raw">
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index b9cd18a..3b701f6 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -70,6 +70,7 @@
     kKeyIsSyncFrame       = 'sync',  // int32_t (bool)
     kKeyIsCodecConfig     = 'conf',  // int32_t (bool)
     kKeyIsMuxerData       = 'muxd',  // int32_t (bool)
+    kKeyIsEndOfStream     = 'feos',  // int32_t (bool)
     kKeyTime              = 'time',  // int64_t (usecs)
     kKeyDecodingTime      = 'decT',  // int64_t (decoding timestamp in usecs)
     kKeyNTPTime           = 'ntpT',  // uint64_t (ntp-timestamp)
@@ -237,6 +238,9 @@
     kKeyOpaqueCSD2       = 'csd2',
 
     kKeyHapticChannelCount = 'hapC',
+
+    // Treat empty track as malformed for MediaRecorder.
+    kKeyEmptyTrackMalFormed = 'nemt', // bool (int32_t)
 };
 
 enum {
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 1aa8a20..574bd7a 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -112,7 +112,9 @@
     sp<ABuffer> profileLevelID = NULL;
     if (GetAttribute(params, "profile-level-id", &val)) {
         profileLevelID = decodeHex(val);
-        CHECK_EQ(profileLevelID->size(), 3u);
+        if (profileLevelID != NULL && profileLevelID->size() != 3u) {
+            profileLevelID = NULL;
+        }
     }
 
     Vector<sp<ABuffer> > paramSets;
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index 409f141..ff063e3 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -243,6 +243,10 @@
     sp<MetaData> trackMeta = new MetaData;
     convertMessageToMetaData(format, trackMeta);
     mCurrentTrack = new MediaAdapter(trackMeta);
+    if (mCurrentTrack == nullptr) {
+        ALOGE("MediaAdapter returned nullptr");
+        return -1;
+    }
     status_t result = mWriter->addSource(mCurrentTrack);
     return result;
 }
@@ -301,7 +305,7 @@
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
 
-    getInputBufferInfo(inputFile, inputInfo);
+    ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
     status = addWriterSource(isAudio, param);
     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
 
@@ -338,7 +342,7 @@
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
 
-    getInputBufferInfo(inputFile, inputInfo);
+    ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
     status = addWriterSource(isAudio, param);
     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
 
@@ -397,7 +401,7 @@
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
     ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
 
-    getInputBufferInfo(inputFile, inputInfo);
+    ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
     status = addWriterSource(isAudio, param);
     ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
 
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 631a2ab..59ce8db 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -321,6 +321,7 @@
 status_t WebmFrameMediaSourceThread::pause() {
     if (mStarted) {
         mPaused = true;
+        mResumed = false;
     }
     return OK;
 }
diff --git a/media/libwatchdog/Android.bp b/media/libwatchdog/Android.bp
index 849623a..2aefa7d 100644
--- a/media/libwatchdog/Android.bp
+++ b/media/libwatchdog/Android.bp
@@ -19,10 +19,8 @@
     ],
     export_include_dirs: ["include"],
     shared_libs: [
-        "liblog",
-    ],
-    static_libs: [
         "libbase",
+        "liblog",
     ],
     target: {
         windows: {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e5a6e27..74a09d1 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -29,6 +29,7 @@
 #include <string>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <thread>
 
 #include <android/os/IExternalVibratorService.h>
 #include <binder/IPCThreadState.h>
@@ -144,6 +145,19 @@
     return sExternalVibratorService;
 }
 
+class DevicesFactoryHalCallbackImpl : public DevicesFactoryHalCallback {
+  public:
+    void onNewDevicesAvailable() override {
+        // Start a detached thread to execute notification in parallel.
+        // This is done to prevent mutual blocking of audio_flinger and
+        // audio_policy services during system initialization.
+        std::thread notifier([]() {
+            AudioSystem::onNewAudioModulesAvailable();
+        });
+        notifier.detach();
+    }
+};
+
 // ----------------------------------------------------------------------------
 
 std::string formatToString(audio_format_t format) {
@@ -227,6 +241,9 @@
     mMode = AUDIO_MODE_NORMAL;
 
     gAudioFlinger = this;
+
+    mDevicesFactoryHalCallback = new DevicesFactoryHalCallbackImpl;
+    mDevicesFactoryHal->setCallbackOnce(mDevicesFactoryHalCallback);
 }
 
 status_t AudioFlinger::setAudioHalPids(const std::vector<pid_t>& pids) {
@@ -833,7 +850,7 @@
                                       input.notificationsPerBuffer, input.speed,
                                       input.sharedBuffer, sessionId, &output.flags,
                                       callingPid, input.clientInfo.clientTid, clientUid,
-                                      &lStatus, portId);
+                                      &lStatus, portId, input.audioTrackCallback);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
         // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index a16fa94..6d7bf3c 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -33,6 +33,7 @@
 #include <sys/types.h>
 #include <limits.h>
 
+#include <android/media/IAudioTrackCallback.h>
 #include <android/os/BnExternalVibrationController.h>
 #include <android-base/macros.h>
 
@@ -104,6 +105,7 @@
 class AudioBuffer;
 class AudioResampler;
 class DeviceHalInterface;
+class DevicesFactoryHalCallback;
 class DevicesFactoryHalInterface;
 class EffectsFactoryHalInterface;
 class FastMixer;
@@ -836,6 +838,7 @@
                 DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>  mAudioHwDevs;
 
                 sp<DevicesFactoryHalInterface> mDevicesFactoryHal;
+                sp<DevicesFactoryHalCallback> mDevicesFactoryHalCallback;
 
     // for dump, indicates which hardware operation is currently in progress (but not stream ops)
     enum hardware_call_state {
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 2f3724f..82b9c96 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1395,7 +1395,11 @@
 
 void AudioFlinger::EffectChain::setVolumeForOutput_l(uint32_t left, uint32_t right)
 {
-    if (mEffectCallback->isOffloadOrDirect() && !isNonOffloadableEnabled_l()) {
+    // for offload or direct thread, if the effect chain has non-offloadable
+    // effect and any effect module within the chain has volume control, then
+    // volume control is delegated to effect, otherwise, set volume to hal.
+    if (mEffectCallback->isOffloadOrDirect() &&
+        !(isNonOffloadableEnabled_l() && hasVolumeControlEnabled_l())) {
         float vol_l = (float)left / (1 << 24);
         float vol_r = (float)right / (1 << 24);
         mEffectCallback->setVolumeForOutput(vol_l, vol_r);
@@ -2296,6 +2300,13 @@
     }
 }
 
+bool AudioFlinger::EffectChain::hasVolumeControlEnabled_l() const {
+    for (const auto &effect : mEffects) {
+        if (effect->isVolumeControlEnabled()) return true;
+    }
+    return false;
+}
+
 // setVolume_l() must be called with ThreadBase::mLock or EffectChain::mLock held
 bool AudioFlinger::EffectChain::setVolume_l(uint32_t *left, uint32_t *right, bool force)
 {
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 4901451..2826297 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -596,6 +596,9 @@
 
     void setThread(const sp<ThreadBase>& thread);
 
+    // true if any effect module within the chain has volume control
+    bool hasVolumeControlEnabled_l() const;
+
     void setVolumeForOutput_l(uint32_t left, uint32_t right);
 
     mutable  Mutex mLock;        // mutex protecting effect list
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2833525..f24dcd7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -42,6 +42,7 @@
 #include <private/media/AudioTrackShared.h>
 #include <private/android_filesystem_config.h>
 #include <audio_utils/Balance.h>
+#include <audio_utils/Metadata.h>
 #include <audio_utils/channels.h>
 #include <audio_utils/mono_blend.h>
 #include <audio_utils/primitives.h>
@@ -1921,6 +1922,16 @@
 
 void AudioFlinger::PlaybackThread::onFirstRef()
 {
+    if (mOutput == nullptr || mOutput->stream == nullptr) {
+        ALOGE("The stream is not open yet"); // This should not happen.
+    } else {
+        // setEventCallback will need a strong pointer as a parameter. Calling it
+        // here instead of constructor of PlaybackThread so that the onFirstRef
+        // callback would not be made on an incompletely constructed object.
+        if (mOutput->stream->setEventCallback(this) != OK) {
+            ALOGE("Failed to add event callback");
+        }
+    }
     run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
 }
 
@@ -2050,7 +2061,8 @@
         pid_t tid,
         uid_t uid,
         status_t *status,
-        audio_port_handle_t portId)
+        audio_port_handle_t portId,
+        const sp<media::IAudioTrackCallback>& callback)
 {
     size_t frameCount = *pFrameCount;
     size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2340,6 +2352,12 @@
             goto Exit;
         }
         mTracks.add(track);
+        {
+            Mutex::Autolock _atCbL(mAudioTrackCbLock);
+            if (callback.get() != nullptr) {
+                mAudioTrackCallbacks.emplace(callback);
+            }
+        }
 
         sp<EffectChain> chain = getEffectChain_l(sessionId);
         if (chain != 0) {
@@ -2642,6 +2660,29 @@
     mCallbackThread->setAsyncError();
 }
 
+void AudioFlinger::PlaybackThread::onCodecFormatChanged(
+        const std::basic_string<uint8_t>& metadataBs)
+{
+    std::thread([this, metadataBs]() {
+            audio_utils::metadata::Data metadata =
+                    audio_utils::metadata::dataFromByteString(metadataBs);
+            if (metadata.empty()) {
+                ALOGW("Can not transform the buffer to audio metadata, %s, %d",
+                      reinterpret_cast<char*>(const_cast<uint8_t*>(metadataBs.data())),
+                      (int)metadataBs.size());
+                return;
+            }
+
+            audio_utils::metadata::ByteString metaDataStr =
+                    audio_utils::metadata::byteStringFromData(metadata);
+            std::vector metadataVec(metaDataStr.begin(), metaDataStr.end());
+            Mutex::Autolock _l(mAudioTrackCbLock);
+            for (const auto& callback : mAudioTrackCallbacks) {
+                callback->onCodecFormatChanged(metadataVec);
+            }
+    }).detach();
+}
+
 void AudioFlinger::PlaybackThread::resetWriteBlocked(uint32_t sequence)
 {
     Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index b0eb75d..153cf7c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -720,7 +720,7 @@
 
 // --- PlaybackThread ---
 class PlaybackThread : public ThreadBase, public StreamOutHalInterfaceCallback,
-    public VolumeInterface {
+                       public VolumeInterface, public StreamOutHalInterfaceEventCallback {
 public:
 
 #include "PlaybackTracks.h"
@@ -796,6 +796,10 @@
     virtual     void        onAddNewTrack_l();
                 void        onAsyncError(); // error reported by AsyncCallbackThread
 
+    // StreamHalInterfaceCodecFormatCallback implementation
+                void        onCodecFormatChanged(
+                                const std::basic_string<uint8_t>& metadataBs) override;
+
     // ThreadBase virtuals
     virtual     void        preExit();
 
@@ -845,7 +849,8 @@
                                 pid_t tid,
                                 uid_t uid,
                                 status_t *status /*non-NULL*/,
-                                audio_port_handle_t portId);
+                                audio_port_handle_t portId,
+                                const sp<media::IAudioTrackCallback>& callback);
 
                 AudioStreamOut* getOutput() const;
                 AudioStreamOut* clearOutput();
@@ -1168,6 +1173,10 @@
     uint32_t                        mDrainSequence;
     sp<AsyncCallbackThread>         mCallbackThread;
 
+    Mutex                                    mAudioTrackCbLock;
+    // Record of IAudioTrackCallback
+    std::set<sp<media::IAudioTrackCallback>> mAudioTrackCallbacks;
+
 private:
     // The HAL output sink is treated as non-blocking, but current implementation is blocking
     sp<NBAIO_Sink>          mOutputSink;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 4d53be4..8d0e5db 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -83,6 +83,10 @@
     // configuration functions
     //
 
+    // Informs APM that new HAL modules are available. This typically happens
+    // due to registration of an audio HAL service.
+    virtual void onNewAudioModulesAvailable() = 0;
+
     // indicate a change in device connection status
     virtual status_t setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index e59386f..395bc70 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -37,13 +37,13 @@
 {
 public:
     AudioPolicyConfig(HwModuleCollection &hwModules,
-                      DeviceVector &availableOutputDevices,
-                      DeviceVector &availableInputDevices,
+                      DeviceVector &outputDevices,
+                      DeviceVector &inputDevices,
                       sp<DeviceDescriptor> &defaultOutputDevice)
         : mEngineLibraryNameSuffix(kDefaultEngineLibraryNameSuffix),
           mHwModules(hwModules),
-          mAvailableOutputDevices(availableOutputDevices),
-          mAvailableInputDevices(availableInputDevices),
+          mOutputDevices(outputDevices),
+          mInputDevices(inputDevices),
           mDefaultOutputDevice(defaultOutputDevice),
           mIsSpeakerDrcEnabled(false),
           mIsCallScreenModeSupported(false)
@@ -70,23 +70,23 @@
         mHwModules = hwModules;
     }
 
-    void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
+    void addDevice(const sp<DeviceDescriptor> &device)
     {
-        if (audio_is_output_device(availableDevice->type())) {
-            mAvailableOutputDevices.add(availableDevice);
-        } else if (audio_is_input_device(availableDevice->type())) {
-            mAvailableInputDevices.add(availableDevice);
+        if (audio_is_output_device(device->type())) {
+            mOutputDevices.add(device);
+        } else if (audio_is_input_device(device->type())) {
+            mInputDevices.add(device);
         }
     }
 
-    void addAvailableInputDevices(const DeviceVector &availableInputDevices)
+    void addInputDevices(const DeviceVector &inputDevices)
     {
-        mAvailableInputDevices.add(availableInputDevices);
+        mInputDevices.add(inputDevices);
     }
 
-    void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
+    void addOutputDevices(const DeviceVector &outputDevices)
     {
-        mAvailableOutputDevices.add(availableOutputDevices);
+        mOutputDevices.add(outputDevices);
     }
 
     bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
@@ -106,14 +106,14 @@
 
     const HwModuleCollection getHwModules() const { return mHwModules; }
 
-    const DeviceVector &getAvailableInputDevices() const
+    const DeviceVector &getInputDevices() const
     {
-        return mAvailableInputDevices;
+        return mInputDevices;
     }
 
-    const DeviceVector &getAvailableOutputDevices() const
+    const DeviceVector &getOutputDevices() const
     {
-        return mAvailableOutputDevices;
+        return mOutputDevices;
     }
 
     void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
@@ -134,13 +134,11 @@
         sp<AudioProfile> micProfile = new AudioProfile(
                 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
         defaultInputDevice->addAudioProfile(micProfile);
-        mAvailableOutputDevices.add(mDefaultOutputDevice);
-        mAvailableInputDevices.add(defaultInputDevice);
+        mOutputDevices.add(mDefaultOutputDevice);
+        mInputDevices.add(defaultInputDevice);
 
         sp<HwModule> module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY, 2 /*halVersionMajor*/);
         mHwModules.add(module);
-        mDefaultOutputDevice->attach(module);
-        defaultInputDevice->attach(module);
 
         sp<OutputProfile> outProfile = new OutputProfile("primary");
         outProfile->addAudioProfile(
@@ -191,8 +189,8 @@
     std::string mSource;
     std::string mEngineLibraryNameSuffix;
     HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
-    DeviceVector &mAvailableOutputDevices;
-    DeviceVector &mAvailableInputDevices;
+    DeviceVector &mOutputDevices;
+    DeviceVector &mInputDevices;
     sp<DeviceDescriptor> &mDefaultOutputDevice;
     // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
     // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index dd51658..aaa28bc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -33,7 +33,10 @@
 
 namespace android {
 
-DeviceTypeSet APM_AUDIO_OUT_DEVICE_REMOTE_ALL = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+static const DeviceTypeSet& getAllOutRemoteDevices() {
+    static const DeviceTypeSet allOutRemoteDevices = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+    return allOutRemoteDevices;
+}
 
 AudioOutputDescriptor::AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
                                              AudioPolicyClientInterface *clientInterface)
@@ -681,7 +684,7 @@
         const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
         if (outputDesc->isActive(volumeSource, inPastMs, sysTime)
                 && (!(outputDesc->devices()
-                        .containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL)))) {
+                        .containsDeviceAmongTypes(getAllOutRemoteDevices())))) {
             return true;
         }
     }
@@ -693,7 +696,7 @@
     nsecs_t sysTime = systemTime();
     for (size_t i = 0; i < size(); i++) {
         const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-        if (outputDesc->devices().containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL) &&
+        if (outputDesc->devices().containsDeviceAmongTypes(getAllOutRemoteDevices()) &&
                 outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
             // do not consider re routing (when the output is going to a dynamic policy)
             // as "remote playback"
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 1b2f7c7..883e713 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -653,7 +653,7 @@
                         sp<DeviceDescriptor> device = module->getDeclaredDevices().
                                 getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
                                                         attachedDevice.get())));
-                        ctx->addAvailableDevice(device);
+                        ctx->addDevice(device);
                     }
                 }
             }
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index a7d7cf6..b14d2bb 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -41,20 +41,23 @@
 {
 
 struct legacy_strategy_map { const char *name; legacy_strategy id; };
-static const std::vector<legacy_strategy_map> gLegacyStrategy = {
-    { "STRATEGY_NONE", STRATEGY_NONE },
-    { "STRATEGY_MEDIA", STRATEGY_MEDIA },
-    { "STRATEGY_PHONE", STRATEGY_PHONE },
-    { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
-    { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
-    { "STRATEGY_DTMF", STRATEGY_DTMF },
-    { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
-    { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
-    { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
-    { "STRATEGY_REROUTING", STRATEGY_REROUTING },
-    { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
-    { "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
-};
+static const std::vector<legacy_strategy_map>& getLegacyStrategy() {
+    static const std::vector<legacy_strategy_map> legacyStrategy = {
+        { "STRATEGY_NONE", STRATEGY_NONE },
+        { "STRATEGY_MEDIA", STRATEGY_MEDIA },
+        { "STRATEGY_PHONE", STRATEGY_PHONE },
+        { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
+        { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
+        { "STRATEGY_DTMF", STRATEGY_DTMF },
+        { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
+        { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
+        { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
+        { "STRATEGY_REROUTING", STRATEGY_REROUTING },
+        { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
+        { "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
+    };
+    return legacyStrategy;
+}
 
 Engine::Engine()
 {
@@ -63,7 +66,8 @@
              "Policy Engine configuration is partially invalid, skipped %zu elements",
              result.nbSkippedElement);
 
-    for (const auto &strategy : gLegacyStrategy) {
+    auto legacyStrategy = getLegacyStrategy();
+    for (const auto &strategy : legacyStrategy) {
         mLegacyStrategyMap[getProductStrategyByName(strategy.name)] = strategy.id;
     }
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0aa087a..5a012bf 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4397,7 +4397,7 @@
     mpClientInterface(clientInterface),
     mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
     mA2dpSuspended(false),
-    mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice),
+    mConfig(mHwModulesAll, mOutputDevicesAll, mInputDevicesAll, mDefaultOutputDevice),
     mAudioPortGeneration(1),
     mBeaconMuteRefCount(0),
     mBeaconPlayingRefCount(0),
@@ -4442,141 +4442,9 @@
         return status;
     }
 
-    // mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
+    // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
     // open all output streams needed to access attached devices
-    for (const auto& hwModule : mHwModulesAll) {
-        hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
-        if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
-            ALOGW("could not open HW module %s", hwModule->getName());
-            continue;
-        }
-        mHwModules.push_back(hwModule);
-        // open all output streams needed to access attached devices
-        // except for direct output streams that are only opened when they are actually
-        // required by an app.
-        // This also validates mAvailableOutputDevices list
-        for (const auto& outProfile : hwModule->getOutputProfiles()) {
-            if (!outProfile->canOpenNewIo()) {
-                ALOGE("Invalid Output profile max open count %u for profile %s",
-                      outProfile->maxOpenCount, outProfile->getTagName().c_str());
-                continue;
-            }
-            if (!outProfile->hasSupportedDevices()) {
-                ALOGW("Output profile contains no device on module %s", hwModule->getName());
-                continue;
-            }
-            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
-                mTtsOutputAvailable = true;
-            }
-
-            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
-                continue;
-            }
-            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
-            DeviceVector availProfileDevices = supportedDevices.filter(mAvailableOutputDevices);
-            sp<DeviceDescriptor> supportedDevice = 0;
-            if (supportedDevices.contains(mDefaultOutputDevice)) {
-                supportedDevice = mDefaultOutputDevice;
-            } else {
-                // choose first device present in profile's SupportedDevices also part of
-                // mAvailableOutputDevices.
-                if (availProfileDevices.isEmpty()) {
-                    continue;
-                }
-                supportedDevice = availProfileDevices.itemAt(0);
-            }
-            if (!mAvailableOutputDevices.contains(supportedDevice)) {
-                continue;
-            }
-            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
-                                                                                 mpClientInterface);
-            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-            status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
-                                               AUDIO_STREAM_DEFAULT,
-                                               AUDIO_OUTPUT_FLAG_NONE, &output);
-            if (status != NO_ERROR) {
-                ALOGW("Cannot open output stream for devices %s on hw module %s",
-                      supportedDevice->toString().c_str(), hwModule->getName());
-                continue;
-            }
-            for (const auto &device : availProfileDevices) {
-                // give a valid ID to an attached device once confirmed it is reachable
-                if (!device->isAttached()) {
-                    device->attach(hwModule);
-                }
-            }
-            if (mPrimaryOutput == 0 &&
-                    outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
-                mPrimaryOutput = outputDesc;
-            }
-            addOutput(output, outputDesc);
-            setOutputDevices(outputDesc,
-                             DeviceVector(supportedDevice),
-                             true,
-                             0,
-                             NULL);
-        }
-        // open input streams needed to access attached devices to validate
-        // mAvailableInputDevices list
-        for (const auto& inProfile : hwModule->getInputProfiles()) {
-            if (!inProfile->canOpenNewIo()) {
-                ALOGE("Invalid Input profile max open count %u for profile %s",
-                      inProfile->maxOpenCount, inProfile->getTagName().c_str());
-                continue;
-            }
-            if (!inProfile->hasSupportedDevices()) {
-                ALOGW("Input profile contains no device on module %s", hwModule->getName());
-                continue;
-            }
-            // chose first device present in profile's SupportedDevices also part of
-            // available input devices
-            const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
-            DeviceVector availProfileDevices = supportedDevices.filter(mAvailableInputDevices);
-            if (availProfileDevices.isEmpty()) {
-                ALOGE("%s: Input device list is empty!", __FUNCTION__);
-                continue;
-            }
-            sp<AudioInputDescriptor> inputDesc =
-                    new AudioInputDescriptor(inProfile, mpClientInterface);
-
-            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
-            status_t status = inputDesc->open(nullptr,
-                                              availProfileDevices.itemAt(0),
-                                              AUDIO_SOURCE_MIC,
-                                              AUDIO_INPUT_FLAG_NONE,
-                                              &input);
-            if (status != NO_ERROR) {
-                ALOGW("Cannot open input stream for device %s on hw module %s",
-                      availProfileDevices.toString().c_str(),
-                      hwModule->getName());
-                continue;
-            }
-            for (const auto &device : availProfileDevices) {
-                // give a valid ID to an attached device once confirmed it is reachable
-                if (!device->isAttached()) {
-                    device->attach(hwModule);
-                    device->importAudioPortAndPickAudioProfile(inProfile, true);
-                }
-            }
-            inputDesc->close();
-        }
-    }
-    // make sure all attached devices have been allocated a unique ID
-    auto checkAndSetAvailable = [this](auto& devices) {
-        for (size_t i = 0; i < devices.size();) {
-            const auto &device = devices[i];
-            if (!device->isAttached()) {
-                ALOGW("device %s is unreachable", device->toString().c_str());
-                devices.remove(device);
-                continue;
-            }
-            // Device is now validated and can be appended to the available devices of the engine
-            setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
-            i++;
-        }
-    };
-    checkAndSetAvailable(mAvailableOutputDevices);
-    checkAndSetAvailable(mAvailableInputDevices);
+    onNewAudioModulesAvailable();
 
     // make sure default device is reachable
     if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
@@ -4631,6 +4499,134 @@
 
 // ---
 
+void AudioPolicyManager::onNewAudioModulesAvailable()
+{
+    for (const auto& hwModule : mHwModulesAll) {
+        if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
+            continue;
+        }
+        hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
+        if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
+            ALOGW("could not open HW module %s", hwModule->getName());
+            continue;
+        }
+        mHwModules.push_back(hwModule);
+        // open all output streams needed to access attached devices
+        // except for direct output streams that are only opened when they are actually
+        // required by an app.
+        // This also validates mAvailableOutputDevices list
+        for (const auto& outProfile : hwModule->getOutputProfiles()) {
+            if (!outProfile->canOpenNewIo()) {
+                ALOGE("Invalid Output profile max open count %u for profile %s",
+                      outProfile->maxOpenCount, outProfile->getTagName().c_str());
+                continue;
+            }
+            if (!outProfile->hasSupportedDevices()) {
+                ALOGW("Output profile contains no device on module %s", hwModule->getName());
+                continue;
+            }
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+                mTtsOutputAvailable = true;
+            }
+
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+                continue;
+            }
+            const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+            DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
+            sp<DeviceDescriptor> supportedDevice = 0;
+            if (supportedDevices.contains(mDefaultOutputDevice)) {
+                supportedDevice = mDefaultOutputDevice;
+            } else {
+                // choose first device present in profile's SupportedDevices also part of
+                // mAvailableOutputDevices.
+                if (availProfileDevices.isEmpty()) {
+                    continue;
+                }
+                supportedDevice = availProfileDevices.itemAt(0);
+            }
+            if (!mOutputDevicesAll.contains(supportedDevice)) {
+                continue;
+            }
+            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
+                                                                                 mpClientInterface);
+            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+            status_t status = outputDesc->open(nullptr, DeviceVector(supportedDevice),
+                                               AUDIO_STREAM_DEFAULT,
+                                               AUDIO_OUTPUT_FLAG_NONE, &output);
+            if (status != NO_ERROR) {
+                ALOGW("Cannot open output stream for devices %s on hw module %s",
+                      supportedDevice->toString().c_str(), hwModule->getName());
+                continue;
+            }
+            for (const auto &device : availProfileDevices) {
+                // give a valid ID to an attached device once confirmed it is reachable
+                if (!device->isAttached()) {
+                    device->attach(hwModule);
+                    mAvailableOutputDevices.add(device);
+                    setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+                }
+            }
+            if (mPrimaryOutput == 0 &&
+                    outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
+                mPrimaryOutput = outputDesc;
+            }
+            addOutput(output, outputDesc);
+            setOutputDevices(outputDesc,
+                             DeviceVector(supportedDevice),
+                             true,
+                             0,
+                             NULL);
+        }
+        // open input streams needed to access attached devices to validate
+        // mAvailableInputDevices list
+        for (const auto& inProfile : hwModule->getInputProfiles()) {
+            if (!inProfile->canOpenNewIo()) {
+                ALOGE("Invalid Input profile max open count %u for profile %s",
+                      inProfile->maxOpenCount, inProfile->getTagName().c_str());
+                continue;
+            }
+            if (!inProfile->hasSupportedDevices()) {
+                ALOGW("Input profile contains no device on module %s", hwModule->getName());
+                continue;
+            }
+            // chose first device present in profile's SupportedDevices also part of
+            // available input devices
+            const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+            DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
+            if (availProfileDevices.isEmpty()) {
+                ALOGE("%s: Input device list is empty!", __FUNCTION__);
+                continue;
+            }
+            sp<AudioInputDescriptor> inputDesc =
+                    new AudioInputDescriptor(inProfile, mpClientInterface);
+
+            audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+            status_t status = inputDesc->open(nullptr,
+                                              availProfileDevices.itemAt(0),
+                                              AUDIO_SOURCE_MIC,
+                                              AUDIO_INPUT_FLAG_NONE,
+                                              &input);
+            if (status != NO_ERROR) {
+                ALOGW("Cannot open input stream for device %s on hw module %s",
+                      availProfileDevices.toString().c_str(),
+                      hwModule->getName());
+                continue;
+            }
+            for (const auto &device : availProfileDevices) {
+                // give a valid ID to an attached device once confirmed it is reachable
+                if (!device->isAttached()) {
+                    device->attach(hwModule);
+                    device->importAudioPortAndPickAudioProfile(inProfile, true);
+                    mAvailableInputDevices.add(device);
+                    setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
+                }
+            }
+            inputDesc->close();
+        }
+    }
+}
+
 void AudioPolicyManager::addOutput(audio_io_handle_t output,
                                    const sp<SwAudioOutputDescriptor>& outputDesc)
 {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index b0adbc7..8121f86 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -325,6 +325,8 @@
 
         bool isCallScreenModeSupported() override;
 
+        void onNewAudioModulesAvailable() override;
+
         status_t initialize();
 
 protected:
@@ -729,6 +731,8 @@
         SwAudioOutputCollection mPreviousOutputs;
         AudioInputCollection mInputs;     // list of input descriptors
 
+        DeviceVector  mOutputDevicesAll; // all output devices from the config
+        DeviceVector  mInputDevicesAll;  // all input devices from the config
         DeviceVector  mAvailableOutputDevices; // all available output devices
         DeviceVector  mAvailableInputDevices;  // all available input devices
 
@@ -739,9 +743,8 @@
 
         EffectDescriptorCollection mEffects;  // list of registered audio effects
         sp<DeviceDescriptor> mDefaultOutputDevice; // output device selected by default at boot time
-        HwModuleCollection mHwModules; // contains only modules that have been loaded successfully
-        HwModuleCollection mHwModulesAll; // normally not needed, used during construction and for
-                                          // dumps
+        HwModuleCollection mHwModules; // contains modules that have been loaded successfully
+        HwModuleCollection mHwModulesAll; // contains all modules declared in the config
 
         AudioPolicyConfig mConfig;
 
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 38801ec..0da3b9c 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -66,6 +66,14 @@
 
 // ----------------------------------------------------------------------------
 
+void AudioPolicyService::doOnNewAudioModulesAvailable()
+{
+    if (mAudioPolicyManager == NULL) return;
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    mAudioPolicyManager->onNewAudioModulesAvailable();
+}
+
 status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
                                                   audio_policy_dev_state_t state,
                                                   const char *device_address,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 99cec5a..bf38477 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -446,17 +446,19 @@
 
     sp<AudioRecordClient> topActive;
     sp<AudioRecordClient> latestActive;
+    sp<AudioRecordClient> topSensitiveActive;
     sp<AudioRecordClient> latestSensitiveActive;
 
     nsecs_t topStartNs = 0;
     nsecs_t latestStartNs = 0;
+    nsecs_t topSensitiveStartNs = 0;
     nsecs_t latestSensitiveStartNs = 0;
     bool isA11yOnTop = mUidPolicy->isA11yOnTop();
     bool isAssistantOnTop = false;
     bool isSensitiveActive = false;
     bool isInCall = mPhoneState == AUDIO_MODE_IN_CALL;
-    bool rttCallActive =
-            (mPhoneState == AUDIO_MODE_IN_CALL || mPhoneState == AUDIO_MODE_IN_COMMUNICATION)
+    bool isInCommunication = mPhoneState == AUDIO_MODE_IN_COMMUNICATION;
+    bool rttCallActive = (isInCall || isInCommunication)
             && mUidPolicy->isRttEnabled();
     bool onlyHotwordActive = true;
 
@@ -479,33 +481,47 @@
             continue;
         }
 
-        bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
         bool isAccessibility = mUidPolicy->isA11yUid(current->uid);
-        if (appState == APP_STATE_TOP && !isAccessibility) {
-            if (current->startTimeNs > topStartNs) {
-                topActive = current;
-                topStartNs = current->startTimeNs;
+        // Clients capturing for Accessibility services are not considered
+        // for top or latest active to avoid masking regular clients started before
+        if (!isAccessibility) {
+            bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
+            bool isPrivacySensitive =
+                    (current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0;
+            if (appState == APP_STATE_TOP) {
+                if (isPrivacySensitive) {
+                    if (current->startTimeNs > topSensitiveStartNs) {
+                        topSensitiveActive = current;
+                        topSensitiveStartNs = current->startTimeNs;
+                    }
+                } else {
+                    if (current->startTimeNs > topStartNs) {
+                        topActive = current;
+                        topStartNs = current->startTimeNs;
+                    }
+                }
+                if (isAssistant) {
+                    isAssistantOnTop = true;
+                }
             }
-            if (isAssistant) {
-                isAssistantOnTop = true;
+            // Clients capturing for HOTWORD are not considered
+            // for latest active to avoid masking regular clients started before
+            if (!(current->attributes.source == AUDIO_SOURCE_HOTWORD
+                    || ((isA11yOnTop || rttCallActive) && isAssistant))) {
+                if (isPrivacySensitive) {
+                    if (current->startTimeNs > latestSensitiveStartNs) {
+                        latestSensitiveActive = current;
+                        latestSensitiveStartNs = current->startTimeNs;
+                    }
+                    isSensitiveActive = true;
+                } else {
+                    if (current->startTimeNs > latestStartNs) {
+                        latestActive = current;
+                        latestStartNs = current->startTimeNs;
+                    }
+                }
             }
         }
-        // Client capturing for HOTWORD or Accessibility services not considered
-        // for latest active to avoid masking regular clients started before
-        if (current->startTimeNs > latestStartNs
-                && !(current->attributes.source == AUDIO_SOURCE_HOTWORD
-                        || ((isA11yOnTop || rttCallActive) && isAssistant))
-                && !isAccessibility) {
-            latestActive = current;
-            latestStartNs = current->startTimeNs;
-        }
-        if ((current->attributes.flags & AUDIO_FLAG_CAPTURE_PRIVATE) != 0) {
-            if (current->startTimeNs > latestSensitiveStartNs) {
-                latestSensitiveActive = current;
-                latestSensitiveStartNs = current->startTimeNs;
-            }
-            isSensitiveActive = true;
-        }
         if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
             onlyHotwordActive = false;
         }
@@ -514,6 +530,21 @@
     // if no active client with UI on Top, consider latest active as top
     if (topActive == nullptr) {
         topActive = latestActive;
+        topStartNs = latestStartNs;
+    }
+    if (topSensitiveActive == nullptr) {
+        topSensitiveActive = latestSensitiveActive;
+        topSensitiveStartNs = latestSensitiveStartNs;
+    }
+
+    // If both privacy sensitive and regular capture are active:
+    //  if the regular capture is privileged
+    //    allow concurrency
+    //  else
+    //    favor the privacy sensitive case
+    if (topActive != nullptr && topSensitiveActive != nullptr
+            && !topActive->canCaptureCallOrOutput) {
+        topActive = nullptr;
     }
 
     for (size_t i =0; i < mAudioRecordClients.size(); i++) {
@@ -524,8 +555,17 @@
 
         audio_source_t source = current->attributes.source;
         bool isTopOrLatestActive = topActive == nullptr ? false : current->uid == topActive->uid;
-        bool isLatestSensitive = latestSensitiveActive == nullptr ?
-                                 false : current->uid == latestSensitiveActive->uid;
+        bool isTopOrLatestSensitive = topSensitiveActive == nullptr ?
+                                 false : current->uid == topSensitiveActive->uid;
+
+        auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) {
+            bool canCaptureCall = recordClient->canCaptureCallOrOutput;
+            bool canCaptureCommunication = recordClient->canCaptureCallOrOutput
+                || recordClient->uid == mPhoneStateOwnerUid
+                || isServiceUid(mPhoneStateOwnerUid);
+            return !(isInCall && !canCaptureCall)
+                && !(isInCommunication && !canCaptureCommunication);
+        };
 
         // By default allow capture if:
         //     The assistant is not on TOP
@@ -533,9 +573,10 @@
         //     AND there is no active privacy sensitive capture or call
         //             OR client has CAPTURE_AUDIO_OUTPUT privileged permission
         bool allowCapture = !isAssistantOnTop
-                && ((isTopOrLatestActive && !isLatestSensitive) || isLatestSensitive)
-                && !(isSensitiveActive && !(isLatestSensitive || current->canCaptureCallOrOutput))
-                && !(isInCall && !current->canCaptureCallOrOutput);
+                && (isTopOrLatestActive || isTopOrLatestSensitive)
+                && !(isSensitiveActive
+                    && !(isTopOrLatestSensitive || current->canCaptureCallOrOutput))
+                && canCaptureIfInCallOrCommunication(current);
 
         if (isVirtualSource(source)) {
             // Allow capture for virtual (remote submix, call audio TX or RX...) sources
@@ -554,8 +595,9 @@
                 }
             } else {
                 if (((isAssistantOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
-                        source == AUDIO_SOURCE_HOTWORD) &&
-                        (!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) {
+                        source == AUDIO_SOURCE_HOTWORD)
+                        && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+                        && canCaptureIfInCallOrCommunication(current)) {
                     allowCapture = true;
                 }
             }
@@ -567,7 +609,8 @@
             //     OR
             //         Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
             if (!isAssistantOnTop
-                    && (!(isSensitiveActive || isInCall) || current->canCaptureCallOrOutput)) {
+                    && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+                    && canCaptureIfInCallOrCommunication(current)) {
                 allowCapture = true;
             }
             if (isA11yOnTop) {
@@ -580,7 +623,8 @@
             //     All active clients are using HOTWORD source
             //     AND no call is active
             //         OR client has CAPTURE_AUDIO_OUTPUT privileged permission
-            if (onlyHotwordActive && !(isInCall && !current->canCaptureCallOrOutput)) {
+            if (onlyHotwordActive
+                    && canCaptureIfInCallOrCommunication(current)) {
                 allowCapture = true;
             }
         }
@@ -1277,6 +1321,16 @@
                         mLock.lock();
                     }
                     } break;
+                case AUDIO_MODULES_UPDATE: {
+                    ALOGV("AudioCommandThread() processing audio modules update");
+                    svc = mService.promote();
+                    if (svc == 0) {
+                        break;
+                    }
+                    mLock.unlock();
+                    svc->doOnNewAudioModulesAvailable();
+                    mLock.lock();
+                    } break;
 
                 default:
                     ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
@@ -1566,6 +1620,13 @@
     sendCommand(command);
 }
 
+void AudioPolicyService::AudioCommandThread::audioModulesUpdateCommand()
+{
+    sp<AudioCommand> command = new AudioCommand();
+    command->mCommand = AUDIO_MODULES_UPDATE;
+    sendCommand(command);
+}
+
 status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
 {
     {
@@ -1813,6 +1874,11 @@
     mAudioCommandThread->setEffectSuspendedCommand(effectId, sessionId, suspended);
 }
 
+void AudioPolicyService::onNewAudioModulesAvailable()
+{
+    mAudioCommandThread->audioModulesUpdateCommand();
+}
+
 
 extern "C" {
 audio_module_handle_t aps_load_hw_module(void *service __unused,
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index c3c87f1..ff99124 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -60,6 +60,7 @@
     // BnAudioPolicyService (see AudioPolicyInterface for method descriptions)
     //
 
+    void onNewAudioModulesAvailable() override;
     virtual status_t setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
                                               const char *device_address,
@@ -277,6 +278,7 @@
 
             bool isCallScreenModeSupported() override;
 
+            void doOnNewAudioModulesAvailable();
             status_t doStopOutput(audio_port_handle_t portId);
             void doReleaseOutput(audio_port_handle_t portId);
 
@@ -463,6 +465,7 @@
             DYN_POLICY_MIX_STATE_UPDATE,
             RECORDING_CONFIGURATION_UPDATE,
             SET_EFFECT_SUSPENDED,
+            AUDIO_MODULES_UPDATE,
         };
 
         AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -508,6 +511,7 @@
                     void        setEffectSuspendedCommand(int effectId,
                                                           audio_session_t sessionId,
                                                           bool suspended);
+                    void        audioModulesUpdateCommand();
                     void        insertCommand_l(AudioCommand *command, int delayMs = 0);
     private:
         class AudioCommandData;
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index c2a92d7..af69466 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -15,6 +15,7 @@
  */
 
 #include <map>
+#include <set>
 
 #include <system/audio.h>
 #include <utils/Log.h>
@@ -27,7 +28,10 @@
 class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
 public:
     // AudioPolicyClientInterface implementation
-    audio_module_handle_t loadHwModule(const char * /*name*/) override {
+    audio_module_handle_t loadHwModule(const char* name) override {
+        if (!mAllowedModuleNames.empty() && !mAllowedModuleNames.count(name)) {
+            return AUDIO_MODULE_HANDLE_NONE;
+        }
         return mNextModuleHandle++;
     }
 
@@ -101,11 +105,18 @@
         return &it->second;
     };
 
+    audio_module_handle_t peekNextModuleHandle() const { return mNextModuleHandle; }
+
+    void swapAllowedModuleNames(std::set<std::string>&& names = {}) {
+        mAllowedModuleNames.swap(names);
+    }
+
 private:
     audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
     audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
     audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
     std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
+    std::set<std::string> mAllowedModuleNames;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index bafcc63..922a538 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -27,6 +27,8 @@
     using AudioPolicyManager::loadConfig;
     using AudioPolicyManager::initialize;
     using AudioPolicyManager::getOutputs;
+    using AudioPolicyManager::getAvailableOutputDevices;
+    using AudioPolicyManager::getAvailableInputDevices;
 };
 
 }  // namespace android
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index 8736cf1..b5c67a1 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -67,10 +67,10 @@
     manager.loadConfig();
     ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
 
-    for (auto desc : manager.getConfig().getAvailableInputDevices()) {
+    for (auto desc : manager.getConfig().getInputDevices()) {
         ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
     }
-    for (auto desc : manager.getConfig().getAvailableOutputDevices()) {
+    for (auto desc : manager.getConfig().getOutputDevices()) {
         ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
     }
 }
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 2a8349c..7d92f34 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -298,9 +298,9 @@
     audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
     uid_t uid = 42;
     const PatchCountCheck patchCount = snapshotPatchCount();
-    ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
+    ASSERT_FALSE(mManager->getAvailableInputDevices().isEmpty());
     PatchBuilder patchBuilder;
-    patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
+    patchBuilder.addSource(mManager->getAvailableInputDevices()[0]).
             addSink(mManager->getConfig().getDefaultOutputDevice());
     ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
     ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
@@ -334,15 +334,13 @@
     sp<AudioProfile> pcmInputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
     mMsdInputDevice->addAudioProfile(pcmInputProfile);
-    config.addAvailableDevice(mMsdOutputDevice);
-    config.addAvailableDevice(mMsdInputDevice);
+    config.addDevice(mMsdOutputDevice);
+    config.addDevice(mMsdInputDevice);
 
     sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
     HwModuleCollection modules = config.getHwModules();
     modules.add(msdModule);
     config.setHwModules(modules);
-    mMsdOutputDevice->attach(msdModule);
-    mMsdInputDevice->attach(msdModule);
 
     sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
     msdOutputProfile->addAudioProfile(pcmOutputProfile);
@@ -1127,3 +1125,40 @@
                     AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
             "low latency");
 }
+
+class AudioPolicyManagerDynamicHwModulesTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+    void SetUpManagerConfig() override;
+};
+
+void AudioPolicyManagerDynamicHwModulesTest::SetUpManagerConfig() {
+    AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig();
+    // Only allow successful opening of "primary" hw module during APM initialization.
+    mClient->swapAllowedModuleNames({"primary"});
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, DynamicAddition) {
+    const auto handleBefore = mClient->peekNextModuleHandle();
+    mManager->onNewAudioModulesAvailable();
+    ASSERT_EQ(handleBefore, mClient->peekNextModuleHandle());
+    // Reset module loading restrictions.
+    mClient->swapAllowedModuleNames();
+    mManager->onNewAudioModulesAvailable();
+    const auto handleAfter = mClient->peekNextModuleHandle();
+    ASSERT_GT(handleAfter, handleBefore);
+    mManager->onNewAudioModulesAvailable();
+    ASSERT_EQ(handleAfter, mClient->peekNextModuleHandle());
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, AddedDeviceAvailable) {
+    ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, mManager->getDeviceConnectionState(
+                    AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+    mClient->swapAllowedModuleNames({"primary", "r_submix"});
+    mManager->onNewAudioModulesAvailable();
+    ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, mManager->getDeviceConnectionState(
+                    AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
+}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 2de5c80..9bc79e0 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -126,6 +126,8 @@
 static const String16 sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
 static const String16
         sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
+static const String16 sCameraOpenCloseListenerPermission(
+        "android.permission.CAMERA_OPEN_CLOSE_LISTENER");
 
 // Matches with PERCEPTIBLE_APP_ADJ in ProcessList.java
 static constexpr int32_t kVendorClientScore = 200;
@@ -2146,6 +2148,8 @@
 
     auto clientUid = CameraThreadState::getCallingUid();
     auto clientPid = CameraThreadState::getCallingPid();
+    bool openCloseCallbackAllowed = checkPermission(sCameraOpenCloseListenerPermission,
+            clientPid, clientUid);
 
     Mutex::Autolock lock(mServiceLock);
 
@@ -2160,7 +2164,8 @@
         }
 
         sp<ServiceListener> serviceListener =
-                new ServiceListener(this, listener, clientUid, clientPid, isVendorListener);
+                new ServiceListener(this, listener, clientUid, clientPid, isVendorListener,
+                        openCloseCallbackAllowed);
         auto ret = serviceListener->initialize();
         if (ret != NO_ERROR) {
             String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
@@ -2923,6 +2928,9 @@
 
     sCameraService->mUidPolicy->registerMonitorUid(mClientUid);
 
+    // Notify listeners of camera open/close status
+    sCameraService->updateOpenCloseStatus(mCameraIdStr, true/*open*/, mClientPackageName);
+
     return OK;
 }
 
@@ -2963,6 +2971,9 @@
 
     sCameraService->mUidPolicy->unregisterMonitorUid(mClientUid);
 
+    // Notify listeners of camera open/close status
+    sCameraService->updateOpenCloseStatus(mCameraIdStr, false/*open*/, mClientPackageName);
+
     return OK;
 }
 
@@ -3759,6 +3770,29 @@
         });
 }
 
+void CameraService::updateOpenCloseStatus(const String8& cameraId, bool open,
+        const String16& clientPackageName) {
+    Mutex::Autolock lock(mStatusListenerLock);
+
+    for (const auto& it : mListenerList) {
+        if (!it->isOpenCloseCallbackAllowed()) {
+            continue;
+        }
+
+        binder::Status ret;
+        String16 cameraId64(cameraId);
+        if (open) {
+            ret = it->getListener()->onCameraOpened(cameraId64, clientPackageName);
+        } else {
+            ret = it->getListener()->onCameraClosed(cameraId64);
+        }
+        if (!ret.isOk()) {
+            ALOGE("%s: Failed to trigger onCameraOpened/onCameraClosed callback: %d", __FUNCTION__,
+                    ret.exceptionCode());
+        }
+    }
+}
+
 template<class Func>
 void CameraService::CameraState::updateStatus(StatusInternal status,
         const String8& cameraId,
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 751833e..1adf15a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -912,9 +912,10 @@
     class ServiceListener : public virtual IBinder::DeathRecipient {
         public:
             ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
-                    int uid, int pid, bool isVendorClient)
+                    int uid, int pid, bool isVendorClient, bool openCloseCallbackAllowed)
                     : mParent(parent), mListener(listener), mListenerUid(uid), mListenerPid(pid),
-                      mIsVendorListener(isVendorClient) { }
+                      mIsVendorListener(isVendorClient),
+                      mOpenCloseCallbackAllowed(openCloseCallbackAllowed) { }
 
             status_t initialize() {
                 return IInterface::asBinder(mListener)->linkToDeath(this);
@@ -931,6 +932,7 @@
             int getListenerPid() { return mListenerPid; }
             sp<hardware::ICameraServiceListener> getListener() { return mListener; }
             bool isVendorListener() { return mIsVendorListener; }
+            bool isOpenCloseCallbackAllowed() { return mOpenCloseCallbackAllowed; }
 
         private:
             wp<CameraService> mParent;
@@ -938,6 +940,7 @@
             int mListenerUid = -1;
             int mListenerPid = -1;
             bool mIsVendorListener = false;
+            bool mOpenCloseCallbackAllowed = false;
     };
 
     // Guarded by mStatusListenerMutex
@@ -960,6 +963,13 @@
     void updateStatus(StatusInternal status,
             const String8& cameraId);
 
+    /**
+     * Update the opened/closed status of the given camera id.
+     *
+     * This method acqiures mStatusListenerLock.
+     */
+    void updateOpenCloseStatus(const String8& cameraId, bool open, const String16& packageName);
+
     // flashlight control
     sp<CameraFlashlight> mFlashlight;
     // guard mTorchStatusMap
diff --git a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
index d7cc2bf..d36ca3b 100644
--- a/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
+++ b/services/camera/libcameraservice/api2/HeicEncoderInfoManager.cpp
@@ -91,6 +91,8 @@
             // The "measured-frame-rate-WIDTHxHEIGHT-range" key is optional.
             // Hardcode to some default value (3.33ms * tile count) based on resolution.
             *stall = 3333333LL * width * height / (kGridWidth * kGridHeight);
+            *useHeic = chooseHeic;
+            *useGrid = enableGrid;
             return true;
         }
 
@@ -275,9 +277,13 @@
             ALOGE("%s: Failed to get codec info for %s", __FUNCTION__, mime);
             break;
         }
+        ALOGV("%s: [%s] codec found", __FUNCTION__,
+                info->getCodecName());
 
         // Filter out software ones as they may be too slow
         if (!(info->getAttributes() & MediaCodecInfo::kFlagIsHardwareAccelerated)) {
+            ALOGV("%s: [%s] Filter out software ones as they may be too slow", __FUNCTION__,
+                    info->getCodecName());
             continue;
         }
 
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index aac49ef..cc369fa 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -326,8 +326,11 @@
 
     // Pass the camera ID to start interface so that it will save it to the map of ICameraProviders
     // that are currently in use.
-    const sp<provider::V2_4::ICameraProvider> interface =
-            deviceInfo->mParentProvider->startProviderInterface();
+    sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+    if (parentProvider == nullptr) {
+        return DEAD_OBJECT;
+    }
+    const sp<provider::V2_4::ICameraProvider> interface = parentProvider->startProviderInterface();
     if (interface == nullptr) {
         return DEAD_OBJECT;
     }
@@ -380,8 +383,11 @@
     if (deviceInfo == nullptr) return NAME_NOT_FOUND;
 
     auto *deviceInfo3 = static_cast<ProviderInfo::DeviceInfo3*>(deviceInfo);
-    const sp<provider::V2_4::ICameraProvider> provider =
-            deviceInfo->mParentProvider->startProviderInterface();
+    sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+    if (parentProvider == nullptr) {
+        return DEAD_OBJECT;
+    }
+    const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
     if (provider == nullptr) {
         return DEAD_OBJECT;
     }
@@ -423,8 +429,11 @@
     if (deviceInfo == nullptr) return NAME_NOT_FOUND;
 
     auto *deviceInfo1 = static_cast<ProviderInfo::DeviceInfo1*>(deviceInfo);
-    const sp<provider::V2_4::ICameraProvider> provider =
-            deviceInfo->mParentProvider->startProviderInterface();
+    sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
+    if (parentProvider == nullptr) {
+        return DEAD_OBJECT;
+    }
+    const sp<provider::V2_4::ICameraProvider> provider = parentProvider->startProviderInterface();
     if (provider == nullptr) {
         return DEAD_OBJECT;
     }
@@ -999,7 +1008,8 @@
         if (sizeAvail) continue;
 
         int64_t stall = 0;
-        bool useHeic, useGrid;
+        bool useHeic = false;
+        bool useGrid = false;
         if (camera3::HeicCompositeStream::isSizeSupportedByHeifEncoder(
                 halStreamConfigs.data.i32[i+1], halStreamConfigs.data.i32[i+2],
                 &useHeic, &useGrid, &stall)) {
@@ -2044,7 +2054,10 @@
     sp<InterfaceT> device;
     ATRACE_CALL();
     if (mSavedInterface == nullptr) {
-        device = mParentProvider->startDeviceInterface<InterfaceT>(mName);
+        sp<ProviderInfo> parentProvider = mParentProvider.promote();
+        if (parentProvider != nullptr) {
+            device = parentProvider->startDeviceInterface<InterfaceT>(mName);
+        }
     } else {
         device = (InterfaceT *) mSavedInterface.get();
     }
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 9a715b7..50044d8 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -447,7 +447,7 @@
             std::map<std::string, hardware::camera::common::V1_0::CameraDeviceStatus>
                     mPhysicalStatus;
 
-            sp<ProviderInfo> mParentProvider;
+            wp<ProviderInfo> mParentProvider;
 
             bool hasFlashUnit() const { return mHasFlashUnit; }
             bool supportNativeZoomRatio() const { return mSupportNativeZoomRatio; }
diff --git a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
index 95493a1..7148035 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
+++ b/services/camera/libcameraservice/hidl/AidlCameraServiceListener.h
@@ -58,6 +58,15 @@
         // TODO: no implementation yet.
         return binder::Status::ok();
     }
+    virtual binder::Status onCameraOpened(const ::android::String16& /*cameraId*/,
+            const ::android::String16& /*clientPackageId*/) {
+        // empty implementation
+        return binder::Status::ok();
+    }
+    virtual binder::Status onCameraClosed(const ::android::String16& /*cameraId*/) {
+        // empty implementation
+        return binder::Status::ok();
+    }
 };
 
 } // implementation
diff --git a/services/camera/libcameraservice/utils/ExifUtils.cpp b/services/camera/libcameraservice/utils/ExifUtils.cpp
index c0afdc1..8a0303a 100644
--- a/services/camera/libcameraservice/utils/ExifUtils.cpp
+++ b/services/camera/libcameraservice/utils/ExifUtils.cpp
@@ -603,13 +603,13 @@
 }
 
 bool ExifUtilsImpl::setImageHeight(uint32_t length) {
-    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
     SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
     return true;
 }
 
 bool ExifUtilsImpl::setImageWidth(uint32_t width) {
-    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
     SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
     return true;
 }
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index e2e1429..4bf103c 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -89,6 +89,31 @@
         "android.hidl.memory@1.0",
     ],
 
+    runtime_libs: [
+        "libstagefright_soft_aacdec",
+        "libstagefright_soft_aacenc",
+        "libstagefright_soft_amrdec",
+        "libstagefright_soft_amrnbenc",
+        "libstagefright_soft_amrwbenc",
+        "libstagefright_soft_avcdec",
+        "libstagefright_soft_avcenc",
+        "libstagefright_soft_flacdec",
+        "libstagefright_soft_flacenc",
+        "libstagefright_soft_g711dec",
+        "libstagefright_soft_gsmdec",
+        "libstagefright_soft_hevcdec",
+        "libstagefright_soft_mp3dec",
+        "libstagefright_soft_mpeg2dec",
+        "libstagefright_soft_mpeg4dec",
+        "libstagefright_soft_mpeg4enc",
+        "libstagefright_soft_opusdec",
+        "libstagefright_soft_rawdec",
+        "libstagefright_soft_vorbisdec",
+        "libstagefright_soft_vpxdec",
+        "libstagefright_soft_vpxenc",
+        "libstagefright_softomx_plugin",
+    ],
+
     // OMX interfaces force this to stay in 32-bit mode;
     compile_multilib: "32",
 
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 835f8bb..b4a9ff6 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -23,7 +23,7 @@
 # on ARM is statically loaded at 0xffff 0000. See
 # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
 # for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
 munmap: 1
 mprotect: 1
 madvise: 1
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm64.policy b/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
index 835f8bb..b4a9ff6 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm64.policy
@@ -23,7 +23,7 @@
 # on ARM is statically loaded at 0xffff 0000. See
 # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
 # for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
 munmap: 1
 mprotect: 1
 madvise: 1
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 512e675..9058f10 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -31,7 +31,7 @@
 # on ARM is statically loaded at 0xffff 0000. See
 # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
 # for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
 munmap: 1
 prctl: 1
 getuid32: 1
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index d9603ef..4c51a9c 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
@@ -35,7 +35,7 @@
 # on ARM is statically loaded at 0xffff 0000. See
 # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
 # for more details.
-mremap: arg3 == 3
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
 munmap: 1
 prctl: 1
 writev: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 07536fc..e1f7fe7 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -48,6 +48,14 @@
 # for dynamically loading extractors
 pread64: 1
 
+# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
+# parser support for '<' is in this needs to be modified to also prevent
+# |old_address| and |new_address| from touching the exception vector page, which
+# on ARM is statically loaded at 0xffff 0000. See
+# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
+# for more details.
+mremap: arg3 == 3 || arg3 == MREMAP_MAYMOVE
+
 # for FileSource
 readlinkat: 1
 _llseek: 1
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index 811e135..a6fefd2 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -113,6 +113,7 @@
     case AID_MEDIA_CODEC:
     case AID_MEDIA_EX:
     case AID_MEDIA_DRM:
+    // case AID_SHELL: // DEBUG ONLY - used for mediametrics_tests to add new keys
     case AID_SYSTEM:
         // trusted source, only override default values
         isTrusted = true;
@@ -145,9 +146,10 @@
         }
     }
 
-    ALOGV("%s: given uid %d; sanitized uid: %d sanitized pkg: %s "
+    ALOGV("%s: isTrusted:%d given uid %d; sanitized uid: %d sanitized pkg: %s "
           "sanitized pkg version: %lld",
           __func__,
+          (int)isTrusted,
           uid_given, item->getUid(),
           item->getPkgName().c_str(),
           (long long)item->getPkgVersionCode());
@@ -384,7 +386,7 @@
                 break;
             }
             if (now > when && (now - when) <= mMaxRecordAgeNs) {
-                break;  // TODO: if we use BOOTTIME, should be monotonic.
+                break; // Note SYSTEM_TIME_REALTIME may not be monotonic.
             }
             if (i >= mMaxRecordsExpiredAtOnce) {
                 // this represents "one too many"; tell caller there are
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
index e048d0e..a4c3693 100644
--- a/services/mediametrics/TimeMachine.h
+++ b/services/mediametrics/TimeMachine.h
@@ -93,7 +93,7 @@
 
         template <typename T>
         status_t getValue(const std::string &property, T* value, int64_t time = 0) const {
-            if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+            if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
             const auto tsptr = mPropertyMap.find(property);
             if (tsptr == mPropertyMap.end()) return BAD_VALUE;
             const auto& timeSequence = tsptr->second;
@@ -122,14 +122,25 @@
         template <typename T>
         void putValue(const std::string &property,
                 T&& e, int64_t time = 0) {
-            if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+            if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
             mLastModificationTime = time;
+            if (mPropertyMap.size() >= kKeyMaxProperties &&
+                    !mPropertyMap.count(property)) {
+                ALOGV("%s: too many properties, rejecting %s", __func__, property.c_str());
+                return;
+            }
             auto& timeSequence = mPropertyMap[property];
             Elem el{std::forward<T>(e)};
             if (timeSequence.empty()           // no elements
                     || property.back() == AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED
                     || timeSequence.rbegin()->second != el) { // value changed
                 timeSequence.emplace(time, std::move(el));
+
+                if (timeSequence.size() > kTimeSequenceMaxElements) {
+                    ALOGV("%s: restricting maximum elements (discarding oldest) for %s",
+                            __func__, property.c_str());
+                    timeSequence.erase(timeSequence.begin());
+                }
             }
         }
 
@@ -188,6 +199,8 @@
 
     using History = std::map<std::string /* key */, std::shared_ptr<KeyHistory>>;
 
+    static inline constexpr size_t kTimeSequenceMaxElements = 100;
+    static inline constexpr size_t kKeyMaxProperties = 100;
     static inline constexpr size_t kKeyLowWaterMark = 500;
     static inline constexpr size_t kKeyHighWaterMark = 1000;
 
@@ -239,6 +252,9 @@
         const int64_t time = item->getTimestamp();
         const std::string &key = item->getKey();
 
+        ALOGV("%s(%zu, %zu): key: %s  isTrusted:%d  size:%zu",
+                __func__, mKeyLowWaterMark, mKeyHighWaterMark,
+                key.c_str(), (int)isTrusted, item->count());
         std::shared_ptr<KeyHistory> keyHistory;
         {
             std::vector<std::any> garbage;
@@ -324,7 +340,7 @@
     /**
      * Individual property put.
      *
-     * Put takes in a time (if none is provided then BOOTTIME is used).
+     * Put takes in a time (if none is provided then SYSTEM_TIME_REALTIME is used).
      */
     template <typename T>
     status_t put(const std::string &url, T &&e, int64_t time = 0) {
@@ -333,7 +349,7 @@
         std::shared_ptr<KeyHistory> keyHistory =
             getKeyHistoryFromUrl(url, &key, &prop);
         if (keyHistory == nullptr) return BAD_VALUE;
-        if (time == 0) time = systemTime(SYSTEM_TIME_BOOTTIME);
+        if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
         std::lock_guard lock(getLockForKey(key));
         keyHistory->putValue(prop, std::forward<T>(e), time);
         return NO_ERROR;
@@ -446,6 +462,9 @@
     /**
      * Garbage collects if the TimeMachine size exceeds the high water mark.
      *
+     * This GC operation limits the number of keys stored (not the size of properties
+     * stored in each key).
+     *
      * \param garbage a type-erased vector of elements to be destroyed
      *        outside of lock.  Move large items to be destroyed here.
      *
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/TransactionLog.h
index 27e2c14..190a99e 100644
--- a/services/mediametrics/TransactionLog.h
+++ b/services/mediametrics/TransactionLog.h
@@ -264,7 +264,7 @@
         return ret;
     }
 
-    const size_t mLowWaterMark = kLogItemsHighWater;
+    const size_t mLowWaterMark = kLogItemsLowWater;
     const size_t mHighWaterMark = kLogItemsHighWater;
 
     mutable std::mutex mLock;
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 27b72eb..b8e566e 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -846,3 +846,21 @@
       ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
   }
 }
+
+#if 0
+// Stress test code for garbage collection, you need to enable AID_SHELL as trusted to run
+// in MediaMetricsService.cpp.
+//
+// TODO: Make a dedicated stress test.
+//
+TEST(mediametrics_tests, gc_same_key) {
+  // random keys ignored when empty
+  for (int i = 0; i < 10000000; ++i) {
+      std::unique_ptr<mediametrics::Item> test_key(mediametrics::Item::create("audio.zzz.123"));
+      test_key->set("event#", "hello");
+      test_key->set("value",  (int)10);
+      test_key->selfrecord();
+  }
+  //mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+#endif