Merge "libeffects: Rename .c files at lvm/lib to .cpp"
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index f56e1b5..bd6af83 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -22,6 +22,12 @@
 namespace.default.search.paths      = /apex/com.android.media.swcodec/${LIB}
 namespace.default.asan.search.paths = /apex/com.android.media.swcodec/${LIB}
 
+# Below lines are required to be able to access libs in APEXes which are
+# actually symlinks to the files under /system/lib. The symlinks exist for
+# bundled APEXes to reduce space.
+namespace.default.permitted.paths   = /system/${LIB}
+namespace.default.asan.permitted.paths = /system/${LIB}
+
 namespace.default.links = platform
 
 # TODO: replace the following when apex has a way to auto-generate this list
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index defc94f..7b447d3 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -23,6 +23,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_SYSTEM_EXT_MODULE:= true
 LOCAL_MODULE:= stagefright
 
 include $(BUILD_EXECUTABLE)
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 84f2f6d..52c7438 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -44,9 +44,11 @@
         "libcutils",
         "libdl",
         "liblog",
+        "libmedia",
         "libmediadrmmetrics_lite",
         "libmediametrics",
         "libmediautils",
+        "libresourcemanagerservice",
         "libstagefright_foundation",
         "libutils",
         "android.hardware.drm@1.0",
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index e79fd4b..a2234e6 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -295,38 +295,45 @@
     }
 }
 
-
 Mutex DrmHal::mLock;
 
-struct DrmSessionClient : public DrmSessionClientInterface {
-    explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}
-
-    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
-        sp<DrmHal> drm = mDrm.promote();
-        if (drm == NULL) {
-            return true;
-        }
-        status_t err = drm->closeSession(sessionId);
-        if (err != OK) {
-            return false;
-        }
-        drm->sendEvent(EventType::SESSION_RECLAIMED,
-                toHidlVec(sessionId), hidl_vec<uint8_t>());
+bool DrmHal::DrmSessionClient::reclaimResource() {
+    sp<DrmHal> drm = mDrm.promote();
+    if (drm == NULL) {
         return true;
     }
+    status_t err = drm->closeSession(mSessionId);
+    if (err != OK) {
+        return false;
+    }
+    drm->sendEvent(EventType::SESSION_RECLAIMED,
+            toHidlVec(mSessionId), hidl_vec<uint8_t>());
+    return true;
+}
 
-protected:
-    virtual ~DrmSessionClient() {}
+String8 DrmHal::DrmSessionClient::getName() {
+    String8 name;
+    sp<DrmHal> drm = mDrm.promote();
+    if (drm == NULL) {
+        name.append("<deleted>");
+    } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK
+        || name.isEmpty()) {
+      name.append("<Get vendor failed or is empty>");
+    }
+    name.append("[");
+    for (size_t i = 0; i < mSessionId.size(); ++i) {
+        name.appendFormat("%02x", mSessionId[i]);
+    }
+    name.append("]");
+    return name;
+}
 
-private:
-    wp<DrmHal> mDrm;
-
-    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
-};
+DrmHal::DrmSessionClient::~DrmSessionClient() {
+    DrmSessionManager::Instance()->removeSession(mSessionId);
+}
 
 DrmHal::DrmHal()
-   : mDrmSessionClient(new DrmSessionClient(this)),
-     mFactories(makeDrmFactories()),
+   : mFactories(makeDrmFactories()),
      mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
 }
 
@@ -335,14 +342,13 @@
     auto openSessions = mOpenSessions;
     for (size_t i = 0; i < openSessions.size(); i++) {
         mLock.unlock();
-        closeSession(openSessions[i]);
+        closeSession(openSessions[i]->mSessionId);
         mLock.lock();
     }
     mOpenSessions.clear();
 }
 
 DrmHal::~DrmHal() {
-    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
 }
 
 void DrmHal::cleanup() {
@@ -748,9 +754,9 @@
     } while (retry);
 
     if (err == OK) {
-        DrmSessionManager::Instance()->addSession(getCallingPid(),
-                mDrmSessionClient, sessionId);
-        mOpenSessions.push(sessionId);
+        sp<DrmSessionClient> client(new DrmSessionClient(this, sessionId));
+        DrmSessionManager::Instance()->addSession(getCallingPid(), client, sessionId);
+        mOpenSessions.push(client);
         mMetrics.SetSessionStart(sessionId);
     }
 
@@ -767,7 +773,7 @@
         if (status == Status::OK) {
             DrmSessionManager::Instance()->removeSession(sessionId);
             for (size_t i = 0; i < mOpenSessions.size(); i++) {
-                if (mOpenSessions[i] == sessionId) {
+                if (isEqualSessionId(mOpenSessions[i]->mSessionId, sessionId)) {
                     mOpenSessions.removeAt(i);
                     break;
                 }
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 375644c..0b927ef 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -21,12 +21,17 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IProcessInfoService.h>
 #include <binder/IServiceManager.h>
-#include <media/stagefright/ProcessInfo.h>
-#include <mediadrm/DrmSessionClientInterface.h>
+#include <cutils/properties.h>
+#include <media/IResourceManagerClient.h>
+#include <media/MediaResource.h>
 #include <mediadrm/DrmSessionManager.h>
 #include <unistd.h>
 #include <utils/String8.h>
 
+#include <vector>
+
+#include "ResourceManagerService.h"
+
 namespace android {
 
 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
@@ -37,6 +42,35 @@
     return sessionIdStr;
 }
 
+static std::vector<uint8_t> toStdVec(const Vector<uint8_t> &vector) {
+    const uint8_t *v = vector.array();
+    std::vector<uint8_t> vec(v, v + vector.size());
+    return vec;
+}
+
+static uint64_t toClientId(const sp<IResourceManagerClient>& drm) {
+    return reinterpret_cast<int64_t>(drm.get());
+}
+
+static Vector<MediaResource> toResourceVec(const Vector<uint8_t> &sessionId) {
+    Vector<MediaResource> resources;
+    // use UINT64_MAX to decrement through addition overflow
+    resources.push_back(MediaResource(MediaResource::kDrmSession, toStdVec(sessionId), UINT64_MAX));
+    return resources;
+}
+
+static sp<IResourceManagerService> getResourceManagerService() {
+    if (property_get_bool("persist.device_config.media_native.mediadrmserver", 1)) {
+        return new ResourceManagerService();
+    }
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == NULL) {
+        return NULL;
+    }
+    sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
+    return interface_cast<IResourceManagerService>(binder);
+}
+
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
     if (sessionId1.size() != sessionId2.size()) {
         return false;
@@ -51,189 +85,114 @@
 
 sp<DrmSessionManager> DrmSessionManager::Instance() {
     static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
+    drmSessionManager->init();
     return drmSessionManager;
 }
 
 DrmSessionManager::DrmSessionManager()
-    : mProcessInfo(new ProcessInfo()),
-      mTime(0) {}
+    : DrmSessionManager(getResourceManagerService()) {
+}
 
-DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
-    : mProcessInfo(processInfo),
-      mTime(0) {}
+DrmSessionManager::DrmSessionManager(const sp<IResourceManagerService> &service)
+    : mService(service),
+      mInitialized(false) {
+    if (mService == NULL) {
+        ALOGE("Failed to init ResourceManagerService");
+    }
+}
 
-DrmSessionManager::~DrmSessionManager() {}
+DrmSessionManager::~DrmSessionManager() {
+    if (mService != NULL) {
+        IInterface::asBinder(mService)->unlinkToDeath(this);
+    }
+}
 
-void DrmSessionManager::addSession(
-        int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t> &sessionId) {
-    ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
+void DrmSessionManager::init() {
+    Mutex::Autolock lock(mLock);
+    if (mInitialized) {
+        return;
+    }
+    mInitialized = true;
+    if (mService != NULL) {
+        IInterface::asBinder(mService)->linkToDeath(this);
+    }
+}
+
+void DrmSessionManager::addSession(int pid,
+        const sp<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
             GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    SessionInfo info;
-    info.drm = drm;
-    info.sessionId = sessionId;
-    info.timeStamp = getTime_l();
-    ssize_t index = mSessionMap.indexOfKey(pid);
-    if (index < 0) {
-        // new pid
-        SessionInfos infosForPid;
-        infosForPid.push_back(info);
-        mSessionMap.add(pid, infosForPid);
-    } else {
-        mSessionMap.editValueAt(index).push_back(info);
+    if (mService == NULL) {
+        return;
     }
+
+    int64_t clientId = toClientId(drm);
+    mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+    mService->addResource(pid, uid, clientId, drm, toResourceVec(sessionId));
 }
 
 void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
     ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
-            SessionInfo& info = infos.editItemAt(j);
-            if (isEqualSessionId(sessionId, info.sessionId)) {
-                info.timeStamp = getTime_l();
-                return;
-            }
-        }
+    auto it = mSessionMap.find(toStdVec(sessionId));
+    if (mService == NULL || it == mSessionMap.end()) {
+        return;
     }
+
+    auto info = it->second;
+    mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId));
 }
 
 void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
     ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
-            if (isEqualSessionId(sessionId, infos[j].sessionId)) {
-                infos.removeAt(j);
-                return;
-            }
-        }
+    auto it = mSessionMap.find(toStdVec(sessionId));
+    if (mService == NULL || it == mSessionMap.end()) {
+        return;
     }
-}
 
-void DrmSessionManager::removeDrm(const sp<DrmSessionClientInterface>& drm) {
-    ALOGV("removeDrm(%p)", drm.get());
-
-    Mutex::Autolock lock(mLock);
-    bool found = false;
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size();) {
-            if (infos[j].drm == drm) {
-                ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
-                j = infos.removeAt(j);
-                found = true;
-            } else {
-                ++j;
-            }
-        }
-        if (found) {
-            break;
-        }
-    }
+    auto info = it->second;
+    mService->removeResource(info.pid, info.clientId, toResourceVec(sessionId));
+    mSessionMap.erase(it);
 }
 
 bool DrmSessionManager::reclaimSession(int callingPid) {
     ALOGV("reclaimSession(%d)", callingPid);
 
-    sp<DrmSessionClientInterface> drm;
-    Vector<uint8_t> sessionId;
-    int lowestPriorityPid;
-    int lowestPriority;
-    {
-        Mutex::Autolock lock(mLock);
-        int callingPriority;
-        if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
-            return false;
-        }
-        if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
-            return false;
-        }
-        if (lowestPriority <= callingPriority) {
-            return false;
-        }
+    // unlock early because reclaimResource might callback into removeSession
+    mLock.lock();
+    sp<IResourceManagerService> service(mService);
+    mLock.unlock();
 
-        if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
-            return false;
-        }
-    }
-
-    if (drm == NULL) {
+    if (service == NULL) {
         return false;
     }
 
-    ALOGV("reclaim session(%s) opened by pid %d",
-            GetSessionIdString(sessionId).string(), lowestPriorityPid);
-
-    return drm->reclaimSession(sessionId);
+    // cannot update mSessionMap because we do not know which sessionId is reclaimed;
+    // we rely on IResourceManagerClient to removeSession in reclaimResource
+    Vector<uint8_t> dummy;
+    return service->reclaimResource(callingPid, toResourceVec(dummy));
 }
 
-int64_t DrmSessionManager::getTime_l() {
-    return mTime++;
+size_t DrmSessionManager::getSessionCount() const {
+    Mutex::Autolock lock(mLock);
+    return mSessionMap.size();
 }
 
-bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
-    int pid = -1;
-    int priority = -1;
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        if (mSessionMap.valueAt(i).size() == 0) {
-            // no opened session by this process.
-            continue;
-        }
-        int tempPid = mSessionMap.keyAt(i);
-        int tempPriority;
-        if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
-            // shouldn't happen.
-            return false;
-        }
-        if (pid == -1) {
-            pid = tempPid;
-            priority = tempPriority;
-        } else {
-            if (tempPriority > priority) {
-                pid = tempPid;
-                priority = tempPriority;
-            }
-        }
-    }
-    if (pid != -1) {
-        *lowestPriorityPid = pid;
-        *lowestPriority = priority;
-    }
-    return (pid != -1);
+bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
+    Mutex::Autolock lock(mLock);
+    return mSessionMap.count(toStdVec(sessionId));
 }
 
-bool DrmSessionManager::getLeastUsedSession_l(
-        int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
-    ssize_t index = mSessionMap.indexOfKey(pid);
-    if (index < 0) {
-        return false;
-    }
-
-    int leastUsedIndex = -1;
-    int64_t minTs = LLONG_MAX;
-    const SessionInfos& infos = mSessionMap.valueAt(index);
-    for (size_t j = 0; j < infos.size(); ++j) {
-        if (leastUsedIndex == -1) {
-            leastUsedIndex = j;
-            minTs = infos[j].timeStamp;
-        } else {
-            if (infos[j].timeStamp < minTs) {
-                leastUsedIndex = j;
-                minTs = infos[j].timeStamp;
-            }
-        }
-    }
-    if (leastUsedIndex != -1) {
-        *drm = infos[leastUsedIndex].drm;
-        *sessionId = infos[leastUsedIndex].sessionId;
-    }
-    return (leastUsedIndex != -1);
+void DrmSessionManager::binderDied(const wp<IBinder>& /*who*/) {
+    ALOGW("ResourceManagerService died.");
+    Mutex::Autolock lock(mLock);
+    mService.clear();
 }
 
 }  // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index bdf1b30..542d300 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -26,8 +26,10 @@
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
 #include <android/hardware/drm/1.2/IDrmPluginListener.h>
 
+#include <media/IResourceManagerService.h>
 #include <media/MediaAnalyticsItem.h>
 #include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
 #include <mediadrm/IDrm.h>
 #include <mediadrm/IDrmClient.h>
 #include <utils/threads.h>
@@ -59,6 +61,26 @@
 struct DrmHal : public BnDrm,
                 public IBinder::DeathRecipient,
                 public IDrmPluginListener_V1_2 {
+
+    struct DrmSessionClient : public BnResourceManagerClient {
+        explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
+          : mSessionId(sessionId),
+            mDrm(drm) {}
+
+        virtual bool reclaimResource();
+        virtual String8 getName();
+
+        const Vector<uint8_t> mSessionId;
+
+    protected:
+        virtual ~DrmSessionClient();
+
+    private:
+        wp<DrmHal> mDrm;
+
+        DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+    };
+
     DrmHal();
     virtual ~DrmHal();
 
@@ -193,8 +215,6 @@
 private:
     static Mutex mLock;
 
-    sp<DrmSessionClientInterface> mDrmSessionClient;
-
     sp<IDrmClient> mListener;
     mutable Mutex mEventLock;
     mutable Mutex mNotifyLock;
@@ -208,7 +228,7 @@
     // Mutable to allow modification within GetPropertyByteArray.
     mutable MediaDrmMetrics mMetrics;
 
-    Vector<Vector<uint8_t>> mOpenSessions;
+    Vector<sp<DrmSessionClient>> mOpenSessions;
     void closeOpenSessions();
     void cleanup();
 
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index ba27199..b1ad580 100644
--- a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -18,56 +18,61 @@
 
 #define DRM_SESSION_MANAGER_H_
 
+#include <binder/IBinder.h>
+#include <media/IResourceManagerService.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <utils/Vector.h>
 
+#include <map>
+#include <utility>
+#include <vector>
+
 namespace android {
 
 class DrmSessionManagerTest;
-struct DrmSessionClientInterface;
-struct ProcessInfoInterface;
+class IResourceManagerClient;
 
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
 
 struct SessionInfo {
-    sp<DrmSessionClientInterface> drm;
-    Vector<uint8_t> sessionId;
-    int64_t timeStamp;
+    pid_t pid;
+    uid_t uid;
+    int64_t clientId;
 };
 
-typedef Vector<SessionInfo > SessionInfos;
-typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;
+typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
 
-struct DrmSessionManager : public RefBase {
+struct DrmSessionManager : public IBinder::DeathRecipient {
     static sp<DrmSessionManager> Instance();
 
     DrmSessionManager();
-    explicit DrmSessionManager(sp<ProcessInfoInterface> processInfo);
+    explicit DrmSessionManager(const sp<IResourceManagerService> &service);
 
-    void addSession(int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t>& sessionId);
+    void addSession(int pid, const sp<IResourceManagerClient>& drm, const Vector<uint8_t>& sessionId);
     void useSession(const Vector<uint8_t>& sessionId);
     void removeSession(const Vector<uint8_t>& sessionId);
-    void removeDrm(const sp<DrmSessionClientInterface>& drm);
     bool reclaimSession(int callingPid);
 
+    // sanity check APIs
+    size_t getSessionCount() const;
+    bool containsSession(const Vector<uint8_t>& sessionId) const;
+
+    // implements DeathRecipient
+    virtual void binderDied(const wp<IBinder>& /*who*/);
+
 protected:
     virtual ~DrmSessionManager();
 
 private:
-    friend class DrmSessionManagerTest;
+    void init();
 
-    int64_t getTime_l();
-    bool getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority);
-    bool getLeastUsedSession_l(
-            int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId);
-
-    sp<ProcessInfoInterface> mProcessInfo;
+    sp<IResourceManagerService> mService;
     mutable Mutex mLock;
-    PidSessionInfosMap mSessionMap;
-    int64_t mTime;
+    SessionInfoMap mSessionMap;
+    bool mInitialized;
 
     DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
 };
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index fa98178..2be51dd 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -500,7 +500,7 @@
 status_t C2SoftAvcDec::initDecoder() {
     if (OK != createDecoder()) return UNKNOWN_ERROR;
     mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
-    mStride = ALIGN64(mWidth);
+    mStride = ALIGN128(mWidth);
     mSignalledError = false;
     resetPlugin();
     (void) setNumCores();
@@ -755,8 +755,8 @@
         ALOGE("not supposed to be here, invalid decoder context");
         return C2_CORRUPTED;
     }
-    if (mStride != ALIGN64(mWidth)) {
-        mStride = ALIGN64(mWidth);
+    if (mStride != ALIGN128(mWidth)) {
+        mStride = ALIGN128(mWidth);
         if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
     }
     if (mOutBlock &&
@@ -908,7 +908,7 @@
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
             if (mHeaderDecoded == false) {
                 mHeaderDecoded = true;
-                setParams(ALIGN64(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+                setParams(ALIGN128(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
             }
             if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
                 mWidth = s_decode_op.u4_pic_wd;
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index 4414a26..ed27493 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -40,6 +40,7 @@
 #define ivdext_ctl_get_vui_params_ip_t  ih264d_ctl_get_vui_params_ip_t
 #define ivdext_ctl_get_vui_params_op_t  ih264d_ctl_get_vui_params_op_t
 #define ALIGN64(x)                      ((((x) + 63) >> 6) << 6)
+#define ALIGN128(x)                     ((((x) + 127) >> 7) << 7)
 #define MAX_NUM_CORES                   4
 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
         (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index df677c2..6db4387 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -497,7 +497,7 @@
 status_t C2SoftHevcDec::initDecoder() {
     if (OK != createDecoder()) return UNKNOWN_ERROR;
     mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
-    mStride = ALIGN64(mWidth);
+    mStride = ALIGN128(mWidth);
     mSignalledError = false;
     resetPlugin();
     (void) setNumCores();
@@ -752,8 +752,8 @@
         ALOGE("not supposed to be here, invalid decoder context");
         return C2_CORRUPTED;
     }
-    if (mStride != ALIGN64(mWidth)) {
-        mStride = ALIGN64(mWidth);
+    if (mStride != ALIGN128(mWidth)) {
+        mStride = ALIGN128(mWidth);
         if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
     }
     if (mOutBlock &&
@@ -904,7 +904,7 @@
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
             if (mHeaderDecoded == false) {
                 mHeaderDecoded = true;
-                setParams(ALIGN64(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+                setParams(ALIGN128(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
             }
             if (s_decode_op.u4_pic_wd != mWidth ||  s_decode_op.u4_pic_ht != mHeight) {
                 mWidth = s_decode_op.u4_pic_wd;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.h b/media/codec2/components/hevc/C2SoftHevcDec.h
index ce63a6c..aecd101 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.h
+++ b/media/codec2/components/hevc/C2SoftHevcDec.h
@@ -38,6 +38,7 @@
 #define ivdext_ctl_get_vui_params_ip_t  ihevcd_cxa_ctl_get_vui_params_ip_t
 #define ivdext_ctl_get_vui_params_op_t  ihevcd_cxa_ctl_get_vui_params_op_t
 #define ALIGN64(x)                      ((((x) + 63) >> 6) << 6)
+#define ALIGN128(x)                     ((((x) + 127) >> 7) << 7)
 #define MAX_NUM_CORES                   4
 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
         (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 2efb987..375ce17 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -29,6 +29,7 @@
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <android-base/stringprintf.h>
 #include <binder/MemoryDealer.h>
+#include <cutils/properties.h>
 #include <gui/Surface.h>
 #include <media/openmax/OMX_Core.h>
 #include <media/stagefright/foundation/ABuffer.h>
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 52cc7ad..6fbad0a 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -71,6 +71,8 @@
         "libutils",
     ],
 
+    tidy: false, // b/146435095, clang-tidy segmentation fault
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index a58167a..53b394f 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: ["AACExtractor.cpp"],
 
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index 4bd933d..cd76062 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: ["AMRExtractor.cpp"],
 
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 3a3d051..c669b34 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: ["FLACExtractor.cpp"],
 
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index d36cb49..40c91e7 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: ["MidiExtractor.cpp"],
 
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 1744d3d..650d79d 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: ["MatroskaExtractor.cpp"],
 
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index 4e2f248..6f02b0f 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: [
             "MP3Extractor.cpp",
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index 1b308aa..d9f11fc 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -35,7 +35,7 @@
     compile_multilib: "first",
 }
 
-cc_library_shared {
+cc_library {
 
 
     name: "libmp4extractor",
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 1d9e1e6..14bd644 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: [
         "ExtractorBundle.cpp",
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index 604ec59..e661b5d 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: ["OggExtractor.cpp"],
 
diff --git a/media/extractors/tests/Android.bp b/media/extractors/tests/Android.bp
new file mode 100644
index 0000000..059c308
--- /dev/null
+++ b/media/extractors/tests/Android.bp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "ExtractorUnitTest",
+    gtest: true,
+
+    srcs: ["ExtractorUnitTest.cpp"],
+
+    static_libs: [
+        "libaacextractor",
+        "libamrextractor",
+        "libmp3extractor",
+        "libwavextractor",
+        "liboggextractor",
+        "libflacextractor",
+        "libmidiextractor",
+        "libmkvextractor",
+        "libmpeg2extractor",
+        "libmp4extractor",
+        "libaudioutils",
+        "libdatasource",
+
+        "libstagefright",
+        "libstagefright_id3",
+        "libstagefright_flacdec",
+        "libstagefright_esds",
+        "libstagefright_mpeg2support",
+        "libstagefright_mpeg2extractor",
+        "libstagefright_foundation",
+        "libstagefright_metadatautils",
+
+        "libmedia_midiiowrapper",
+        "libsonivox",
+        "libvorbisidec",
+        "libwebm",
+        "libFLAC",
+    ],
+
+    shared_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.token@1.0-utils",
+        "android.hidl.allocator@1.0",
+        "libbinder",
+        "libbinder_ndk",
+        "libutils",
+        "liblog",
+        "libcutils",
+        "libmediandk",
+        "libmedia",
+        "libcrypto",
+        "libhidlmemory",
+        "libhidlbase",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/extractors/",
+        "frameworks/av/media/libstagefright/",
+    ],
+
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    ldflags: [
+        "-Wl",
+        "-Bsymbolic",
+        // to ignore duplicate symbol: GETEXTRACTORDEF
+        "-z muldefs",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/extractors/tests/ExtractorUnitTest.cpp b/media/extractors/tests/ExtractorUnitTest.cpp
new file mode 100644
index 0000000..518166e
--- /dev/null
+++ b/media/extractors/tests/ExtractorUnitTest.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExtractorUnitTest"
+#include <utils/Log.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaDataUtils.h>
+
+#include "aac/AACExtractor.h"
+#include "amr/AMRExtractor.h"
+#include "flac/FLACExtractor.h"
+#include "midi/MidiExtractor.h"
+#include "mkv/MatroskaExtractor.h"
+#include "mp3/MP3Extractor.h"
+#include "mp4/MPEG4Extractor.h"
+#include "mp4/SampleTable.h"
+#include "mpeg2/MPEG2PSExtractor.h"
+#include "mpeg2/MPEG2TSExtractor.h"
+#include "ogg/OggExtractor.h"
+#include "wav/WAVExtractor.h"
+
+#include "ExtractorUnitTestEnvironment.h"
+
+using namespace android;
+
+#define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput"
+
+constexpr int32_t kMaxCount = 10;
+constexpr int32_t kOpusSeekPreRollUs = 80000;  // 80 ms;
+
+static ExtractorUnitTestEnvironment *gEnv = nullptr;
+
+class ExtractorUnitTest : public ::testing::TestWithParam<pair<string, string>> {
+  public:
+    ExtractorUnitTest() : mInputFp(nullptr), mDataSource(nullptr), mExtractor(nullptr) {}
+
+    ~ExtractorUnitTest() {
+        if (mInputFp) {
+            fclose(mInputFp);
+            mInputFp = nullptr;
+        }
+        if (mDataSource) {
+            mDataSource.clear();
+            mDataSource = nullptr;
+        }
+        if (mExtractor) {
+            delete mExtractor;
+            mExtractor = nullptr;
+        }
+    }
+
+    virtual void SetUp() override {
+        mExtractorName = unknown_comp;
+        mDisableTest = false;
+
+        static const std::map<std::string, standardExtractors> mapExtractor = {
+                {"aac", AAC},     {"amr", AMR},         {"mp3", MP3},        {"ogg", OGG},
+                {"wav", WAV},     {"mkv", MKV},         {"flac", FLAC},      {"midi", MIDI},
+                {"mpeg4", MPEG4}, {"mpeg2ts", MPEG2TS}, {"mpeg2ps", MPEG2PS}};
+        // Find the component type
+        string writerFormat = GetParam().first;
+        if (mapExtractor.find(writerFormat) != mapExtractor.end()) {
+            mExtractorName = mapExtractor.at(writerFormat);
+        }
+        if (mExtractorName == standardExtractors::unknown_comp) {
+            cout << "[   WARN   ] Test Skipped. Invalid extractor\n";
+            mDisableTest = true;
+        }
+    }
+
+    int32_t setDataSource(string inputFileName);
+
+    int32_t createExtractor();
+
+    enum standardExtractors {
+        AAC,
+        AMR,
+        FLAC,
+        MIDI,
+        MKV,
+        MP3,
+        MPEG4,
+        MPEG2PS,
+        MPEG2TS,
+        OGG,
+        WAV,
+        unknown_comp,
+    };
+
+    bool mDisableTest;
+    standardExtractors mExtractorName;
+
+    FILE *mInputFp;
+    sp<DataSource> mDataSource;
+    MediaExtractorPluginHelper *mExtractor;
+};
+
+int32_t ExtractorUnitTest::setDataSource(string inputFileName) {
+    mInputFp = fopen(inputFileName.c_str(), "rb");
+    if (!mInputFp) {
+        ALOGE("Unable to open input file for reading");
+        return -1;
+    }
+    struct stat buf;
+    stat(inputFileName.c_str(), &buf);
+    int32_t fd = fileno(mInputFp);
+    mDataSource = new FileSource(dup(fd), 0, buf.st_size);
+    if (!mDataSource) return -1;
+    return 0;
+}
+
+int32_t ExtractorUnitTest::createExtractor() {
+    switch (mExtractorName) {
+        case AAC:
+            mExtractor = new AACExtractor(new DataSourceHelper(mDataSource->wrap()), 0);
+            break;
+        case AMR:
+            mExtractor = new AMRExtractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case MP3:
+            mExtractor = new MP3Extractor(new DataSourceHelper(mDataSource->wrap()), nullptr);
+            break;
+        case OGG:
+            mExtractor = new OggExtractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case WAV:
+            mExtractor = new WAVExtractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case MKV:
+            mExtractor = new MatroskaExtractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case FLAC:
+            mExtractor = new FLACExtractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case MPEG4:
+            mExtractor = new MPEG4Extractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case MPEG2TS:
+            mExtractor = new MPEG2TSExtractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case MPEG2PS:
+            mExtractor = new MPEG2PSExtractor(new DataSourceHelper(mDataSource->wrap()));
+            break;
+        case MIDI:
+            mExtractor = new MidiExtractor(mDataSource->wrap());
+            break;
+        default:
+            return -1;
+    }
+    if (!mExtractor) return -1;
+    return 0;
+}
+
+void getSeekablePoints(vector<int64_t> &seekablePoints, MediaTrackHelper *track) {
+    int32_t status = 0;
+    if (!seekablePoints.empty()) {
+        seekablePoints.clear();
+    }
+    int64_t timeStamp;
+    while (status != AMEDIA_ERROR_END_OF_STREAM) {
+        MediaBufferHelper *buffer = nullptr;
+        status = track->read(&buffer);
+        if (buffer) {
+            AMediaFormat *metaData = buffer->meta_data();
+            int32_t isSync = 0;
+            AMediaFormat_getInt32(metaData, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, &isSync);
+            if (isSync) {
+                AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp);
+                seekablePoints.push_back(timeStamp);
+            }
+            buffer->release();
+        }
+    }
+}
+
+TEST_P(ExtractorUnitTest, CreateExtractorTest) {
+    if (mDisableTest) return;
+
+    ALOGV("Checks if a valid extractor is created for a given input file");
+    string inputFileName = gEnv->getRes() + GetParam().second;
+
+    ASSERT_EQ(setDataSource(inputFileName), 0)
+            << "SetDataSource failed for" << GetParam().first << "extractor";
+
+    ASSERT_EQ(createExtractor(), 0)
+            << "Extractor creation failed for" << GetParam().first << "extractor";
+
+    // A valid extractor instace should return success for following calls
+    ASSERT_GT(mExtractor->countTracks(), 0);
+
+    AMediaFormat *format = AMediaFormat_new();
+    ASSERT_NE(format, nullptr) << "AMediaFormat_new returned null AMediaformat";
+
+    ASSERT_EQ(mExtractor->getMetaData(format), AMEDIA_OK);
+    AMediaFormat_delete(format);
+}
+
+TEST_P(ExtractorUnitTest, ExtractorTest) {
+    if (mDisableTest) return;
+
+    ALOGV("Validates %s Extractor for a given input file", GetParam().first.c_str());
+    string inputFileName = gEnv->getRes() + GetParam().second;
+
+    int32_t status = setDataSource(inputFileName);
+    ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+    status = createExtractor();
+    ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+    int32_t numTracks = mExtractor->countTracks();
+    ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+    for (int32_t idx = 0; idx < numTracks; idx++) {
+        MediaTrackHelper *track = mExtractor->getTrack(idx);
+        ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+        CMediaTrack *cTrack = wrap(track);
+        ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+        MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+        status = cTrack->start(track, bufferGroup->wrap());
+        ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+
+        FILE *outFp = fopen((OUTPUT_DUMP_FILE + to_string(idx)).c_str(), "wb");
+        if (!outFp) {
+            ALOGW("Unable to open output file for dumping extracted stream");
+        }
+
+        while (status != AMEDIA_ERROR_END_OF_STREAM) {
+            MediaBufferHelper *buffer = nullptr;
+            status = track->read(&buffer);
+            ALOGV("track->read Status = %d buffer %p", status, buffer);
+            if (buffer) {
+                ALOGV("buffer->data %p buffer->size() %zu buffer->range_length() %zu",
+                      buffer->data(), buffer->size(), buffer->range_length());
+                if (outFp) fwrite(buffer->data(), 1, buffer->range_length(), outFp);
+                buffer->release();
+            }
+        }
+        if (outFp) fclose(outFp);
+        status = cTrack->stop(track);
+        ASSERT_EQ(OK, status) << "Failed to stop the track";
+        delete bufferGroup;
+        delete track;
+    }
+}
+
+TEST_P(ExtractorUnitTest, MetaDataComparisonTest) {
+    if (mDisableTest) return;
+
+    ALOGV("Validates Extractor's meta data for a given input file");
+    string inputFileName = gEnv->getRes() + GetParam().second;
+
+    int32_t status = setDataSource(inputFileName);
+    ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+    status = createExtractor();
+    ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+    int32_t numTracks = mExtractor->countTracks();
+    ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+    AMediaFormat *extractorFormat = AMediaFormat_new();
+    ASSERT_NE(extractorFormat, nullptr) << "AMediaFormat_new returned null AMediaformat";
+    AMediaFormat *trackFormat = AMediaFormat_new();
+    ASSERT_NE(trackFormat, nullptr) << "AMediaFormat_new returned null AMediaformat";
+
+    for (int32_t idx = 0; idx < numTracks; idx++) {
+        MediaTrackHelper *track = mExtractor->getTrack(idx);
+        ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+        CMediaTrack *cTrack = wrap(track);
+        ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+        MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+        status = cTrack->start(track, bufferGroup->wrap());
+        ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+
+        status = mExtractor->getTrackMetaData(extractorFormat, idx, 1);
+        ASSERT_EQ(OK, (media_status_t)status) << "Failed to get trackMetaData";
+
+        status = track->getFormat(trackFormat);
+        ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
+
+        const char *extractorMime, *trackMime;
+        AMediaFormat_getString(extractorFormat, AMEDIAFORMAT_KEY_MIME, &extractorMime);
+        AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &trackMime);
+        ASSERT_TRUE(!strcmp(extractorMime, trackMime))
+                << "Extractor's format doesn't match track format";
+
+        if (!strncmp(extractorMime, "audio/", 6)) {
+            int32_t exSampleRate, exChannelCount;
+            int32_t trackSampleRate, trackChannelCount;
+            ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+                                              &exChannelCount));
+            ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE,
+                                              &exSampleRate));
+            ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+                                              &trackChannelCount));
+            ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE,
+                                              &trackSampleRate));
+            ASSERT_EQ(exChannelCount, trackChannelCount) << "ChannelCount not as expected";
+            ASSERT_EQ(exSampleRate, trackSampleRate) << "SampleRate not as expected";
+        } else {
+            int32_t exWidth, exHeight;
+            int32_t trackWidth, trackHeight;
+            ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_WIDTH, &exWidth));
+            ASSERT_TRUE(AMediaFormat_getInt32(extractorFormat, AMEDIAFORMAT_KEY_HEIGHT, &exHeight));
+            ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_WIDTH, &trackWidth));
+            ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_HEIGHT, &trackHeight));
+            ASSERT_EQ(exWidth, trackWidth) << "Width not as expected";
+            ASSERT_EQ(exHeight, trackHeight) << "Height not as expected";
+        }
+        status = cTrack->stop(track);
+        ASSERT_EQ(OK, status) << "Failed to stop the track";
+        delete bufferGroup;
+        delete track;
+    }
+    AMediaFormat_delete(trackFormat);
+    AMediaFormat_delete(extractorFormat);
+}
+
+TEST_P(ExtractorUnitTest, MultipleStartStopTest) {
+    if (mDisableTest) return;
+
+    ALOGV("Test %s extractor for multiple start and stop calls", GetParam().first.c_str());
+    string inputFileName = gEnv->getRes() + GetParam().second;
+
+    int32_t status = setDataSource(inputFileName);
+    ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+    status = createExtractor();
+    ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+    int32_t numTracks = mExtractor->countTracks();
+    ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+    // start/stop the tracks multiple times
+    for (int32_t count = 0; count < kMaxCount; count++) {
+        for (int32_t idx = 0; idx < numTracks; idx++) {
+            MediaTrackHelper *track = mExtractor->getTrack(idx);
+            ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+            CMediaTrack *cTrack = wrap(track);
+            ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+            MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+            status = cTrack->start(track, bufferGroup->wrap());
+            ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+            MediaBufferHelper *buffer = nullptr;
+            status = track->read(&buffer);
+            if (buffer) {
+                ALOGV("buffer->data %p buffer->size() %zu buffer->range_length() %zu",
+                      buffer->data(), buffer->size(), buffer->range_length());
+                buffer->release();
+            }
+            status = cTrack->stop(track);
+            ASSERT_EQ(OK, status) << "Failed to stop the track";
+            delete bufferGroup;
+            delete track;
+        }
+    }
+}
+
+TEST_P(ExtractorUnitTest, SeekTest) {
+    // Both Flac and Wav extractor can give samples from any pts and mark the given sample as
+    // sync frame. So, this seek test is not applicable to FLAC and WAV extractors
+    if (mDisableTest || mExtractorName == FLAC || mExtractorName == WAV) return;
+
+    ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str());
+    string inputFileName = gEnv->getRes() + GetParam().second;
+
+    int32_t status = setDataSource(inputFileName);
+    ASSERT_EQ(status, 0) << "SetDataSource failed for" << GetParam().first << "extractor";
+
+    status = createExtractor();
+    ASSERT_EQ(status, 0) << "Extractor creation failed for" << GetParam().first << "extractor";
+
+    int32_t numTracks = mExtractor->countTracks();
+    ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+    uint32_t seekFlag = mExtractor->flags();
+    if (!(seekFlag & MediaExtractorPluginHelper::CAN_SEEK)) {
+        cout << "[   WARN   ] Test Skipped. " << GetParam().first
+             << " Extractor doesn't support seek\n";
+        return;
+    }
+
+    vector<int64_t> seekablePoints;
+    for (int32_t idx = 0; idx < numTracks; idx++) {
+        MediaTrackHelper *track = mExtractor->getTrack(idx);
+        ASSERT_NE(track, nullptr) << "Failed to get track for index " << idx;
+
+        CMediaTrack *cTrack = wrap(track);
+        ASSERT_NE(cTrack, nullptr) << "Failed to get track wrapper for index " << idx;
+
+        // Get all the seekable points of a given input
+        MediaBufferGroup *bufferGroup = new MediaBufferGroup();
+        status = cTrack->start(track, bufferGroup->wrap());
+        ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+        getSeekablePoints(seekablePoints, track);
+        ASSERT_GT(seekablePoints.size(), 0)
+                << "Failed to get seekable points for " << GetParam().first << " extractor";
+
+        AMediaFormat *trackFormat = AMediaFormat_new();
+        ASSERT_NE(trackFormat, nullptr) << "AMediaFormat_new returned null format";
+        status = track->getFormat(trackFormat);
+        ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
+
+        bool isOpus = false;
+        const char *mime;
+        AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
+        if (!strcmp(mime, "audio/opus")) isOpus = true;
+        AMediaFormat_delete(trackFormat);
+
+        int32_t seekIdx = 0;
+        size_t seekablePointsSize = seekablePoints.size();
+        for (int32_t mode = CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC;
+             mode <= CMediaTrackReadOptions::SEEK_CLOSEST; mode++) {
+            for (int32_t seekCount = 0; seekCount < kMaxCount; seekCount++) {
+                seekIdx = rand() % seekablePointsSize + 1;
+                if (seekIdx >= seekablePointsSize) seekIdx = seekablePointsSize - 1;
+
+                int64_t seekToTimeStamp = seekablePoints[seekIdx];
+                if (seekablePointsSize > 1) {
+                    int64_t prevTimeStamp = seekablePoints[seekIdx - 1];
+                    seekToTimeStamp = seekToTimeStamp - ((seekToTimeStamp - prevTimeStamp) >> 3);
+                }
+
+                // Opus has a seekPreRollUs. TimeStamp returned by the
+                // extractor is calculated based on (seekPts - seekPreRollUs).
+                // So we add the preRoll value to the timeStamp we want to seek to.
+                if (isOpus) {
+                    seekToTimeStamp += kOpusSeekPreRollUs;
+                }
+
+                MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
+                        mode | CMediaTrackReadOptions::SEEK, seekToTimeStamp);
+                ASSERT_NE(options, nullptr) << "Cannot create read option";
+
+                MediaBufferHelper *buffer = nullptr;
+                status = track->read(&buffer, options);
+                if (status == AMEDIA_ERROR_END_OF_STREAM) {
+                    delete options;
+                    continue;
+                }
+                if (buffer) {
+                    AMediaFormat *metaData = buffer->meta_data();
+                    int64_t timeStamp;
+                    AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp);
+                    buffer->release();
+
+                    // CMediaTrackReadOptions::SEEK is 8. Using mask 0111b to get true modes
+                    switch (mode & 0x7) {
+                        case CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC:
+                            if (seekablePointsSize == 1) {
+                                EXPECT_EQ(timeStamp, seekablePoints[seekIdx]);
+                            } else {
+                                EXPECT_EQ(timeStamp, seekablePoints[seekIdx - 1]);
+                            }
+                            break;
+                        case CMediaTrackReadOptions::SEEK_NEXT_SYNC:
+                        case CMediaTrackReadOptions::SEEK_CLOSEST_SYNC:
+                        case CMediaTrackReadOptions::SEEK_CLOSEST:
+                            EXPECT_EQ(timeStamp, seekablePoints[seekIdx]);
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                delete options;
+            }
+        }
+        status = cTrack->stop(track);
+        ASSERT_EQ(OK, status) << "Failed to stop the track";
+        delete bufferGroup;
+        delete track;
+    }
+    seekablePoints.clear();
+}
+
+// TODO: (b/145332185)
+// Add MIDI inputs
+INSTANTIATE_TEST_SUITE_P(ExtractorUnitTestAll, ExtractorUnitTest,
+                         ::testing::Values(make_pair("aac", "loudsoftaac.aac"),
+                                           make_pair("amr", "testamr.amr"),
+                                           make_pair("amr", "amrwb.wav"),
+                                           make_pair("ogg", "john_cage.ogg"),
+                                           make_pair("wav", "monotestgsm.wav"),
+                                           make_pair("mpeg2ts", "segment000001.ts"),
+                                           make_pair("flac", "sinesweepflac.flac"),
+                                           make_pair("ogg", "testopus.opus"),
+                                           make_pair("mkv", "sinesweepvorbis.mkv"),
+                                           make_pair("mpeg4", "sinesweepoggmp4.mp4"),
+                                           make_pair("mp3", "sinesweepmp3lame.mp3"),
+                                           make_pair("mkv", "swirl_144x136_vp9.webm"),
+                                           make_pair("mkv", "swirl_144x136_vp8.webm"),
+                                           make_pair("mpeg2ps", "swirl_144x136_mpeg2.mpg"),
+                                           make_pair("mpeg4", "swirl_132x130_mpeg4.mp4")));
+
+int main(int argc, char **argv) {
+    gEnv = new ExtractorUnitTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/extractors/tests/ExtractorUnitTestEnvironment.h b/media/extractors/tests/ExtractorUnitTestEnvironment.h
new file mode 100644
index 0000000..fce8fc2
--- /dev/null
+++ b/media/extractors/tests/ExtractorUnitTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__
+#define __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class ExtractorUnitTestEnvironment : public ::testing::Environment {
+  public:
+    ExtractorUnitTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int ExtractorUnitTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __EXTRACTOR_UNIT_TEST_ENVIRONMENT_H__
diff --git a/media/extractors/tests/README.md b/media/extractors/tests/README.md
new file mode 100644
index 0000000..6e02d3e
--- /dev/null
+++ b/media/extractors/tests/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### Extractor :
+The Extractor Test Suite validates the extractors available in the device.
+
+Run the following steps to build the test suite:
+```
+m ExtractorUnitTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/ExtractorUnitTest/ExtractorUnitTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/ExtractorUnitTest/ExtractorUnitTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/1Z9nCIRB6pGLvb5mPkF8BURa5Nc6cY9pY). Push these files into device for testing.
+Download extractor folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push extractor /data/local/tmp/
+```
+
+usage: ExtractorUnitTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/ExtractorUnitTest -P /data/local/tmp/extractor/
+```
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 7e89271..51e3c31 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
 
     srcs: ["WAVExtractor.cpp"],
 
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 5303631..6a8db22 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -474,7 +474,7 @@
 
 void AudioStream::MyPlayerBase::registerWithAudioManager() {
     if (!mRegistered) {
-        init(android::PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA);
+        init(android::PLAYER_TYPE_AAUDIO, AAudioConvert_usageToInternal(mParent->getUsage()));
         mRegistered = true;
     }
 }
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index cf11936..28190ea 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -48,12 +48,13 @@
                 effect_callback_t cbf,
                 void* user,
                 audio_session_t sessionId,
-                audio_io_handle_t io
+                audio_io_handle_t io,
+                const AudioDeviceTypeAddr& device
                 )
     : mStatus(NO_INIT), mOpPackageName(opPackageName)
 {
     AutoMutex lock(mConstructLock);
-    mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
+    mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device);
 }
 
 AudioEffect::AudioEffect(const char *typeStr,
@@ -63,7 +64,8 @@
                 effect_callback_t cbf,
                 void* user,
                 audio_session_t sessionId,
-                audio_io_handle_t io
+                audio_io_handle_t io,
+                const AudioDeviceTypeAddr& device
                 )
     : mStatus(NO_INIT), mOpPackageName(opPackageName)
 {
@@ -87,7 +89,7 @@
     }
 
     AutoMutex lock(mConstructLock);
-    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
+    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device);
 }
 
 status_t AudioEffect::set(const effect_uuid_t *type,
@@ -96,7 +98,8 @@
                 effect_callback_t cbf,
                 void* user,
                 audio_session_t sessionId,
-                audio_io_handle_t io)
+                audio_io_handle_t io,
+                const AudioDeviceTypeAddr& device)
 {
     sp<IEffect> iEffect;
     sp<IMemory> cblk;
@@ -109,6 +112,10 @@
         return INVALID_OPERATION;
     }
 
+    if (sessionId == AUDIO_SESSION_DEVICE && io != AUDIO_IO_HANDLE_NONE) {
+        ALOGW("IO handle should not be specified for device effect");
+        return BAD_VALUE;
+    }
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
     if (audioFlinger == 0) {
         ALOGE("set(): Could not get audioflinger");
@@ -133,7 +140,7 @@
     mClientPid = IPCThreadState::self()->getCallingPid();
 
     iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
-            mIEffectClient, priority, io, mSessionId, mOpPackageName, mClientPid,
+            mIEffectClient, priority, io, mSessionId, device, mOpPackageName, mClientPid,
             &mStatus, &mId, &enabled);
 
     if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
@@ -167,7 +174,7 @@
     ALOGV("set() %p OK effect: %s id: %d status %d enabled %d pid %d", this, mDescriptor.name, mId,
             mStatus, mEnabled, mClientPid);
 
-    if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
+    if (!audio_is_global_session(mSessionId)) {
         AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
     }
 
@@ -180,7 +187,7 @@
     ALOGV("Destructor %p", this);
 
     if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
-        if (mSessionId > AUDIO_SESSION_OUTPUT_MIX) {
+        if (!audio_is_global_session(mSessionId)) {
             AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
         }
         if (mIEffect != NULL) {
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cb9c7ba..480930b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1491,7 +1491,14 @@
             }
         }
     }
-    ALOGE("invalid attributes %s when converting to stream",  toString(attr).c_str());
+    switch (attr.usage) {
+        case AUDIO_USAGE_VIRTUAL_SOURCE:
+            // virtual source is not expected to have an associated product strategy
+            break;
+        default:
+            ALOGE("invalid attributes %s when converting to stream",  toString(attr).c_str());
+            break;
+    }
     return AUDIO_STREAM_MUSIC;
 }
 
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 90783eb..3f8b52b 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -658,6 +658,7 @@
                                     int32_t priority,
                                     audio_io_handle_t output,
                                     audio_session_t sessionId,
+                                    const AudioDeviceTypeAddr& device,
                                     const String16& opPackageName,
                                     pid_t pid,
                                     status_t *status,
@@ -666,12 +667,11 @@
     {
         Parcel data, reply;
         sp<IEffect> effect;
-
         if (pDesc == NULL) {
             if (status != NULL) {
                 *status = BAD_VALUE;
             }
-            return effect;
+            return nullptr;
         }
 
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -680,6 +680,12 @@
         data.writeInt32(priority);
         data.writeInt32((int32_t) output);
         data.writeInt32(sessionId);
+        if (data.writeParcelable(device) != NO_ERROR) {
+            if (status != NULL) {
+                *status = NO_INIT;
+            }
+            return nullptr;
+        }
         data.writeString16(opPackageName);
         data.writeInt32((int32_t) pid);
 
@@ -1378,14 +1384,18 @@
             int32_t priority = data.readInt32();
             audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
             audio_session_t sessionId = (audio_session_t) data.readInt32();
+            AudioDeviceTypeAddr device;
+            status_t status = NO_ERROR;
+            if ((status = data.readParcelable(&device)) != NO_ERROR) {
+                return status;
+            }
             const String16 opPackageName = data.readString16();
             pid_t pid = (pid_t)data.readInt32();
 
-            status_t status = NO_ERROR;
             int id = 0;
             int enabled = 0;
 
-            sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId,
+            sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId, device,
                     opPackageName, pid, &status, &id, &enabled);
             reply->writeInt32(status);
             reply->writeInt32(id);
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index 6bd4137..f17d737 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -362,17 +362,21 @@
      *      (AudioTrack or MediaPLayer) within the same audio session.
      * io:  HAL audio output or input stream to which this effect must be attached. Leave at 0 for
      *      automatic output selection by AudioFlinger.
+     * device: An audio device descriptor. Only used when "sessionID" is AUDIO_SESSION_DEVICE.
+     *         Specifies the audio device type and address the effect must be attached to.
+     *         If "sessionID" is AUDIO_SESSION_DEVICE then "io" must be AUDIO_IO_HANDLE_NONE.
      */
 
     AudioEffect(const effect_uuid_t *type,
                 const String16& opPackageName,
                 const effect_uuid_t *uuid = NULL,
-                  int32_t priority = 0,
-                  effect_callback_t cbf = NULL,
-                  void* user = NULL,
-                  audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
-                  audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
-                  );
+                int32_t priority = 0,
+                effect_callback_t cbf = NULL,
+                void* user = NULL,
+                audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+                audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+                const AudioDeviceTypeAddr& device = {}
+                );
 
     /* Constructor.
      *      Same as above but with type and uuid specified by character strings
@@ -384,7 +388,8 @@
                     effect_callback_t cbf = NULL,
                     void* user = NULL,
                     audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
-                    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
+                    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+                    const AudioDeviceTypeAddr& device = {}
                     );
 
     /* Terminates the AudioEffect and unregisters it from AudioFlinger.
@@ -406,7 +411,8 @@
                             effect_callback_t cbf = NULL,
                             void* user = NULL,
                             audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
-                            audio_io_handle_t io = AUDIO_IO_HANDLE_NONE
+                            audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+                            const AudioDeviceTypeAddr& device = {}
                             );
 
     /* Result of constructing the AudioEffect. This must be checked
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 8e8a1f5..1c35ff0 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -453,6 +453,7 @@
                                     // AudioFlinger doesn't take over handle reference from client
                                     audio_io_handle_t output,
                                     audio_session_t sessionId,
+                                    const AudioDeviceTypeAddr& device,
                                     const String16& callingPackage,
                                     pid_t pid,
                                     status_t *status,
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
index d390467..b44043a 100644
--- a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -26,6 +26,16 @@
     return mType == other.mType && mAddress == other.mAddress;
 }
 
+bool AudioDeviceTypeAddr::operator<(const AudioDeviceTypeAddr& other) const {
+    if (mType < other.mType)  return true;
+    if (mType > other.mType)  return false;
+
+    if (mAddress < other.mAddress)  return true;
+    // if (mAddress > other.mAddress)  return false;
+
+    return false;
+}
+
 void AudioDeviceTypeAddr::reset() {
     mType = AUDIO_DEVICE_NONE;
     mAddress = "";
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
index acc37ca..60ea78e 100644
--- a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -39,6 +39,8 @@
 
     AudioDeviceTypeAddr& operator= (const AudioDeviceTypeAddr&) = default;
 
+    bool operator<(const AudioDeviceTypeAddr& other) const;
+
     void reset();
 
     status_t readFromParcel(const Parcel *parcel) override;
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 42c16c0..f529cd1 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -28,6 +28,7 @@
 #include <common/all-versions/VersionUtils.h>
 
 #include "DeviceHalHidl.h"
+#include "EffectHalHidl.h"
 #include "HidlUtils.h"
 #include "StreamHalHidl.h"
 #include "VersionUtils.h"
@@ -43,6 +44,8 @@
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 using namespace ::android::hardware::audio::CPP_VERSION;
 
+using EffectHalHidl = ::android::effect::CPP_VERSION::EffectHalHidl;
+
 namespace {
 
 status_t deviceAddressFromHal(
@@ -385,6 +388,36 @@
 }
 #endif
 
+#if MAJOR_VERSION >= 6
+status_t DeviceHalHidl::addDeviceEffect(
+        audio_port_handle_t device, sp<EffectHalInterface> effect) {
+    if (mDevice == 0) return NO_INIT;
+    return processReturn("addDeviceEffect", mDevice->addDeviceEffect(
+            static_cast<AudioPortHandle>(device),
+            static_cast<EffectHalHidl*>(effect.get())->effectId()));
+}
+#else
+status_t DeviceHalHidl::addDeviceEffect(
+        audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+    return INVALID_OPERATION;
+}
+#endif
+
+#if MAJOR_VERSION >= 6
+status_t DeviceHalHidl::removeDeviceEffect(
+        audio_port_handle_t device, sp<EffectHalInterface> effect) {
+    if (mDevice == 0) return NO_INIT;
+    return processReturn("removeDeviceEffect", mDevice->removeDeviceEffect(
+            static_cast<AudioPortHandle>(device),
+            static_cast<EffectHalHidl*>(effect.get())->effectId()));
+}
+#else
+status_t DeviceHalHidl::removeDeviceEffect(
+        audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+    return INVALID_OPERATION;
+}
+#endif
+
 status_t DeviceHalHidl::dump(int fd) {
     if (mDevice == 0) return NO_INIT;
     native_handle_t* hidlHandle = native_handle_create(1, 0);
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index f7d465f..d342d4a 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -113,6 +113,9 @@
     // List microphones
     virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
+    status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+    status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
     virtual status_t dump(int fd);
 
   private:
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
index dfbb6b2..8021d92 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -206,6 +206,17 @@
 }
 #endif
 
+// Local HAL implementation does not support effects
+status_t DeviceHalLocal::addDeviceEffect(
+        audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+    return INVALID_OPERATION;
+}
+
+status_t DeviceHalLocal::removeDeviceEffect(
+        audio_port_handle_t device __unused, sp<EffectHalInterface> effect __unused) {
+    return INVALID_OPERATION;
+}
+
 status_t DeviceHalLocal::dump(int fd) {
     return mDev->dump(mDev, fd);
 }
diff --git a/media/libaudiohal/impl/DeviceHalLocal.h b/media/libaudiohal/impl/DeviceHalLocal.h
index 36db72e..d85e2a7 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.h
+++ b/media/libaudiohal/impl/DeviceHalLocal.h
@@ -106,6 +106,9 @@
     // List microphones
     virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
+    status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+    status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
     virtual status_t dump(int fd);
 
     void closeOutputStream(struct audio_stream_out *stream_out);
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
index ba7b195..867b72d 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.cpp
@@ -105,12 +105,26 @@
 
 status_t EffectsFactoryHalHidl::createEffect(
         const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t ioId,
-        sp<EffectHalInterface> *effect) {
+        int32_t deviceId __unused, sp<EffectHalInterface> *effect) {
     if (mEffectsFactory == 0) return NO_INIT;
     Uuid hidlUuid;
     HidlUtils::uuidFromHal(*pEffectUuid, &hidlUuid);
     Result retval = Result::NOT_INITIALIZED;
-    Return<void> ret = mEffectsFactory->createEffect(
+    Return<void> ret;
+#if MAJOR_VERSION >= 6
+    ret = mEffectsFactory->createEffect(
+            hidlUuid, sessionId, ioId, deviceId,
+            [&](Result r, const sp<IEffect>& result, uint64_t effectId) {
+                retval = r;
+                if (retval == Result::OK) {
+                    *effect = new EffectHalHidl(result, effectId);
+                }
+            });
+#else
+    if (sessionId == AUDIO_SESSION_DEVICE && ioId == AUDIO_IO_HANDLE_NONE) {
+        return INVALID_OPERATION;
+    }
+    ret = mEffectsFactory->createEffect(
             hidlUuid, sessionId, ioId,
             [&](Result r, const sp<IEffect>& result, uint64_t effectId) {
                 retval = r;
@@ -118,6 +132,7 @@
                     *effect = new EffectHalHidl(result, effectId);
                 }
             });
+#endif
     if (ret.isOk()) {
         if (retval == Result::OK) return OK;
         else if (retval == Result::INVALID_ARGUMENTS) return NAME_NOT_FOUND;
diff --git a/media/libaudiohal/impl/EffectsFactoryHalHidl.h b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
index 2828513..dece1bb 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalHidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalHidl.h
@@ -49,7 +49,7 @@
     // To release the effect engine, it is necessary to release references
     // to the returned effect object.
     virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
-            int32_t sessionId, int32_t ioId,
+            int32_t sessionId, int32_t ioId, int32_t deviceId,
             sp<EffectHalInterface> *effect);
 
     virtual status_t dumpEffects(int fd);
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 2200a7f..1e04b21 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_HARDWARE_DEVICE_HAL_INTERFACE_H
 #define ANDROID_HARDWARE_DEVICE_HAL_INTERFACE_H
 
+#include <media/audiohal/EffectHalInterface.h>
 #include <media/MicrophoneInfo.h>
 #include <system/audio.h>
 #include <utils/Errors.h>
@@ -111,6 +112,11 @@
     // List microphones
     virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
 
+    virtual status_t addDeviceEffect(
+            audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
+    virtual status_t removeDeviceEffect(
+            audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
+
     virtual status_t dump(int fd) = 0;
 
   protected:
diff --git a/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
index 316a46c..3a76f9f 100644
--- a/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/EffectsFactoryHalInterface.h
@@ -41,7 +41,7 @@
     // To release the effect engine, it is necessary to release references
     // to the returned effect object.
     virtual status_t createEffect(const effect_uuid_t *pEffectUuid,
-            int32_t sessionId, int32_t ioId,
+            int32_t sessionId, int32_t ioId, int32_t deviceId,
             sp<EffectHalInterface> *effect) = 0;
 
     virtual status_t dumpEffects(int fd) = 0;
diff --git a/media/libaudioprocessing/BufferProviders.cpp b/media/libaudioprocessing/BufferProviders.cpp
index 21d25e1..6d31c12 100644
--- a/media/libaudioprocessing/BufferProviders.cpp
+++ b/media/libaudioprocessing/BufferProviders.cpp
@@ -164,6 +164,7 @@
     if (mEffectsFactory->createEffect(&sDwnmFxDesc.uuid,
                                       sessionId,
                                       SESSION_ID_INVALID_AND_IGNORED,
+                                      AUDIO_PORT_HANDLE_NONE,
                                       &mDownmixInterface) != 0) {
          ALOGE("DownmixerBufferProvider() error creating downmixer effect");
          mDownmixInterface.clear();
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
index 5fa9da9..8476f82 100644
--- a/media/libeffects/config/Android.bp
+++ b/media/libeffects/config/Android.bp
@@ -13,6 +13,8 @@
     shared_libs: [
         "liblog",
         "libtinyxml2",
+        "libutils",
+        "libmedia_helper",
     ],
 
     header_libs: ["libaudio_system_headers"],
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index fa0415b..ef10e0d 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -76,6 +76,10 @@
 using OutputStream = Stream<audio_stream_type_t>;
 using InputStream = Stream<audio_source_t>;
 
+struct DeviceEffects : Stream<audio_devices_t> {
+    std::string address;
+};
+
 /** Parsed configuration.
  * Intended to be a transient structure only used for deserialization.
  * Note: Everything is copied in the configuration from the xml dom.
@@ -89,6 +93,7 @@
     Effects effects;
     std::vector<OutputStream> postprocess;
     std::vector<InputStream> preprocess;
+    std::vector<DeviceEffects> deviceprocess;
 };
 
 /** Result of `parse(const char*)` */
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index f39eb0c..85fbf11 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -26,6 +26,7 @@
 #include <log/log.h>
 
 #include <media/EffectsConfig.h>
+#include <media/TypeConverter.h>
 
 using namespace tinyxml2;
 
@@ -100,6 +101,7 @@
         {AUDIO_STREAM_ENFORCED_AUDIBLE, "enforced_audible"},
         {AUDIO_STREAM_DTMF, "dtmf"},
         {AUDIO_STREAM_TTS, "tts"},
+        {AUDIO_STREAM_ASSISTANT, "assistant"},
 };
 
 /** All input stream types which support effects.
@@ -116,6 +118,8 @@
         {AUDIO_SOURCE_VOICE_COMMUNICATION, "voice_communication"},
         {AUDIO_SOURCE_UNPROCESSED, "unprocessed"},
         {AUDIO_SOURCE_VOICE_PERFORMANCE, "voice_performance"},
+        {AUDIO_SOURCE_ECHO_REFERENCE, "echo_reference"},
+        {AUDIO_SOURCE_FM_TUNER, "fm_tuner"},
 };
 
 /** Find the stream type enum corresponding to the stream type name or return false */
@@ -131,6 +135,11 @@
     return false;
 }
 
+template <>
+bool stringToStreamType(const char *streamName, audio_devices_t* type) {
+    return deviceFromString(streamName, *type);
+}
+
 /** Parse a library xml note and push the result in libraries or return false on failure. */
 bool parseLibrary(const XMLElement& xmlLibrary, Libraries* libraries) {
     const char* name = xmlLibrary.Attribute("name");
@@ -218,7 +227,7 @@
     return true;
 }
 
-/** Parse an stream from an xml element describing it.
+/** Parse an <Output|Input>stream or a device from an xml element describing it.
  * @return true and pushes the stream in streams on success,
  *         false on failure. */
 template <class Stream>
@@ -230,14 +239,14 @@
     }
     Stream stream;
     if (!stringToStreamType(streamType, &stream.type)) {
-        ALOGE("Invalid stream type %s: %s", streamType, dump(xmlStream));
+        ALOGE("Invalid <stream|device> type %s: %s", streamType, dump(xmlStream));
         return false;
     }
 
     for (auto& xmlApply : getChildren(xmlStream, "apply")) {
         const char* effectName = xmlApply.get().Attribute("effect");
         if (effectName == nullptr) {
-            ALOGE("stream/apply must have reference an effect: %s", dump(xmlApply));
+            ALOGE("<stream|device>/apply must have reference an effect: %s", dump(xmlApply));
             return false;
         }
         auto* effect = findByName(effectName, effects);
@@ -251,6 +260,21 @@
     return true;
 }
 
+bool parseDeviceEffects(
+        const XMLElement& xmlDevice, Effects& effects, std::vector<DeviceEffects>* deviceEffects) {
+
+    const char* address = xmlDevice.Attribute("address");
+    if (address == nullptr) {
+        ALOGE("device must have an address: %s", dump(xmlDevice));
+        return false;
+    }
+    if (!parseStream(xmlDevice, effects, deviceEffects)) {
+        return false;
+    }
+    deviceEffects->back().address = address;
+    return true;
+}
+
 /** Internal version of the public parse(const char* path) where path always exist. */
 ParsingResult parseWithPath(std::string&& path) {
     XMLDocument doc;
@@ -295,6 +319,14 @@
                 registerFailure(parseStream(xmlStream, config->effects, &config->postprocess));
             }
         }
+
+        // Parse device effect chains
+        for (auto& xmlDeviceEffects : getChildren(xmlConfig, "deviceEffects")) {
+            for (auto& xmlDevice : getChildren(xmlDeviceEffects, "devicePort")) {
+                registerFailure(
+                            parseDeviceEffects(xmlDevice, config->effects, &config->deviceprocess));
+            }
+        }
     }
     return {std::move(config), nbSkippedElements, std::move(path)};
 }
diff --git a/media/libeffects/data/audio_effects.xml b/media/libeffects/data/audio_effects.xml
index 3f85052..2e5f529 100644
--- a/media/libeffects/data/audio_effects.xml
+++ b/media/libeffects/data/audio_effects.xml
@@ -99,4 +99,31 @@
         </postprocess>
     -->
 
+     <!-- Device pre/post processor configurations.
+          The device pre/post processor configuration is described in a deviceEffects element and
+          consists in a list of elements each describing pre/post proecessor settings for a given
+          device or "devicePort".
+          Each devicePort element has a "type" attribute corresponding to the device type (e.g.
+          speaker, bus), an "address" attribute corresponding to the device address and contains a
+          list of "apply" elements indicating one effect to apply.
+          If the device is a source, only pre processing effects are expected, if the
+          device is a sink, only post processing effects are expected.
+          The effect to apply is designated by its name in the "effects" elements.
+          The effect will be enabled by default and the audio framework will automatically add
+          and activate the effect if the given port is involved in an audio patch.
+          If the patch is "HW", the effect must be HW accelerated.
+
+        <deviceEffects>
+            <devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS00_USAGE_MAIN">
+                <apply effect="equalizer"/>
+            </devicePort>
+            <devicePort type="AUDIO_DEVICE_OUT_BUS" address="BUS04_USAGE_VOICE">
+                <apply effect="volume"/>
+            </devicePort>
+            <devicePort type="AUDIO_DEVICE_IN_BUILTIN_MIC" address="bottom">
+                <apply effect="agc"/>
+            </devicePort>
+        </deviceEffects>
+    -->
+
 </audio_effects_conf>
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index c1ce513..dcdf634 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -254,7 +254,8 @@
     return ret;
 }
 
-int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
+int doEffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, int32_t deviceId,
+        effect_handle_t *pHandle)
 {
     list_elem_t *e = gLibraryList;
     lib_entry_t *l = NULL;
@@ -268,9 +269,9 @@
     }
 
     ALOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
-            uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
-            uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
-            uuid->node[3],uuid->node[4],uuid->node[5]);
+          uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
+          uuid->clockSeq, uuid->node[0], uuid->node[1], uuid->node[2],
+          uuid->node[3], uuid->node[4], uuid->node[5]);
 
     ret = init();
 
@@ -282,17 +283,29 @@
     pthread_mutex_lock(&gLibLock);
 
     ret = findEffect(NULL, uuid, &l, &d);
-    if (ret < 0){
+    if (ret < 0) {
         // Sub effects are not associated with the library->effects,
         // so, findEffect will fail. Search for the effect in gSubEffectList.
         ret = findSubEffect(uuid, &l, &d);
-        if (ret < 0 ) {
+        if (ret < 0) {
             goto exit;
         }
     }
 
     // create effect in library
-    ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
+    if (sessionId == AUDIO_SESSION_DEVICE) {
+        if (l->desc->version >= EFFECT_LIBRARY_API_VERSION_3_1) {
+            ALOGI("EffectCreate() create_effect_3_1");
+            ret = l->desc->create_effect_3_1(uuid, sessionId, ioId, deviceId, &itfe);
+        } else {
+            ALOGE("EffectCreate() cannot create device effect on library with API version < 3.1");
+            ret = -ENOSYS;
+        }
+    } else {
+        ALOGI("EffectCreate() create_effect");
+        ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
+    }
+
     if (ret != 0) {
         ALOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
         goto exit;
@@ -324,6 +337,16 @@
     return ret;
 }
 
+int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId,
+        effect_handle_t *pHandle) {
+    return doEffectCreate(uuid, sessionId, ioId, AUDIO_PORT_HANDLE_NONE, pHandle);
+}
+
+int EffectCreateOnDevice(const effect_uuid_t *uuid, int32_t deviceId, int32_t ioId,
+        effect_handle_t *pHandle) {
+    return doEffectCreate(uuid, AUDIO_SESSION_DEVICE, ioId, deviceId, pHandle);
+}
+
 int EffectRelease(effect_handle_t handle)
 {
     effect_entry_t *fx;
diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h
index 29dbc9c..1936343 100644
--- a/media/libeffects/factory/EffectsFactory.h
+++ b/media/libeffects/factory/EffectsFactory.h
@@ -27,6 +27,8 @@
 extern "C" {
 #endif
 
+#define EFFECT_LIBRARY_API_VERSION_CURRENT EFFECT_LIBRARY_API_VERSION_3_1
+
 #define PROPERTY_IGNORE_EFFECTS "ro.audio.ignore_effects"
 
 typedef struct list_elem_s {
diff --git a/media/libeffects/factory/EffectsXmlConfigLoader.cpp b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
index 052a88b..505be7c 100644
--- a/media/libeffects/factory/EffectsXmlConfigLoader.cpp
+++ b/media/libeffects/factory/EffectsXmlConfigLoader.cpp
@@ -94,7 +94,7 @@
     }
 
     uint32_t majorVersion = EFFECT_API_VERSION_MAJOR(description->version);
-    uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION);
+    uint32_t expectedMajorVersion = EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION_CURRENT);
     if (majorVersion != expectedMajorVersion) {
         ALOGE("Unsupported major version %#08x, expected %#08x for library %s",
               majorVersion, expectedMajorVersion, path);
diff --git a/media/libeffects/factory/include/media/EffectsFactoryApi.h b/media/libeffects/factory/include/media/EffectsFactoryApi.h
index a5a12eb..8f7239e 100644
--- a/media/libeffects/factory/include/media/EffectsFactoryApi.h
+++ b/media/libeffects/factory/include/media/EffectsFactoryApi.h
@@ -119,6 +119,36 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 //
+//    Function:       EffectCreateOnDevice
+//
+//    Description:    Same as EffectCreate but uesed when creating an effect attached to a
+//                 particular audio device instance
+//
+//    Input:
+//          pEffectUuid:    pointer to the effect uuid.
+//          deviceId:  identifies the sink or source device this effect is directed to in
+//              audio HAL. Must be specified if sessionId is AUDIO_SESSION_DEVICE.
+//              deviceId is the audio_port_handle_t used for the device when the audio
+//              patch is created at the audio HAL.//
+//          ioId:   identifies the output or input stream this effect is directed to at audio HAL.
+//              For future use especially with tunneled HW accelerated effects
+//    Input/Output:
+//          pHandle:        address where to return the effect handle.
+//
+//    Output:
+//        returned value:    0          successful operation.
+//                          -ENODEV     factory failed to initialize
+//                          -EINVAL     invalid pEffectUuid or pHandle
+//                          -ENOENT     no effect with this uuid found
+//        *pHandle:         updated with the effect handle.
+//
+////////////////////////////////////////////////////////////////////////////////
+ANDROID_API
+int EffectCreateOnDevice(const effect_uuid_t *pEffectUuid, int32_t deviceId, int32_t ioId,
+        effect_handle_t *pHandle);
+
+////////////////////////////////////////////////////////////////////////////////
+//
 //    Function:       EffectRelease
 //
 //    Description:    Releases the effect engine whose handle is given as argument.
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index e636a50..8626009 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -19,6 +19,8 @@
 #include <utils/Log.h>
 #include <media/MediaResource.h>
 
+#include <vector>
+
 namespace android {
 
 MediaResource::MediaResource()
@@ -36,26 +38,48 @@
           mSubType(subType),
           mValue(value) {}
 
+MediaResource::MediaResource(Type type, const std::vector<uint8_t> &id, uint64_t value)
+        : mType(type),
+          mSubType(kUnspecifiedSubType),
+          mValue(value),
+          mId(id) {}
+
 void MediaResource::readFromParcel(const Parcel &parcel) {
     mType = static_cast<Type>(parcel.readInt32());
     mSubType = static_cast<SubType>(parcel.readInt32());
     mValue = parcel.readUint64();
+    parcel.readByteVector(&mId);
 }
 
 void MediaResource::writeToParcel(Parcel *parcel) const {
     parcel->writeInt32(static_cast<int32_t>(mType));
     parcel->writeInt32(static_cast<int32_t>(mSubType));
     parcel->writeUint64(mValue);
+    parcel->writeByteVector(mId);
+}
+
+static String8 bytesToHexString(const std::vector<uint8_t> &bytes) {
+    String8 str;
+    for (auto &b : bytes) {
+        str.appendFormat("%02x", b);
+    }
+    return str;
 }
 
 String8 MediaResource::toString() const {
     String8 str;
-    str.appendFormat("%s/%s:%llu", asString(mType), asString(mSubType), (unsigned long long)mValue);
+    str.appendFormat("%s/%s:[%s]:%llu",
+        asString(mType), asString(mSubType),
+        bytesToHexString(mId).c_str(),
+        (unsigned long long)mValue);
     return str;
 }
 
 bool MediaResource::operator==(const MediaResource &other) const {
-    return (other.mType == mType) && (other.mSubType == mSubType) && (other.mValue == mValue);
+    return (other.mType == mType)
+      && (other.mSubType == mSubType)
+      && (other.mValue == mValue)
+      && (other.mId == mId);
 }
 
 bool MediaResource::operator!=(const MediaResource &other) const {
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 10a07bb..e9684f0 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -20,6 +20,7 @@
 
 #include <binder/Parcel.h>
 #include <utils/String8.h>
+#include <vector>
 
 namespace android {
 
@@ -32,6 +33,7 @@
         kGraphicMemory,
         kCpuBoost,
         kBattery,
+        kDrmSession,
     };
 
     enum SubType {
@@ -43,6 +45,7 @@
     MediaResource();
     MediaResource(Type type, uint64_t value);
     MediaResource(Type type, SubType subType, uint64_t value);
+    MediaResource(Type type, const std::vector<uint8_t> &id, uint64_t value);
 
     void readFromParcel(const Parcel &parcel);
     void writeToParcel(Parcel *parcel) const;
@@ -55,6 +58,8 @@
     Type mType;
     SubType mSubType;
     uint64_t mValue;
+    // for kDrmSession-type mId is the unique session id obtained via MediaDrm#openSession
+    std::vector<uint8_t> mId;
 };
 
 inline static const char *asString(MediaResource::Type i, const char *def = "??") {
@@ -65,6 +70,7 @@
         case MediaResource::kGraphicMemory:  return "graphic-memory";
         case MediaResource::kCpuBoost:       return "cpu-boost";
         case MediaResource::kBattery:        return "battery";
+        case MediaResource::kDrmSession:     return "drm-session";
         default:                             return def;
     }
 }
diff --git a/media/libmediahelper/TypeConverter.cpp b/media/libmediahelper/TypeConverter.cpp
index 5be78d1..c103236 100644
--- a/media/libmediahelper/TypeConverter.cpp
+++ b/media/libmediahelper/TypeConverter.cpp
@@ -312,6 +312,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DTMF),
     MAKE_STRING_FROM_ENUM(AUDIO_STREAM_TTS),
     MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ACCESSIBILITY),
+    MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ASSISTANT),
     MAKE_STRING_FROM_ENUM(AUDIO_STREAM_REROUTING),
     MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH),
     TERMINATOR
@@ -393,6 +394,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_LOW_LATENCY),
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_DEEP_BUFFER),
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_MEDIA_PROJECTION),
+    MAKE_STRING_FROM_ENUM(AUDIO_FLAG_MUTE_HAPTIC),
     MAKE_STRING_FROM_ENUM(AUDIO_FLAG_NO_SYSTEM_CAPTURE),
     TERMINATOR
 };
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 02c23b1..b7856a6 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -64,6 +64,16 @@
     return item;
 }
 
+MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
+    MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+    return item;
+}
+
+mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
+    mediametrics_handle_t handle = (mediametrics_handle_t) item;
+    return handle;
+}
+
 // access functions for the class
 MediaAnalyticsItem::MediaAnalyticsItem()
     : mPid(-1),
diff --git a/media/libmediametrics/MediaMetrics.cpp b/media/libmediametrics/MediaMetrics.cpp
index 6109190..360ae0c 100644
--- a/media/libmediametrics/MediaMetrics.cpp
+++ b/media/libmediametrics/MediaMetrics.cpp
@@ -169,6 +169,11 @@
     return item->selfrecord();
 }
 
+mediametrics_handle_t mediametrics_dup(mediametrics_handle_t handle) {
+    android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+    if (item == NULL) return android::MediaAnalyticsItem::convert(item);
+    return android::MediaAnalyticsItem::convert(item->dup());
+}
 
 const char *mediametrics_readable(mediametrics_handle_t handle) {
     android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 4a36f6a..42a2f5b 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_MEDIA_MEDIAANALYTICSITEM_H
 #define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
 
+#include "MediaMetrics.h"
+
 #include <string>
 #include <sys/types.h>
 
@@ -94,6 +96,9 @@
         static MediaAnalyticsItem* create(Key key);
         static MediaAnalyticsItem* create();
 
+        static MediaAnalyticsItem* convert(mediametrics_handle_t);
+        static mediametrics_handle_t convert(MediaAnalyticsItem *);
+
         // access functions for the class
         ~MediaAnalyticsItem();
 
diff --git a/media/libmediametrics/include/MediaMetrics.h b/media/libmediametrics/include/MediaMetrics.h
index a4e1ed2..29fb241 100644
--- a/media/libmediametrics/include/MediaMetrics.h
+++ b/media/libmediametrics/include/MediaMetrics.h
@@ -79,6 +79,7 @@
 // # of attributes set within this record.
 int32_t mediametrics_count(mediametrics_handle_t handle);
 
+mediametrics_handle_t mediametrics_dup(mediametrics_handle_t handle);
 bool mediametrics_selfRecord(mediametrics_handle_t handle);
 
 const char *mediametrics_readable(mediametrics_handle_t handle);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 3388097..c1c4b55 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1798,7 +1798,9 @@
 }
 
 void NuPlayer::closeAudioSink() {
-    mRenderer->closeAudioSink();
+    if (mRenderer != NULL) {
+        mRenderer->closeAudioSink();
+    }
 }
 
 void NuPlayer::restartAudio(
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index f8c89e5..8357925 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -6,14 +6,22 @@
 
     shared_libs: [
         "liblog",
+        "libbinder",
+        "libmedia",
         "libmediaplayerservice",
         "libmediadrm",
+        "libresourcemanagerservice",
         "libutils",
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
         "android.hardware.drm@1.2",
     ],
 
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/av/services/mediaresourcemanager",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index d81ee05..58e4bee 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -20,14 +20,29 @@
 
 #include <gtest/gtest.h>
 
+#include <media/IResourceManagerService.h>
+#include <media/IResourceManagerClient.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/ProcessInfoInterface.h>
 #include <mediadrm/DrmHal.h>
 #include <mediadrm/DrmSessionClientInterface.h>
 #include <mediadrm/DrmSessionManager.h>
 
+#include <algorithm>
+#include <vector>
+
+#include "ResourceManagerService.h"
+
 namespace android {
 
+static Vector<uint8_t> toAndroidVector(const std::vector<uint8_t> &vec) {
+    Vector<uint8_t> aVec;
+    for (auto b : vec) {
+        aVec.push_back(b);
+    }
+    return aVec;
+}
+
 struct FakeProcessInfo : public ProcessInfoInterface {
     FakeProcessInfo() {}
     virtual ~FakeProcessInfo() {}
@@ -47,173 +62,128 @@
     DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
 };
 
-struct FakeDrm : public DrmSessionClientInterface {
-    FakeDrm() {}
+struct FakeDrm : public BnResourceManagerClient {
+    FakeDrm(const std::vector<uint8_t>& sessionId, const sp<DrmSessionManager>& manager)
+        : mSessionId(toAndroidVector(sessionId)),
+          mReclaimed(false),
+          mDrmSessionManager(manager) {}
+
     virtual ~FakeDrm() {}
 
-    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
-        mReclaimedSessions.push_back(sessionId);
+    virtual bool reclaimResource() {
+        mReclaimed = true;
+        mDrmSessionManager->removeSession(mSessionId);
         return true;
     }
 
-    const Vector<Vector<uint8_t> >& reclaimedSessions() const {
-        return mReclaimedSessions;
+    virtual String8 getName() {
+        String8 name("FakeDrm[");
+        for (size_t i = 0; i < mSessionId.size(); ++i) {
+            name.appendFormat("%02x", mSessionId[i]);
+        }
+        name.append("]");
+        return name;
     }
 
+    bool isReclaimed() const {
+        return mReclaimed;
+    }
+
+    const Vector<uint8_t> mSessionId;
+
 private:
-    Vector<Vector<uint8_t> > mReclaimedSessions;
+    bool mReclaimed;
+    const sp<DrmSessionManager> mDrmSessionManager;
 
     DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
 };
 
+struct FakeSystemCallback :
+        public ResourceManagerService::SystemCallbackInterface {
+    FakeSystemCallback() {}
+
+    virtual void noteStartVideo(int /*uid*/) override {}
+
+    virtual void noteStopVideo(int /*uid*/) override {}
+
+    virtual void noteResetVideo() override {}
+
+    virtual bool requestCpusetBoost(
+            bool /*enable*/, const sp<IInterface> &/*client*/) override {
+        return true;
+    }
+
+protected:
+    virtual ~FakeSystemCallback() {}
+
+private:
+
+    DISALLOW_EVIL_CONSTRUCTORS(FakeSystemCallback);
+};
+
 static const int kTestPid1 = 30;
 static const int kTestPid2 = 20;
-static const uint8_t kTestSessionId1[] = {1, 2, 3};
-static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
-static const uint8_t kTestSessionId3[] = {9, 0};
+static const std::vector<uint8_t> kTestSessionId1{1, 2, 3};
+static const std::vector<uint8_t> kTestSessionId2{4, 5, 6, 7, 8};
+static const std::vector<uint8_t> kTestSessionId3{9, 0};
 
 class DrmSessionManagerTest : public ::testing::Test {
 public:
     DrmSessionManagerTest()
-        : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
-          mTestDrm1(new FakeDrm()),
-          mTestDrm2(new FakeDrm()) {
-        GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
-        GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
-        GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
+        : mService(new ResourceManagerService(new FakeProcessInfo(), new FakeSystemCallback())),
+          mDrmSessionManager(new DrmSessionManager(mService)),
+          mTestDrm1(new FakeDrm(kTestSessionId1, mDrmSessionManager)),
+          mTestDrm2(new FakeDrm(kTestSessionId2, mDrmSessionManager)),
+          mTestDrm3(new FakeDrm(kTestSessionId3, mDrmSessionManager)) {
+        DrmSessionManager *ptr = new DrmSessionManager(mService);
+        EXPECT_NE(ptr, nullptr);
+        /* mDrmSessionManager = ptr; */
     }
 
 protected:
-    static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
-        for (size_t i = 0; i < num; ++i) {
-            sessionId->push_back(ids[i]);
-        }
-    }
-
-    static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
-            const Vector<uint8_t>& sessionId, int64_t timeStamp) {
-        EXPECT_EQ(drm, info.drm);
-        EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
-        EXPECT_EQ(timeStamp, info.timeStamp);
-    }
-
     void addSession() {
-        mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
-        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
-        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
-        const PidSessionInfosMap& map = sessionMap();
-        EXPECT_EQ(2u, map.size());
-        ssize_t index1 = map.indexOfKey(kTestPid1);
-        ASSERT_GE(index1, 0);
-        const SessionInfos& infos1 = map[index1];
-        EXPECT_EQ(1u, infos1.size());
-        ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
-
-        ssize_t index2 = map.indexOfKey(kTestPid2);
-        ASSERT_GE(index2, 0);
-        const SessionInfos& infos2 = map[index2];
-        EXPECT_EQ(2u, infos2.size());
-        ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
-        ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
+        mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mTestDrm1->mSessionId);
+        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+        mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
     }
 
-    const PidSessionInfosMap& sessionMap() {
-        return mDrmSessionManager->mSessionMap;
-    }
-
-    void testGetLowestPriority() {
-        int pid;
-        int priority;
-        EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
-        addSession();
-        EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
-        EXPECT_EQ(kTestPid1, pid);
-        FakeProcessInfo processInfo;
-        int priority1;
-        processInfo.getPriority(kTestPid1, &priority1);
-        EXPECT_EQ(priority1, priority);
-    }
-
-    void testGetLeastUsedSession() {
-        sp<DrmSessionClientInterface> drm;
-        Vector<uint8_t> sessionId;
-        EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-
-        addSession();
-
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm1, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
-
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm2, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
-
-        // mSessionId2 is no longer the least used session.
-        mDrmSessionManager->useSession(mSessionId2);
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm2, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
-    }
-
+    sp<IResourceManagerService> mService;
     sp<DrmSessionManager> mDrmSessionManager;
     sp<FakeDrm> mTestDrm1;
     sp<FakeDrm> mTestDrm2;
-    Vector<uint8_t> mSessionId1;
-    Vector<uint8_t> mSessionId2;
-    Vector<uint8_t> mSessionId3;
+    sp<FakeDrm> mTestDrm3;
 };
 
 TEST_F(DrmSessionManagerTest, addSession) {
     addSession();
+
+    EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 TEST_F(DrmSessionManagerTest, useSession) {
     addSession();
 
-    mDrmSessionManager->useSession(mSessionId1);
-    mDrmSessionManager->useSession(mSessionId3);
+    mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+    mDrmSessionManager->useSession(mTestDrm3->mSessionId);
 
-    const PidSessionInfosMap& map = sessionMap();
-    const SessionInfos& infos1 = map.valueFor(kTestPid1);
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
-    ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
+    EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 TEST_F(DrmSessionManagerTest, removeSession) {
     addSession();
 
-    mDrmSessionManager->removeSession(mSessionId2);
+    mDrmSessionManager->removeSession(mTestDrm2->mSessionId);
 
-    const PidSessionInfosMap& map = sessionMap();
-    EXPECT_EQ(2u, map.size());
-    const SessionInfos& infos1 = map.valueFor(kTestPid1);
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    EXPECT_EQ(1u, infos1.size());
-    EXPECT_EQ(1u, infos2.size());
-    // mSessionId2 has been removed.
-    ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
-}
-
-TEST_F(DrmSessionManagerTest, removeDrm) {
-    addSession();
-
-    sp<FakeDrm> drm = new FakeDrm;
-    const uint8_t ids[] = {123};
-    Vector<uint8_t> sessionId;
-    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
-    mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
-
-    mDrmSessionManager->removeDrm(mTestDrm2);
-
-    const PidSessionInfosMap& map = sessionMap();
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    EXPECT_EQ(1u, infos2.size());
-    // mTestDrm2 has been removed.
-    ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
+    EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 TEST_F(DrmSessionManagerTest, reclaimSession) {
@@ -224,30 +194,63 @@
     EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
 
     EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
-    EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
-    EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
-
-    mDrmSessionManager->removeSession(mSessionId1);
+    EXPECT_TRUE(mTestDrm1->isReclaimed());
 
     // add a session from a higher priority process.
-    sp<FakeDrm> drm = new FakeDrm;
-    const uint8_t ids[] = {1, 3, 5};
-    Vector<uint8_t> sessionId;
-    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
-    mDrmSessionManager->addSession(15, drm, sessionId);
+    const std::vector<uint8_t> sid{1, 3, 5};
+    sp<FakeDrm> drm = new FakeDrm(sid, mDrmSessionManager);
+    mDrmSessionManager->addSession(15, drm, drm->mSessionId);
 
+    // make sure mTestDrm2 is reclaimed next instead of mTestDrm3
+    mDrmSessionManager->useSession(mTestDrm3->mSessionId);
     EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
-    EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
-    // mSessionId2 is reclaimed.
-    EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
+    EXPECT_TRUE(mTestDrm2->isReclaimed());
+
+    EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(drm->mSessionId));
 }
 
-TEST_F(DrmSessionManagerTest, getLowestPriority) {
-    testGetLowestPriority();
-}
+TEST_F(DrmSessionManagerTest, reclaimAfterUse) {
+    // nothing to reclaim yet
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid2));
 
-TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
-    testGetLeastUsedSession();
+    // add sessions from same pid
+    mDrmSessionManager->addSession(kTestPid2, mTestDrm1, mTestDrm1->mSessionId);
+    mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mTestDrm2->mSessionId);
+    mDrmSessionManager->addSession(kTestPid2, mTestDrm3, mTestDrm3->mSessionId);
+
+    // use some but not all sessions
+    mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+    mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+    mDrmSessionManager->useSession(mTestDrm2->mSessionId);
+
+    // calling pid priority is too low
+    int lowPriorityPid = kTestPid2 + 1;
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(lowPriorityPid));
+
+    // unused session is reclaimed first
+    int highPriorityPid = kTestPid2 - 1;
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+    EXPECT_FALSE(mTestDrm1->isReclaimed());
+    EXPECT_FALSE(mTestDrm2->isReclaimed());
+    EXPECT_TRUE(mTestDrm3->isReclaimed());
+    mDrmSessionManager->removeSession(mTestDrm3->mSessionId);
+
+    // less-used session is reclaimed next
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+    EXPECT_FALSE(mTestDrm1->isReclaimed());
+    EXPECT_TRUE(mTestDrm2->isReclaimed());
+    EXPECT_TRUE(mTestDrm3->isReclaimed());
+
+    // most-used session still open
+    EXPECT_EQ(1u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 } // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 3d6ebc3..77eace9 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -527,7 +527,7 @@
       mFlags(0),
       mStickyError(OK),
       mSoftRenderer(NULL),
-      mAnalyticsItem(NULL),
+      mMetricsHandle(0),
       mIsVideo(false),
       mVideoWidth(0),
       mVideoHeight(0),
@@ -548,19 +548,19 @@
     mResourceManagerClient = new ResourceManagerClient(this);
     mResourceManagerService = new ResourceManagerServiceProxy(pid, mUid);
 
-    initAnalyticsItem();
+    initMediametrics();
 }
 
 MediaCodec::~MediaCodec() {
     CHECK_EQ(mState, UNINITIALIZED);
     mResourceManagerService->removeClient(getId(mResourceManagerClient));
 
-    flushAnalyticsItem();
+    flushMediametrics();
 }
 
-void MediaCodec::initAnalyticsItem() {
-    if (mAnalyticsItem == NULL) {
-        mAnalyticsItem = MediaAnalyticsItem::create(kCodecKeyName);
+void MediaCodec::initMediametrics() {
+    if (mMetricsHandle == 0) {
+        mMetricsHandle = mediametrics_create(kCodecKeyName);
     }
 
     mLatencyHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
@@ -574,38 +574,39 @@
     }
 }
 
-void MediaCodec::updateAnalyticsItem() {
-    ALOGV("MediaCodec::updateAnalyticsItem");
-    if (mAnalyticsItem == NULL) {
+void MediaCodec::updateMediametrics() {
+    ALOGV("MediaCodec::updateMediametrics");
+    if (mMetricsHandle == 0) {
         return;
     }
 
+
     if (mLatencyHist.getCount() != 0 ) {
-        mAnalyticsItem->setInt64(kCodecLatencyMax, mLatencyHist.getMax());
-        mAnalyticsItem->setInt64(kCodecLatencyMin, mLatencyHist.getMin());
-        mAnalyticsItem->setInt64(kCodecLatencyAvg, mLatencyHist.getAvg());
-        mAnalyticsItem->setInt64(kCodecLatencyCount, mLatencyHist.getCount());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyMax, mLatencyHist.getMax());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyMin, mLatencyHist.getMin());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyAvg, mLatencyHist.getAvg());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyCount, mLatencyHist.getCount());
 
         if (kEmitHistogram) {
             // and the histogram itself
             std::string hist = mLatencyHist.emit();
-            mAnalyticsItem->setCString(kCodecLatencyHist, hist.c_str());
+            mediametrics_setCString(mMetricsHandle, kCodecLatencyHist, hist.c_str());
         }
     }
     if (mLatencyUnknown > 0) {
-        mAnalyticsItem->setInt64(kCodecLatencyUnknown, mLatencyUnknown);
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown);
     }
 
 #if 0
     // enable for short term, only while debugging
-    updateEphemeralAnalytics(mAnalyticsItem);
+    updateEphemeralMediametrics(mMetricsHandle);
 #endif
 }
 
-void MediaCodec::updateEphemeralAnalytics(MediaAnalyticsItem *item) {
-    ALOGD("MediaCodec::updateEphemeralAnalytics()");
+void MediaCodec::updateEphemeralMediametrics(mediametrics_handle_t item) {
+    ALOGD("MediaCodec::updateEphemeralMediametrics()");
 
-    if (item == NULL) {
+    if (item == 0) {
         return;
     }
 
@@ -628,28 +629,27 @@
 
     // spit the data (if any) into the supplied analytics record
     if (recentHist.getCount()!= 0 ) {
-        item->setInt64(kCodecRecentLatencyMax, recentHist.getMax());
-        item->setInt64(kCodecRecentLatencyMin, recentHist.getMin());
-        item->setInt64(kCodecRecentLatencyAvg, recentHist.getAvg());
-        item->setInt64(kCodecRecentLatencyCount, recentHist.getCount());
+        mediametrics_setInt64(item, kCodecRecentLatencyMax, recentHist.getMax());
+        mediametrics_setInt64(item, kCodecRecentLatencyMin, recentHist.getMin());
+        mediametrics_setInt64(item, kCodecRecentLatencyAvg, recentHist.getAvg());
+        mediametrics_setInt64(item, kCodecRecentLatencyCount, recentHist.getCount());
 
         if (kEmitHistogram) {
             // and the histogram itself
             std::string hist = recentHist.emit();
-            item->setCString(kCodecRecentLatencyHist, hist.c_str());
+            mediametrics_setCString(item, kCodecRecentLatencyHist, hist.c_str());
         }
     }
 }
 
-void MediaCodec::flushAnalyticsItem() {
-    updateAnalyticsItem();
-    if (mAnalyticsItem != NULL) {
-        // don't log empty records
-        if (mAnalyticsItem->count() > 0) {
-            mAnalyticsItem->selfrecord();
+void MediaCodec::flushMediametrics() {
+    updateMediametrics();
+    if (mMetricsHandle != 0) {
+        if (mediametrics_count(mMetricsHandle) > 0) {
+            mediametrics_selfRecord(mMetricsHandle);
         }
-        delete mAnalyticsItem;
-        mAnalyticsItem = NULL;
+        mediametrics_delete(mMetricsHandle);
+        mMetricsHandle = 0;
     }
 }
 
@@ -981,9 +981,10 @@
     // ".secure"
     msg->setString("name", name);
 
-    if (mAnalyticsItem != NULL) {
-        mAnalyticsItem->setCString(kCodecCodec, name.c_str());
-        mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
+    if (mMetricsHandle != 0) {
+        mediametrics_setCString(mMetricsHandle, kCodecCodec, name.c_str());
+        mediametrics_setCString(mMetricsHandle, kCodecMode,
+                                mIsVideo ? kCodecModeVideo : kCodecModeAudio);
     }
 
     if (mIsVideo) {
@@ -1044,16 +1045,17 @@
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, this);
 
-    if (mAnalyticsItem != NULL) {
+    if (mMetricsHandle != 0) {
         int32_t profile = 0;
         if (format->findInt32("profile", &profile)) {
-            mAnalyticsItem->setInt32(kCodecProfile, profile);
+            mediametrics_setInt32(mMetricsHandle, kCodecProfile, profile);
         }
         int32_t level = 0;
         if (format->findInt32("level", &level)) {
-            mAnalyticsItem->setInt32(kCodecLevel, level);
+            mediametrics_setInt32(mMetricsHandle, kCodecLevel, level);
         }
-        mAnalyticsItem->setInt32(kCodecEncoder, (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
+        mediametrics_setInt32(mMetricsHandle, kCodecEncoder,
+                              (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
     }
 
     if (mIsVideo) {
@@ -1063,17 +1065,17 @@
             mRotationDegrees = 0;
         }
 
-        if (mAnalyticsItem != NULL) {
-            mAnalyticsItem->setInt32(kCodecWidth, mVideoWidth);
-            mAnalyticsItem->setInt32(kCodecHeight, mVideoHeight);
-            mAnalyticsItem->setInt32(kCodecRotation, mRotationDegrees);
+        if (mMetricsHandle != 0) {
+            mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth);
+            mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight);
+            mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees);
             int32_t maxWidth = 0;
             if (format->findInt32("max-width", &maxWidth)) {
-                mAnalyticsItem->setInt32(kCodecMaxWidth, maxWidth);
+                mediametrics_setInt32(mMetricsHandle, kCodecMaxWidth, maxWidth);
             }
             int32_t maxHeight = 0;
             if (format->findInt32("max-height", &maxHeight)) {
-                mAnalyticsItem->setInt32(kCodecMaxHeight, maxHeight);
+                mediametrics_setInt32(mMetricsHandle, kCodecMaxHeight, maxHeight);
             }
         }
 
@@ -1095,8 +1097,8 @@
         } else {
             msg->setPointer("descrambler", descrambler.get());
         }
-        if (mAnalyticsItem != NULL) {
-            mAnalyticsItem->setInt32(kCodecCrypto, 1);
+        if (mMetricsHandle != 0) {
+            mediametrics_setInt32(mMetricsHandle, kCodecCrypto, 1);
         }
     } else if (mFlags & kFlagIsSecure) {
         ALOGW("Crypto or descrambler should be given for secure codec");
@@ -1561,22 +1563,22 @@
     return OK;
 }
 
-status_t MediaCodec::getMetrics(MediaAnalyticsItem * &reply) {
+status_t MediaCodec::getMetrics(mediametrics_handle_t &reply) {
 
-    reply = NULL;
+    reply = 0;
 
     // shouldn't happen, but be safe
-    if (mAnalyticsItem == NULL) {
+    if (mMetricsHandle == 0) {
         return UNKNOWN_ERROR;
     }
 
     // update any in-flight data that's not carried within the record
-    updateAnalyticsItem();
+    updateMediametrics();
 
     // send it back to the caller.
-    reply = mAnalyticsItem->dup();
+    reply = mediametrics_dup(mMetricsHandle);
 
-    updateEphemeralAnalytics(reply);
+    updateEphemeralMediametrics(reply);
 
     return OK;
 }
@@ -1890,10 +1892,11 @@
                         case CONFIGURING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
                             }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : INITIALIZED);
@@ -1903,10 +1906,11 @@
                         case STARTING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
                             }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : CONFIGURED);
@@ -1944,10 +1948,11 @@
                         case FLUSHING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
 
                                 setState(UNINITIALIZED);
                             } else {
@@ -1977,10 +1982,11 @@
                                 setState(INITIALIZED);
                                 break;
                             default:
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
                                 setState(UNINITIALIZED);
                                 break;
                             }
@@ -2037,7 +2043,8 @@
                     CHECK(msg->findString("componentName", &mComponentName));
 
                     if (mComponentName.c_str()) {
-                        mAnalyticsItem->setCString(kCodecCodec, mComponentName.c_str());
+                        mediametrics_setCString(mMetricsHandle, kCodecCodec,
+                                                mComponentName.c_str());
                     }
 
                     const char *owner = mCodecInfo->getOwnerName();
@@ -2053,11 +2060,11 @@
                     if (mComponentName.endsWith(".secure")) {
                         mFlags |= kFlagIsSecure;
                         resourceType = MediaResource::kSecureCodec;
-                        mAnalyticsItem->setInt32(kCodecSecure, 1);
+                        mediametrics_setInt32(mMetricsHandle, kCodecSecure, 1);
                     } else {
                         mFlags &= ~kFlagIsSecure;
                         resourceType = MediaResource::kNonSecureCodec;
-                        mAnalyticsItem->setInt32(kCodecSecure, 0);
+                        mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
                     }
 
                     if (mIsVideo) {
@@ -2105,14 +2112,15 @@
                     (new AMessage)->postReply(mReplyID);
 
                     // augment our media metrics info, now that we know more things
-                    if (mAnalyticsItem != NULL) {
+                    if (mMetricsHandle != 0) {
                         sp<AMessage> format;
                         if (mConfigureMsg != NULL &&
                             mConfigureMsg->findMessage("format", &format)) {
                                 // format includes: mime
                                 AString mime;
                                 if (format->findString("mime", &mime)) {
-                                    mAnalyticsItem->setCString(kCodecMime, mime.c_str());
+                                    mediametrics_setCString(mMetricsHandle, kCodecMime,
+                                                            mime.c_str());
                                 }
                             }
                     }
diff --git a/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h
new file mode 100644
index 0000000..0344ac5
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __AMRNBDEC_TEST_ENVIRONMENT_H__
+#define __AMRNBDEC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrnbDecTestEnvironment : public ::testing::Environment {
+  public:
+    AmrnbDecTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int AmrnbDecTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __AMRNBDEC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
new file mode 100644
index 0000000..af62074
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrnbDecoderTest"
+#define OUTPUT_FILE "/data/local/tmp/amrnbDecode.out"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "gsmamr_dec.h"
+
+#include "AmrnbDecTestEnvironment.h"
+
+// Constants for AMR-NB
+constexpr int32_t kInputBufferSize = 64;
+constexpr int32_t kSamplesPerFrame = L_FRAME;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kSampleRate = 8000;
+constexpr int32_t kChannels = 1;
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const int32_t kFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31, -1, -1, -1, -1, -1, -1, -1, -1};
+
+constexpr int32_t kNumFrameReset = 150;
+
+static AmrnbDecTestEnvironment *gEnv = nullptr;
+
+class AmrnbDecoderTest : public ::testing::TestWithParam<string> {
+  public:
+    AmrnbDecoderTest() : mFpInput(nullptr) {}
+
+    ~AmrnbDecoderTest() {
+        if (mFpInput) {
+            fclose(mFpInput);
+            mFpInput = nullptr;
+        }
+    }
+
+    FILE *mFpInput;
+    SNDFILE *openOutputFile(SF_INFO *sfInfo);
+    int32_t DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, int32_t frameCount = INT32_MAX);
+};
+
+SNDFILE *AmrnbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
+    memset(sfInfo, 0, sizeof(SF_INFO));
+    sfInfo->channels = kChannels;
+    sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+    sfInfo->samplerate = kSampleRate;
+    SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
+    return outFileHandle;
+}
+
+int32_t AmrnbDecoderTest::DecodeFrames(void *amrHandle, SNDFILE *outFileHandle,
+                                       int32_t frameCount) {
+    uint8_t inputBuf[kInputBufferSize];
+    int16_t outputBuf[kOutputBufferSize];
+
+    while (frameCount > 0) {
+        uint8_t mode;
+        int32_t bytesRead = fread(&mode, 1, 1, mFpInput);
+        if (bytesRead != 1) break;
+
+        // Find frame type
+        Frame_Type_3GPP frameType = (Frame_Type_3GPP)((mode >> 3) & 0x0f);
+        int32_t frameSize = kFrameSizes[frameType];
+        if (frameSize < 0) {
+            ALOGE("Illegal frame type");
+            return -1;
+        }
+        bytesRead = fread(inputBuf, 1, frameSize, mFpInput);
+        if (bytesRead != frameSize) break;
+
+        int32_t bytesDecoded = AMRDecode(amrHandle, frameType, inputBuf, outputBuf, MIME_IETF);
+        if (bytesDecoded == -1) {
+            ALOGE("Failed to decode the input file");
+            return -1;
+        }
+
+        sf_writef_short(outFileHandle, outputBuf, kSamplesPerFrame);
+        frameCount--;
+    }
+    return 0;
+}
+
+TEST_F(AmrnbDecoderTest, CreateAmrnbDecoderTest) {
+    void *amrHandle;
+    int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
+    ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
+    GSMDecodeFrameExit(&amrHandle);
+    ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+}
+
+TEST_P(AmrnbDecoderTest, DecodeTest) {
+    string inputFile = gEnv->getRes() + GetParam();
+    mFpInput = fopen(inputFile.c_str(), "rb");
+    ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+    // Open the output file.
+    SF_INFO sfInfo;
+    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+    void *amrHandle;
+    int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
+    ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
+
+    // Decode
+    int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle);
+    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+    sf_close(outFileHandle);
+    GSMDecodeFrameExit(&amrHandle);
+    ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+}
+
+TEST_P(AmrnbDecoderTest, ResetDecodeTest) {
+    string inputFile = gEnv->getRes() + GetParam();
+    mFpInput = fopen(inputFile.c_str(), "rb");
+    ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+    // Open the output file.
+    SF_INFO sfInfo;
+    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+    void *amrHandle;
+    int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
+    ASSERT_EQ(status, 0) << "Error creating AMR-NB decoder";
+
+    // Decode kNumFrameReset first
+    int32_t decoderErr = DecodeFrames(amrHandle, outFileHandle, kNumFrameReset);
+    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+    status = Speech_Decode_Frame_reset(amrHandle);
+    ASSERT_EQ(status, 0) << "Error resting AMR-NB decoder";
+
+    // Start decoding again
+    decoderErr = DecodeFrames(amrHandle, outFileHandle);
+    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+    sf_close(outFileHandle);
+    GSMDecodeFrameExit(&amrHandle);
+    ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+}
+
+INSTANTIATE_TEST_SUITE_P(AmrnbDecoderTestAll, AmrnbDecoderTest,
+                         ::testing::Values(("bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb"),
+                                           ("sine_amrnb_1ch_12kbps_8000hz.amrnb")));
+
+int main(int argc, char **argv) {
+    gEnv = new AmrnbDecTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/codecs/amrnb/dec/test/Android.bp b/media/libstagefright/codecs/amrnb/dec/test/Android.bp
new file mode 100644
index 0000000..7a95cfa
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "AmrnbDecoderTest",
+    gtest: true,
+
+    srcs: [
+        "AmrnbDecoderTest.cpp",
+    ],
+
+    static_libs: [
+        "libstagefright_amrnb_common",
+        "libstagefright_amrnbdec",
+        "libaudioutils",
+        "libsndfile",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/codecs/amrnb/dec/test/README.md b/media/libstagefright/codecs/amrnb/dec/test/README.md
new file mode 100644
index 0000000..62e13ae
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/dec/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### AMR-NB Decoder :
+The Amr-Nb Decoder Test Suite validates the amrnb decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrnbDecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
+Download amr-nb folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push amr-nb/. /data/local/tmp/
+```
+
+usage: AmrnbDecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncTestEnvironment.h b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncTestEnvironment.h
new file mode 100644
index 0000000..5a2fcd1
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __AMRNBENC_TEST_ENVIRONMENT_H__
+#define __AMRNBENC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrnbEncTestEnvironment : public ::testing::Environment {
+  public:
+    AmrnbEncTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int AmrnbEncTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __AMRNBENC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
new file mode 100644
index 0000000..fb72998
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrnbEncoderTest"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "gsmamr_enc.h"
+
+#include "AmrnbEncTestEnvironment.h"
+
+#define OUTPUT_FILE "/data/local/tmp/amrnbEncode.out"
+
+constexpr int32_t kInputBufferSize = L_FRAME * 2;  // 160 samples * 16-bit per sample.
+constexpr int32_t kOutputBufferSize = 1024;
+constexpr int32_t kNumFrameReset = 200;
+constexpr int32_t kMaxCount = 10;
+struct AmrNbEncState {
+    void *encCtx;
+    void *pidSyncCtx;
+};
+
+static AmrnbEncTestEnvironment *gEnv = nullptr;
+
+class AmrnbEncoderTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+  public:
+    AmrnbEncoderTest() : mAmrEncHandle(nullptr) {}
+
+    ~AmrnbEncoderTest() {
+        if (mAmrEncHandle) {
+            free(mAmrEncHandle);
+            mAmrEncHandle = nullptr;
+        }
+    }
+
+    AmrNbEncState *mAmrEncHandle;
+    int32_t EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
+                         int32_t frameCount = INT32_MAX);
+};
+
+int32_t AmrnbEncoderTest::EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
+                                       int32_t frameCount) {
+    int32_t frameNum = 0;
+    uint16_t inputBuf[kInputBufferSize];
+    uint8_t outputBuf[kOutputBufferSize];
+    while (frameNum < frameCount) {
+        int32_t bytesRead = fread(inputBuf, 1, kInputBufferSize, fpInput);
+        if (bytesRead != kInputBufferSize && !feof(fpInput)) {
+            ALOGE("Unable to read data from input file");
+            return -1;
+        } else if (feof(fpInput) && bytesRead == 0) {
+            break;
+        }
+        Frame_Type_3GPP frame_type = (Frame_Type_3GPP)mode;
+        int32_t bytesGenerated =
+                AMREncode(mAmrEncHandle->encCtx, mAmrEncHandle->pidSyncCtx, (Mode)mode,
+                          (Word16 *)inputBuf, outputBuf, &frame_type, AMR_TX_WMF);
+        frameNum++;
+        if (bytesGenerated < 0) {
+            ALOGE("Error in encoging the file: Invalid output format");
+            return -1;
+        }
+
+        // Convert from WMF to RFC 3267 format.
+        if (bytesGenerated > 0) {
+            outputBuf[0] = ((outputBuf[0] << 3) | 4) & 0x7c;
+        }
+        fwrite(outputBuf, 1, bytesGenerated, mFpOutput);
+    }
+    return 0;
+}
+
+TEST_F(AmrnbEncoderTest, CreateAmrnbEncoderTest) {
+    mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
+    ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
+    for (int count = 0; count < kMaxCount; count++) {
+        int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
+        ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
+        ALOGV("Successfully created encoder");
+    }
+    if (mAmrEncHandle) {
+        AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
+        ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
+        ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
+        free(mAmrEncHandle);
+        mAmrEncHandle = nullptr;
+        ALOGV("Successfully deleted encoder");
+    }
+}
+
+TEST_P(AmrnbEncoderTest, EncodeTest) {
+    mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
+    ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
+    int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
+    ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
+
+    string inputFile = gEnv->getRes() + GetParam().first;
+    FILE *fpInput = fopen(inputFile.c_str(), "rb");
+    ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
+
+    FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
+    ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
+
+    // Write file header.
+    fwrite("#!AMR\n", 1, 6, fpOutput);
+
+    int32_t mode = GetParam().second;
+    int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput);
+    ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
+
+    fclose(fpOutput);
+    fclose(fpInput);
+
+    AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
+    ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
+    ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
+    free(mAmrEncHandle);
+    mAmrEncHandle = nullptr;
+    ALOGV("Successfully deleted encoder");
+}
+
+TEST_P(AmrnbEncoderTest, ResetEncoderTest) {
+    mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
+    ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
+    int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
+    ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
+
+    string inputFile = gEnv->getRes() + GetParam().first;
+    FILE *fpInput = fopen(inputFile.c_str(), "rb");
+    ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
+
+    FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
+    ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
+
+    // Write file header.
+    fwrite("#!AMR\n", 1, 6, fpOutput);
+
+    int32_t mode = GetParam().second;
+    // Encode kNumFrameReset first
+    int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput, kNumFrameReset);
+    ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
+
+    status = AMREncodeReset(mAmrEncHandle->encCtx, mAmrEncHandle->pidSyncCtx);
+    ASSERT_EQ(status, 0) << "Error resting AMR-NB encoder";
+
+    // Start encoding again
+    encodeErr = EncodeFrames(mode, fpInput, fpOutput);
+    ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
+
+    fclose(fpOutput);
+    fclose(fpInput);
+
+    AMREncodeExit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx);
+    ASSERT_EQ(mAmrEncHandle->encCtx, nullptr) << "Error deleting AMR-NB encoder";
+    ASSERT_EQ(mAmrEncHandle->pidSyncCtx, nullptr) << "Error deleting AMR-NB encoder";
+    free(mAmrEncHandle);
+    mAmrEncHandle = nullptr;
+    ALOGV("Successfully deleted encoder");
+}
+
+// TODO: Add more test vectors
+INSTANTIATE_TEST_SUITE_P(AmrnbEncoderTestAll, AmrnbEncoderTest,
+                         ::testing::Values(make_pair("bbb_raw_1ch_8khz_s16le.raw", MR475),
+                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR515),
+                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR59),
+                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR67),
+                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR74),
+                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR795),
+                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR102),
+                                           make_pair("bbb_raw_1ch_8khz_s16le.raw", MR122),
+                                           make_pair("sinesweepraw.raw", MR475),
+                                           make_pair("sinesweepraw.raw", MR515),
+                                           make_pair("sinesweepraw.raw", MR59),
+                                           make_pair("sinesweepraw.raw", MR67),
+                                           make_pair("sinesweepraw.raw", MR74),
+                                           make_pair("sinesweepraw.raw", MR795),
+                                           make_pair("sinesweepraw.raw", MR102),
+                                           make_pair("sinesweepraw.raw", MR122)));
+
+int main(int argc, char **argv) {
+    gEnv = new AmrnbEncTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/test/Android.bp b/media/libstagefright/codecs/amrnb/enc/test/Android.bp
new file mode 100644
index 0000000..e8982fe
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "AmrnbEncoderTest",
+    gtest: true,
+
+    srcs: [
+        "AmrnbEncoderTest.cpp",
+    ],
+
+    static_libs: [
+        "libstagefright_amrnb_common",
+        "libstagefright_amrnbenc",
+        "libaudioutils",
+        "libsndfile",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/test/README.md b/media/libstagefright/codecs/amrnb/enc/test/README.md
new file mode 100644
index 0000000..4ddaa57
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### AMR-NB Encoder :
+The Amr-Nb Encoder Test Suite validates the amrnb encoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrnbEncoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrnbEncoderTest/AmrnbEncoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrnbEncoderTest/AmrnbEncoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
+Download amr-nb_encoder folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push amr-nb_encoder/. /data/local/tmp/
+```
+
+usage: AmrnbEncoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/codecs/amrwb/test/AmrwbDecTestEnvironment.h b/media/libstagefright/codecs/amrwb/test/AmrwbDecTestEnvironment.h
new file mode 100644
index 0000000..84d337d
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/AmrwbDecTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __AMRWBDEC_TEST_ENVIRONMENT_H__
+#define __AMRWBDEC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrwbDecTestEnvironment : public ::testing::Environment {
+  public:
+    AmrwbDecTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int AmrwbDecTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __AMRWBDEC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.cpp b/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.cpp
new file mode 100644
index 0000000..2aad81b
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrwbDecoderTest"
+#define OUTPUT_FILE "/data/local/tmp/amrwbDecode.out"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "pvamrwbdecoder.h"
+#include "pvamrwbdecoder_api.h"
+
+#include "AmrwbDecTestEnvironment.h"
+
+// Constants for AMR-WB.
+constexpr int32_t kInputBufferSize = 64;
+constexpr int32_t kSamplesPerFrame = 320;
+constexpr int32_t kBitsPerSample = 16;
+constexpr int32_t kSampleRate = 16000;
+constexpr int32_t kChannels = 1;
+constexpr int32_t kMaxSourceDataUnitSize = KAMRWB_NB_BITS_MAX * sizeof(int16_t);
+constexpr int32_t kOutputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+const int32_t kFrameSizes[16] = {17, 23, 32, 36, 40, 46, 50, 58, 60, -1, -1, -1, -1, -1, -1, -1};
+constexpr int32_t kNumFrameReset = 150;
+
+constexpr int32_t kMaxCount = 10;
+
+static AmrwbDecTestEnvironment *gEnv = nullptr;
+
+class AmrwbDecoderTest : public ::testing::TestWithParam<string> {
+  public:
+    AmrwbDecoderTest() : mFpInput(nullptr) {}
+
+    ~AmrwbDecoderTest() {
+        if (mFpInput) {
+            fclose(mFpInput);
+            mFpInput = nullptr;
+        }
+    }
+
+    FILE *mFpInput;
+    int32_t DecodeFrames(int16_t *decoderCookie, void *decoderBuf, SNDFILE *outFileHandle,
+                         int32_t frameCount = INT32_MAX);
+    SNDFILE *openOutputFile(SF_INFO *sfInfo);
+};
+
+SNDFILE *AmrwbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
+    memset(sfInfo, 0, sizeof(SF_INFO));
+    sfInfo->channels = kChannels;
+    sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+    sfInfo->samplerate = kSampleRate;
+    SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
+    return outFileHandle;
+}
+
+int32_t AmrwbDecoderTest::DecodeFrames(int16_t *decoderCookie, void *decoderBuf,
+                                       SNDFILE *outFileHandle, int32_t frameCount) {
+    uint8_t inputBuf[kInputBufferSize];
+    int16_t inputSampleBuf[kMaxSourceDataUnitSize];
+    int16_t outputBuf[kOutputBufferSize];
+
+    while (frameCount > 0) {
+        uint8_t modeByte;
+        int32_t bytesRead = fread(&modeByte, 1, 1, mFpInput);
+        if (bytesRead != 1) break;
+
+        int16 mode = ((modeByte >> 3) & 0x0f);
+        if (mode >= 9) {
+            // Produce silence for comfort noise, speech lost and no data.
+            int32_t outputBufferSize = kSamplesPerFrame * kBitsPerSample / 8;
+            memset(outputBuf, 0, outputBufferSize);
+        } else {
+            // Read rest of the frame.
+            int32_t frameSize = kFrameSizes[mode];
+            // AMR-WB file format cannot have mode 10, 11, 12 and 13.
+            if (frameSize < 0) {
+                ALOGE("Illegal frame mode");
+                return -1;
+            }
+            bytesRead = fread(inputBuf, 1, frameSize, mFpInput);
+            if (bytesRead != frameSize) break;
+
+            int16 frameMode = mode;
+            int16 frameType;
+            RX_State_wb rx_state;
+            mime_unsorting(inputBuf, inputSampleBuf, &frameType, &frameMode, 1, &rx_state);
+
+            int16_t numSamplesOutput;
+            pvDecoder_AmrWb(frameMode, inputSampleBuf, outputBuf, &numSamplesOutput, decoderBuf,
+                            frameType, decoderCookie);
+            if (numSamplesOutput != kSamplesPerFrame) {
+                ALOGE("Failed to decode the input file");
+                return -1;
+            }
+            for (int count = 0; count < kSamplesPerFrame; ++count) {
+                /* Delete the 2 LSBs (14-bit output) */
+                outputBuf[count] &= 0xfffc;
+            }
+        }
+        sf_writef_short(outFileHandle, outputBuf, kSamplesPerFrame / kChannels);
+        frameCount--;
+    }
+    return 0;
+}
+
+TEST_F(AmrwbDecoderTest, MultiCreateAmrwbDecoderTest) {
+    uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+    void *decoderBuf = malloc(memRequirements);
+    ASSERT_NE(decoderBuf, nullptr)
+            << "Failed to allocate decoder memory of size " << memRequirements;
+
+    // Create AMR-WB decoder instance.
+    void *amrHandle = nullptr;
+    int16_t *decoderCookie;
+    for (int count = 0; count < kMaxCount; count++) {
+        pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+        ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
+        ALOGV("Decoder created successfully");
+    }
+    if (decoderBuf) {
+        free(decoderBuf);
+        decoderBuf = nullptr;
+    }
+}
+
+TEST_P(AmrwbDecoderTest, DecodeTest) {
+    uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+    void *decoderBuf = malloc(memRequirements);
+    ASSERT_NE(decoderBuf, nullptr)
+            << "Failed to allocate decoder memory of size " << memRequirements;
+
+    void *amrHandle = nullptr;
+    int16_t *decoderCookie;
+    pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+    ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
+
+    string inputFile = gEnv->getRes() + GetParam();
+    mFpInput = fopen(inputFile.c_str(), "rb");
+    ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+    // Open the output file.
+    SF_INFO sfInfo;
+    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+    int32_t decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle);
+    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+    sf_close(outFileHandle);
+    if (decoderBuf) {
+        free(decoderBuf);
+        decoderBuf = nullptr;
+    }
+}
+
+TEST_P(AmrwbDecoderTest, ResetDecoderTest) {
+    uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
+    void *decoderBuf = malloc(memRequirements);
+    ASSERT_NE(decoderBuf, nullptr)
+            << "Failed to allocate decoder memory of size " << memRequirements;
+
+    void *amrHandle = nullptr;
+    int16_t *decoderCookie;
+    pvDecoder_AmrWb_Init(&amrHandle, decoderBuf, &decoderCookie);
+    ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
+
+    string inputFile = gEnv->getRes() + GetParam();
+    mFpInput = fopen(inputFile.c_str(), "rb");
+    ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
+
+    // Open the output file.
+    SF_INFO sfInfo;
+    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+    // Decode 150 frames first
+    int32_t decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle, kNumFrameReset);
+    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+    // Reset Decoder
+    pvDecoder_AmrWb_Reset(decoderBuf, 1);
+
+    // Start decoding again
+    decoderErr = DecodeFrames(decoderCookie, decoderBuf, outFileHandle);
+    ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
+
+    sf_close(outFileHandle);
+    if (decoderBuf) {
+        free(decoderBuf);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(AmrwbDecoderTestAll, AmrwbDecoderTest,
+                         ::testing::Values(("bbb_amrwb_1ch_14kbps_16000hz.amrwb"),
+                                           ("bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb")));
+
+int main(int argc, char **argv) {
+    gEnv = new AmrwbDecTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/codecs/amrwb/test/Android.bp b/media/libstagefright/codecs/amrwb/test/Android.bp
new file mode 100644
index 0000000..968215a
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/Android.bp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "AmrwbDecoderTest",
+    gtest: true,
+
+    srcs: [
+        "AmrwbDecoderTest.cpp",
+    ],
+
+    static_libs: [
+        "libstagefright_amrwbdec",
+        "libsndfile",
+        "libaudioutils",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/codecs/amrwb/test/README.md b/media/libstagefright/codecs/amrwb/test/README.md
new file mode 100644
index 0000000..502a20d
--- /dev/null
+++ b/media/libstagefright/codecs/amrwb/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### AMR-WB Decoder :
+The Amr-Wb Decoder Test Suite validates the amrwb decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrwbDecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
+Download amr-wb folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push amr-wb/. /data/local/tmp/
+```
+
+usage: AmrwbDecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/codecs/amrwbenc/test/AmrwbEncTestEnvironment.h b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncTestEnvironment.h
new file mode 100644
index 0000000..08ada66
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __AMRWBENC_TEST_ENVIRONMENT_H__
+#define __AMRWBENC_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AmrwbEncTestEnvironment : public ::testing::Environment {
+  public:
+    AmrwbEncTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int AmrwbEncTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __AMRWBENC_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.cpp b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.cpp
new file mode 100644
index 0000000..1a6ee27
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AmrwbEncoderTest"
+
+#include <utils/Log.h>
+
+#include <stdio.h>
+
+#include "cmnMemory.h"
+#include "voAMRWB.h"
+
+#include "AmrwbEncTestEnvironment.h"
+
+#define OUTPUT_FILE "/data/local/tmp/amrwbEncode.out"
+#define VOAMRWB_RFC3267_HEADER_INFO "#!AMR-WB\n"
+
+constexpr int32_t kInputBufferSize = 640;
+constexpr int32_t kOutputBufferSize = 1024;
+
+static AmrwbEncTestEnvironment *gEnv = nullptr;
+
+class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, VOAMRWBFRAMETYPE>> {
+  public:
+    AmrwbEncoderTest() : mEncoderHandle(nullptr) {
+        tuple<string, int32_t, VOAMRWBFRAMETYPE> params = GetParam();
+        mInputFile = gEnv->getRes() + get<0>(params);
+        mMode = get<1>(params);
+        mFrameType = get<2>(params);
+        mMemOperator.Alloc = cmnMemAlloc;
+        mMemOperator.Copy = cmnMemCopy;
+        mMemOperator.Free = cmnMemFree;
+        mMemOperator.Set = cmnMemSet;
+        mMemOperator.Check = cmnMemCheck;
+
+        mUserData.memflag = VO_IMF_USERMEMOPERATOR;
+        mUserData.memData = (VO_PTR)(&mMemOperator);
+    }
+
+    ~AmrwbEncoderTest() {
+        if (mEncoderHandle) {
+            mEncoderHandle = nullptr;
+        }
+    }
+
+    string mInputFile;
+    unsigned char mOutputBuf[kOutputBufferSize];
+    unsigned char mInputBuf[kInputBufferSize];
+    VOAMRWBFRAMETYPE mFrameType;
+    VO_AUDIO_CODECAPI mApiHandle;
+    VO_MEM_OPERATOR mMemOperator;
+    VO_CODEC_INIT_USERDATA mUserData;
+    VO_HANDLE mEncoderHandle;
+    int32_t mMode;
+};
+
+TEST_P(AmrwbEncoderTest, CreateAmrwbEncoderTest) {
+    int32_t status = voGetAMRWBEncAPI(&mApiHandle);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to get api handle";
+
+    status = mApiHandle.Init(&mEncoderHandle, VO_AUDIO_CodingAMRWB, &mUserData);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to init AMRWB encoder";
+
+    status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &mFrameType);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder frame type to " << mFrameType;
+
+    status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_MODE, &mMode);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder mode to %d" << mMode;
+    ALOGV("AMR-WB encoder created successfully");
+
+    status = mApiHandle.Uninit(mEncoderHandle);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to delete AMRWB encoder";
+    ALOGV("AMR-WB encoder deleted successfully");
+}
+
+TEST_P(AmrwbEncoderTest, AmrwbEncodeTest) {
+    VO_CODECBUFFER inData;
+    VO_CODECBUFFER outData;
+    VO_AUDIO_OUTPUTINFO outFormat;
+
+    FILE *fpInput = fopen(mInputFile.c_str(), "rb");
+    ASSERT_NE(fpInput, nullptr) << "Error opening input file " << mInputFile;
+
+    FILE *fpOutput = fopen(OUTPUT_FILE, "wb");
+    ASSERT_NE(fpOutput, nullptr) << "Error opening output file " << OUTPUT_FILE;
+
+    uint32_t status = voGetAMRWBEncAPI(&mApiHandle);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to get api handle";
+
+    status = mApiHandle.Init(&mEncoderHandle, VO_AUDIO_CodingAMRWB, &mUserData);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to init AMRWB encoder";
+
+    status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &mFrameType);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder frame type to " << mFrameType;
+
+    status = mApiHandle.SetParam(mEncoderHandle, VO_PID_AMRWB_MODE, &mMode);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to set AMRWB encoder mode to " << mMode;
+
+    if (mFrameType == VOAMRWB_RFC3267) {
+        /* write RFC3267 Header info to indicate single channel AMR file storage format */
+        int32_t size = strlen(VOAMRWB_RFC3267_HEADER_INFO);
+        memcpy(mOutputBuf, VOAMRWB_RFC3267_HEADER_INFO, size);
+        fwrite(mOutputBuf, 1, size, fpOutput);
+    }
+
+    int32_t frameNum = 0;
+    while (1) {
+        int32_t buffLength =
+                (int32_t)fread(mInputBuf, sizeof(signed char), kInputBufferSize, fpInput);
+
+        if (buffLength == 0 || feof(fpInput)) break;
+        ASSERT_EQ(buffLength, kInputBufferSize) << "Error in reading input file";
+
+        inData.Buffer = (unsigned char *)mInputBuf;
+        inData.Length = buffLength;
+        outData.Buffer = mOutputBuf;
+        status = mApiHandle.SetInputData(mEncoderHandle, &inData);
+        ASSERT_EQ(status, VO_ERR_NONE) << "Failed to setup Input data";
+
+        do {
+            status = mApiHandle.GetOutputData(mEncoderHandle, &outData, &outFormat);
+            ASSERT_NE(status, VO_ERR_LICENSE_ERROR) << "Failed to encode the file";
+            if (status == 0) {
+                frameNum++;
+                fwrite(outData.Buffer, 1, outData.Length, fpOutput);
+                fflush(fpOutput);
+            }
+        } while (status != VO_ERR_INPUT_BUFFER_SMALL);
+    }
+
+    ALOGV("Number of frames processed: %d", frameNum);
+    status = mApiHandle.Uninit(mEncoderHandle);
+    ASSERT_EQ(status, VO_ERR_NONE) << "Failed to delete AMRWB encoder";
+
+    if (fpInput) {
+        fclose(fpInput);
+    }
+    if (fpOutput) {
+        fclose(fpOutput);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        AmrwbEncoderTestAll, AmrwbEncoderTest,
+        ::testing::Values(
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267),
+                make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267)));
+
+int main(int argc, char **argv) {
+    gEnv = new AmrwbEncTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/codecs/amrwbenc/test/Android.bp b/media/libstagefright/codecs/amrwbenc/test/Android.bp
new file mode 100644
index 0000000..7042bc5
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "AmrwbEncoderTest",
+    gtest: true,
+
+    srcs: [
+        "AmrwbEncoderTest.cpp",
+    ],
+
+    static_libs: [
+        "libstagefright_enc_common",
+        "libstagefright_amrwbenc",
+        "libaudioutils",
+        "libsndfile",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/codecs/amrwbenc/test/README.md b/media/libstagefright/codecs/amrwbenc/test/README.md
new file mode 100644
index 0000000..ea2135f
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### AMR-WB Encoder :
+The Amr-Wb Encoder Test Suite validates the amrwb encoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m AmrwbEncoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
+Download amr-wb_encoder folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push amr-wb_encoder/. /data/local/tmp/
+```
+
+usage: AmrwbEncoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/test/Android.bp
new file mode 100644
index 0000000..e335c9b
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Android.bp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+cc_test {
+    name: "Mpeg4H263DecoderTest",
+    gtest: true,
+
+    srcs: [
+        "Mpeg4H263DecoderTest.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright_m4vh263dec",
+        "libstagefright_foundation",
+    ],
+
+    cflags: [
+        "-DOSCL_IMPORT_REF=",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
new file mode 100644
index 0000000..967c1ea
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
@@ -0,0 +1,423 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Mpeg4H263DecoderTest"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <utils/String8.h>
+#include <fstream>
+
+#include <media/stagefright/foundation/AUtils.h>
+#include "mp4dec_api.h"
+
+#include "Mpeg4H263DecoderTestEnvironment.h"
+
+using namespace android;
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/Output.yuv"
+#define CODEC_CONFIG_FLAG 32
+#define SYNC_FRAME 1
+#define MPEG4_MAX_WIDTH 1920
+#define MPEG4_MAX_HEIGHT 1080
+#define H263_MAX_WIDTH 352
+#define H263_MAX_HEIGHT 288
+
+constexpr uint32_t kNumOutputBuffers = 2;
+
+struct FrameInfo {
+    int32_t bytesCount;
+    uint32_t flags;
+    int64_t timestamp;
+};
+
+struct tagvideoDecControls;
+
+static Mpeg4H263DecoderTestEnvironment *gEnv = nullptr;
+
+class Mpeg4H263DecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {
+  public:
+    Mpeg4H263DecoderTest()
+        : mDecHandle(nullptr),
+          mInputBuffer(nullptr),
+          mInitialized(false),
+          mFramesConfigured(false),
+          mNumSamplesOutput(0),
+          mWidth(352),
+          mHeight(288) {
+        memset(mOutputBuffer, 0x0, sizeof(mOutputBuffer));
+    }
+
+    ~Mpeg4H263DecoderTest() {
+        if (mEleStream.is_open()) mEleStream.close();
+        if (mDecHandle) {
+            delete mDecHandle;
+            mDecHandle = nullptr;
+        }
+        if (mInputBuffer) {
+            free(mInputBuffer);
+            mInputBuffer = nullptr;
+        }
+        freeOutputBuffer();
+    }
+
+    status_t initDecoder();
+    void allocOutputBuffer(size_t outputBufferSize);
+    void dumpOutput(ofstream &ostrm);
+    void freeOutputBuffer();
+    void processMpeg4H263Decoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
+                                 ifstream &mEleStream, ofstream &ostrm, MP4DecodingMode inputMode);
+    void deInitDecoder();
+
+    ifstream mEleStream;
+    tagvideoDecControls *mDecHandle;
+    char *mInputBuffer;
+    uint8_t *mOutputBuffer[kNumOutputBuffers];
+    bool mInitialized;
+    bool mFramesConfigured;
+    uint32_t mNumSamplesOutput;
+    uint32_t mWidth;
+    uint32_t mHeight;
+};
+
+status_t Mpeg4H263DecoderTest::initDecoder() {
+    if (!mDecHandle) {
+        mDecHandle = new tagvideoDecControls;
+    }
+    if (!mDecHandle) {
+        return NO_MEMORY;
+    }
+    memset(mDecHandle, 0, sizeof(tagvideoDecControls));
+
+    return OK;
+}
+
+void Mpeg4H263DecoderTest::allocOutputBuffer(size_t outputBufferSize) {
+    for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
+        if (!mOutputBuffer[i]) {
+            mOutputBuffer[i] = (uint8_t *)malloc(outputBufferSize);
+            ASSERT_NE(mOutputBuffer[i], nullptr) << "Output buffer allocation failed";
+        }
+    }
+}
+
+void Mpeg4H263DecoderTest::dumpOutput(ofstream &ostrm) {
+    uint8_t *src = mOutputBuffer[mNumSamplesOutput & 1];
+    size_t vStride = align(mHeight, 16);
+    size_t srcYStride = align(mWidth, 16);
+    size_t srcUVStride = srcYStride / 2;
+    uint8_t *srcStart = src;
+
+    /* Y buffer */
+    for (size_t i = 0; i < mHeight; ++i) {
+        ostrm.write(reinterpret_cast<char *>(src), mWidth);
+        src += srcYStride;
+    }
+    /* U buffer */
+    src = srcStart + vStride * srcYStride;
+    for (size_t i = 0; i < mHeight / 2; ++i) {
+        ostrm.write(reinterpret_cast<char *>(src), mWidth / 2);
+        src += srcUVStride;
+    }
+    /* V buffer */
+    src = srcStart + vStride * srcYStride * 5 / 4;
+    for (size_t i = 0; i < mHeight / 2; ++i) {
+        ostrm.write(reinterpret_cast<char *>(src), mWidth / 2);
+        src += srcUVStride;
+    }
+}
+
+void Mpeg4H263DecoderTest::freeOutputBuffer() {
+    for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
+        if (mOutputBuffer[i]) {
+            free(mOutputBuffer[i]);
+            mOutputBuffer[i] = nullptr;
+        }
+    }
+}
+
+void Mpeg4H263DecoderTest::processMpeg4H263Decoder(vector<FrameInfo> Info, int32_t offset,
+                                                   int32_t range, ifstream &mEleStream,
+                                                   ofstream &ostrm, MP4DecodingMode inputMode) {
+    size_t maxWidth = (inputMode == MPEG4_MODE) ? MPEG4_MAX_WIDTH : H263_MAX_WIDTH;
+    size_t maxHeight = (inputMode == MPEG4_MODE) ? MPEG4_MAX_HEIGHT : H263_MAX_HEIGHT;
+    size_t outputBufferSize = align(maxWidth, 16) * align(maxHeight, 16) * 3 / 2;
+    uint32_t frameIndex = offset;
+    bool status = true;
+    ASSERT_GE(range, 0) << "Invalid range";
+    ASSERT_TRUE(offset >= 0 && offset <= Info.size() - 1) << "Invalid offset";
+    ASSERT_LE(range + offset, Info.size()) << "range+offset can't be greater than the no of frames";
+
+    while (1) {
+        if (frameIndex == Info.size() || frameIndex == (offset + range)) break;
+
+        int32_t bytesCount = Info[frameIndex].bytesCount;
+        ASSERT_GT(bytesCount, 0) << "Size for the memory allocation is negative";
+        mInputBuffer = (char *)malloc(bytesCount);
+        ASSERT_NE(mInputBuffer, nullptr) << "Insufficient memory to read frame";
+        mEleStream.read(mInputBuffer, bytesCount);
+        ASSERT_EQ(mEleStream.gcount(), bytesCount) << "mEleStream.gcount() != bytesCount";
+        static const uint8_t volInfo[] = {0x00, 0x00, 0x01, 0xB0};
+        bool volHeader = memcmp(mInputBuffer, volInfo, 4) == 0;
+        if (volHeader) {
+            PVCleanUpVideoDecoder(mDecHandle);
+            mInitialized = false;
+        }
+
+        if (!mInitialized) {
+            uint8_t *volData[1]{};
+            int32_t volSize = 0;
+
+            uint32_t flags = Info[frameIndex].flags;
+            bool codecConfig = flags == CODEC_CONFIG_FLAG;
+            if (codecConfig || volHeader) {
+                volData[0] = reinterpret_cast<uint8_t *>(mInputBuffer);
+                volSize = bytesCount;
+            }
+
+            status = PVInitVideoDecoder(mDecHandle, volData, &volSize, 1, maxWidth, maxHeight,
+                                        inputMode);
+            ASSERT_TRUE(status) << "PVInitVideoDecoder failed. Unsupported content";
+
+            mInitialized = true;
+            MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
+            ASSERT_EQ(inputMode, actualMode)
+                    << "Decoded mode not same as actual mode of the decoder";
+
+            PVSetPostProcType(mDecHandle, 0);
+
+            int32_t dispWidth, dispHeight;
+            PVGetVideoDimensions(mDecHandle, &dispWidth, &dispHeight);
+
+            int32_t bufWidth, bufHeight;
+            PVGetBufferDimensions(mDecHandle, &bufWidth, &bufHeight);
+
+            ASSERT_LE(dispWidth, bufWidth) << "Display width is greater than buffer width";
+            ASSERT_LE(dispHeight, bufHeight) << "Display height is greater than buffer height";
+
+            if (dispWidth != mWidth || dispHeight != mHeight) {
+                mWidth = dispWidth;
+                mHeight = dispHeight;
+                freeOutputBuffer();
+                if (inputMode == H263_MODE) {
+                    PVCleanUpVideoDecoder(mDecHandle);
+
+                    uint8_t *volData[1]{};
+                    int32_t volSize = 0;
+
+                    status = PVInitVideoDecoder(mDecHandle, volData, &volSize, 1, maxWidth,
+                                                maxHeight, H263_MODE);
+                    ASSERT_TRUE(status) << "PVInitVideoDecoder failed for H263";
+                }
+                mFramesConfigured = false;
+            }
+
+            if (codecConfig) {
+                frameIndex++;
+                continue;
+            }
+        }
+
+        uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
+        ASSERT_GE(outputBufferSize, yFrameSize * 3 / 2)
+                << "Too small output buffer: " << outputBufferSize << " bytes";
+        ASSERT_NO_FATAL_FAILURE(allocOutputBuffer(outputBufferSize));
+
+        if (!mFramesConfigured) {
+            PVSetReferenceYUV(mDecHandle, mOutputBuffer[1]);
+            mFramesConfigured = true;
+        }
+
+        // Need to check if header contains new info, e.g., width/height, etc.
+        VopHeaderInfo headerInfo;
+        uint32_t useExtTimestamp = 1;
+        int32_t inputSize = (Info)[frameIndex].bytesCount;
+        uint32_t timestamp = frameIndex;
+
+        uint8_t *bitstreamTmp = reinterpret_cast<uint8_t *>(mInputBuffer);
+
+        status = PVDecodeVopHeader(mDecHandle, &bitstreamTmp, &timestamp, &inputSize, &headerInfo,
+                                   &useExtTimestamp, mOutputBuffer[mNumSamplesOutput & 1]);
+        ASSERT_EQ(status, PV_TRUE) << "failed to decode vop header";
+
+        // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
+        // decoder may detect size change after PVDecodeVopHeader.
+        int32_t dispWidth, dispHeight;
+        PVGetVideoDimensions(mDecHandle, &dispWidth, &dispHeight);
+
+        int32_t bufWidth, bufHeight;
+        PVGetBufferDimensions(mDecHandle, &bufWidth, &bufHeight);
+
+        ASSERT_LE(dispWidth, bufWidth) << "Display width is greater than buffer width";
+        ASSERT_LE(dispHeight, bufHeight) << "Display height is greater than buffer height";
+        if (dispWidth != mWidth || dispHeight != mHeight) {
+            mWidth = dispWidth;
+            mHeight = dispHeight;
+        }
+
+        status = PVDecodeVopBody(mDecHandle, &inputSize);
+        ASSERT_EQ(status, PV_TRUE) << "failed to decode video frame No = %d" << frameIndex;
+
+        dumpOutput(ostrm);
+
+        ++mNumSamplesOutput;
+        ++frameIndex;
+    }
+    freeOutputBuffer();
+}
+
+void Mpeg4H263DecoderTest::deInitDecoder() {
+    if (mInitialized) {
+        if (mDecHandle) {
+            PVCleanUpVideoDecoder(mDecHandle);
+            delete mDecHandle;
+            mDecHandle = nullptr;
+        }
+        mInitialized = false;
+    }
+    freeOutputBuffer();
+}
+
+void getInfo(string infoFileName, vector<FrameInfo> &Info) {
+    ifstream eleInfo;
+    eleInfo.open(infoFileName);
+    ASSERT_EQ(eleInfo.is_open(), true) << "Failed to open " << infoFileName;
+    int32_t bytesCount = 0;
+    uint32_t flags = 0;
+    uint32_t timestamp = 0;
+    while (1) {
+        if (!(eleInfo >> bytesCount)) {
+            break;
+        }
+        eleInfo >> flags;
+        eleInfo >> timestamp;
+        Info.push_back({bytesCount, flags, timestamp});
+    }
+    if (eleInfo.is_open()) eleInfo.close();
+}
+
+TEST_P(Mpeg4H263DecoderTest, DecodeTest) {
+    tuple<string /* InputFileName */, string /* InfoFileName */, bool /* mode */> params =
+            GetParam();
+
+    string inputFileName = gEnv->getRes() + get<0>(params);
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << get<0>(params);
+
+    string infoFileName = gEnv->getRes() + get<1>(params);
+    vector<FrameInfo> Info;
+    ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
+    ASSERT_NE(Info.empty(), true) << "Invalid Info file";
+
+    ofstream ostrm;
+    ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+    ASSERT_EQ(ostrm.is_open(), true) << "Failed to open output stream for " << get<0>(params);
+
+    status_t err = initDecoder();
+    ASSERT_EQ(err, OK) << "initDecoder: failed to create decoder " << err;
+
+    bool isMpeg4 = get<2>(params);
+    MP4DecodingMode inputMode = isMpeg4 ? MPEG4_MODE : H263_MODE;
+    ASSERT_NO_FATAL_FAILURE(
+            processMpeg4H263Decoder(Info, 0, Info.size(), mEleStream, ostrm, inputMode));
+    deInitDecoder();
+    ostrm.close();
+    Info.clear();
+}
+
+TEST_P(Mpeg4H263DecoderTest, FlushTest) {
+    tuple<string /* InputFileName */, string /* InfoFileName */, bool /* mode */> params =
+            GetParam();
+
+    string inputFileName = gEnv->getRes() + get<0>(params);
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << get<0>(params);
+
+    string infoFileName = gEnv->getRes() + get<1>(params);
+    vector<FrameInfo> Info;
+    ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
+    ASSERT_NE(Info.empty(), true) << "Invalid Info file";
+
+    ofstream ostrm;
+    ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+    ASSERT_EQ(ostrm.is_open(), true) << "Failed to open output stream for " << get<0>(params);
+
+    status_t err = initDecoder();
+    ASSERT_EQ(err, OK) << "initDecoder: failed to create decoder " << err;
+
+    bool isMpeg4 = get<2>(params);
+    MP4DecodingMode inputMode = isMpeg4 ? MPEG4_MODE : H263_MODE;
+    // Number of frames to be decoded before flush
+    int32_t numFrames = Info.size() / 3;
+    ASSERT_NO_FATAL_FAILURE(
+            processMpeg4H263Decoder(Info, 0, numFrames, mEleStream, ostrm, inputMode));
+
+    if (mInitialized) {
+        int32_t status = PVResetVideoDecoder(mDecHandle);
+        ASSERT_EQ(status, PV_TRUE);
+    }
+
+    // Seek to next key frame and start decoding till the end
+    int32_t index = numFrames;
+    bool keyFrame = false;
+    uint32_t flags = 0;
+    while (index < (int32_t)Info.size()) {
+        if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
+        if ((flags & SYNC_FRAME) == SYNC_FRAME) {
+            keyFrame = true;
+            break;
+        }
+        flags = 0;
+        mEleStream.ignore(Info[index].bytesCount);
+        index++;
+    }
+    ALOGV("Index= %d", index);
+    if (keyFrame) {
+        mNumSamplesOutput = 0;
+        ASSERT_NO_FATAL_FAILURE(processMpeg4H263Decoder(Info, index, (int32_t)Info.size() - index,
+                                                        mEleStream, ostrm, inputMode));
+    }
+    deInitDecoder();
+    ostrm.close();
+    Info.clear();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        Mpeg4H263DecoderTestAll, Mpeg4H263DecoderTest,
+        ::testing::Values(make_tuple("swirl_128x96_h263.h263", "swirl_128x96_h263.info", false),
+                          make_tuple("swirl_176x144_h263.h263", "swirl_176x144_h263.info", false),
+                          make_tuple("swirl_352x288_h263.h263", "swirl_352x288_h263.info", false),
+                          make_tuple("bbb_352x288_h263.h263", "bbb_352x288_h263.info", false),
+                          make_tuple("bbb_352x288_mpeg4.m4v", "bbb_352x288_mpeg4.info", true),
+                          make_tuple("swirl_128x128_mpeg4.m4v", "swirl_128x128_mpeg4.info", true),
+                          make_tuple("swirl_130x132_mpeg4.m4v", "swirl_130x132_mpeg4.info", true),
+                          make_tuple("swirl_132x130_mpeg4.m4v", "swirl_132x130_mpeg4.info", true),
+                          make_tuple("swirl_136x144_mpeg4.m4v", "swirl_136x144_mpeg4.info", true),
+                          make_tuple("swirl_144x136_mpeg4.m4v", "swirl_144x136_mpeg4.info", true)));
+
+int main(int argc, char **argv) {
+    gEnv = new Mpeg4H263DecoderTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGD("Decoder Test Result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTestEnvironment.h b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTestEnvironment.h
new file mode 100644
index 0000000..f085845
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef __MPEG4_H263_DECODER_TEST_ENVIRONMENT_H__
+#define __MPEG4_H263_DECODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mpeg4H263DecoderTestEnvironment : public ::testing::Environment {
+  public:
+    Mpeg4H263DecoderTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int Mpeg4H263DecoderTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P': {
+                setRes(optarg);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __MPEG4_H263_DECODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/README.md b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
new file mode 100644
index 0000000..3f46529
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### Mpeg4H263Decoder :
+The Mpeg4H263Decoder Test Suite validates the Mpeg4 and H263 decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m Mpeg4H263DecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/Mpeg4H263DecoderTest/Mpeg4H263DecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/Mpeg4H263DecoderTest/Mpeg4H263DecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b).
+Download Mpeg4H263Decoder folder and push all the files in this folder to /data/local/tmp/ on the device for testing.
+```
+adb push Mpeg4H263Decoder/. /data/local/tmp/
+```
+
+usage: Mpeg4H263DecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mpeg4H263DecoderTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/codecs/mp3dec/test/Android.bp b/media/libstagefright/codecs/mp3dec/test/Android.bp
new file mode 100644
index 0000000..0ff8b12
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "Mp3DecoderTest",
+    gtest: true,
+
+    srcs: [
+        "mp3reader.cpp",
+        "Mp3DecoderTest.cpp",
+    ],
+
+    static_libs: [
+        "libstagefright_mp3dec",
+        "libsndfile",
+        "libaudioutils",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
new file mode 100644
index 0000000..99553ec
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTest.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Mp3DecoderTest"
+
+#include <utils/Log.h>
+
+#include <audio_utils/sndfile.h>
+#include <stdio.h>
+
+#include "mp3reader.h"
+#include "pvmp3decoder_api.h"
+
+#include "Mp3DecoderTestEnvironment.h"
+
+#define OUTPUT_FILE "/data/local/tmp/mp3Decode.out"
+
+constexpr int32_t kInputBufferSize = 1024 * 10;
+constexpr int32_t kOutputBufferSize = 4608 * 2;
+constexpr int32_t kMaxCount = 10;
+constexpr int32_t kNumFrameReset = 150;
+
+static Mp3DecoderTestEnvironment *gEnv = nullptr;
+
+class Mp3DecoderTest : public ::testing::TestWithParam<string> {
+  public:
+    Mp3DecoderTest() : mConfig(nullptr) {}
+
+    ~Mp3DecoderTest() {
+        if (mConfig) {
+            delete mConfig;
+            mConfig = nullptr;
+        }
+    }
+
+    virtual void SetUp() override {
+        mConfig = new tPVMP3DecoderExternal{};
+        ASSERT_NE(mConfig, nullptr) << "Failed to initialize config. No Memory available";
+        mConfig->equalizerType = flat;
+        mConfig->crcEnabled = false;
+    }
+
+    tPVMP3DecoderExternal *mConfig;
+    Mp3Reader mMp3Reader;
+
+    ERROR_CODE DecodeFrames(void *decoderbuf, SNDFILE *outFileHandle, SF_INFO sfInfo,
+                            int32_t frameCount = INT32_MAX);
+    SNDFILE *openOutputFile(SF_INFO *sfInfo);
+};
+
+ERROR_CODE Mp3DecoderTest::DecodeFrames(void *decoderBuf, SNDFILE *outFileHandle, SF_INFO sfInfo,
+                                        int32_t frameCount) {
+    uint8_t inputBuf[kInputBufferSize];
+    int16_t outputBuf[kOutputBufferSize];
+    uint32_t bytesRead;
+    ERROR_CODE decoderErr;
+    while (frameCount > 0) {
+        bool success = mMp3Reader.getFrame(inputBuf, &bytesRead);
+        if (!success) {
+            break;
+        }
+        mConfig->inputBufferCurrentLength = bytesRead;
+        mConfig->inputBufferMaxLength = 0;
+        mConfig->inputBufferUsedLength = 0;
+        mConfig->pInputBuffer = inputBuf;
+        mConfig->pOutputBuffer = outputBuf;
+        mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+        decoderErr = pvmp3_framedecoder(mConfig, decoderBuf);
+        if (decoderErr != NO_DECODING_ERROR) break;
+        sf_writef_short(outFileHandle, outputBuf, mConfig->outputFrameSize / sfInfo.channels);
+        frameCount--;
+    }
+    return decoderErr;
+}
+
+SNDFILE *Mp3DecoderTest::openOutputFile(SF_INFO *sfInfo) {
+    memset(sfInfo, 0, sizeof(SF_INFO));
+    sfInfo->channels = mMp3Reader.getNumChannels();
+    sfInfo->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+    sfInfo->samplerate = mMp3Reader.getSampleRate();
+    SNDFILE *outFileHandle = sf_open(OUTPUT_FILE, SFM_WRITE, sfInfo);
+    return outFileHandle;
+}
+
+TEST_F(Mp3DecoderTest, MultiCreateMp3DecoderTest) {
+    size_t memRequirements = pvmp3_decoderMemRequirements();
+    ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+    void *decoderBuf = malloc(memRequirements);
+    ASSERT_NE(decoderBuf, nullptr)
+            << "Failed to allocate decoder memory of size " << memRequirements;
+    for (int count = 0; count < kMaxCount; count++) {
+        pvmp3_InitDecoder(mConfig, decoderBuf);
+        ALOGV("Decoder created successfully");
+    }
+    if (decoderBuf) {
+        free(decoderBuf);
+        decoderBuf = nullptr;
+    }
+}
+
+TEST_P(Mp3DecoderTest, DecodeTest) {
+    size_t memRequirements = pvmp3_decoderMemRequirements();
+    ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+    void *decoderBuf = malloc(memRequirements);
+    ASSERT_NE(decoderBuf, nullptr)
+            << "Failed to allocate decoder memory of size " << memRequirements;
+
+    pvmp3_InitDecoder(mConfig, decoderBuf);
+    ALOGV("Decoder created successfully");
+    string inputFile = gEnv->getRes() + GetParam();
+    bool status = mMp3Reader.init(inputFile.c_str());
+    ASSERT_TRUE(status) << "Unable to initialize the mp3Reader";
+
+    // Open the output file.
+    SF_INFO sfInfo;
+    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+    ERROR_CODE decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo);
+    ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+    ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+    ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+    mMp3Reader.close();
+    sf_close(outFileHandle);
+    if (decoderBuf) {
+        free(decoderBuf);
+        decoderBuf = nullptr;
+    }
+}
+
+TEST_P(Mp3DecoderTest, ResetDecoderTest) {
+    size_t memRequirements = pvmp3_decoderMemRequirements();
+    ASSERT_NE(memRequirements, 0) << "Failed to get the memory requirement size";
+    void *decoderBuf = malloc(memRequirements);
+    ASSERT_NE(decoderBuf, nullptr)
+            << "Failed to allocate decoder memory of size " << memRequirements;
+
+    pvmp3_InitDecoder(mConfig, decoderBuf);
+    ALOGV("Decoder created successfully.");
+    string inputFile = gEnv->getRes() + GetParam();
+    bool status = mMp3Reader.init(inputFile.c_str());
+    ASSERT_TRUE(status) << "Unable to initialize the mp3Reader";
+
+    // Open the output file.
+    SF_INFO sfInfo;
+    SNDFILE *outFileHandle = openOutputFile(&sfInfo);
+    ASSERT_NE(outFileHandle, nullptr) << "Error opening output file for writing decoded output";
+
+    ERROR_CODE decoderErr;
+    decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo, kNumFrameReset);
+    ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+    ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+    ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+    pvmp3_resetDecoder(decoderBuf);
+    // Decode the same file.
+    decoderErr = DecodeFrames(decoderBuf, outFileHandle, sfInfo);
+    ASSERT_EQ(decoderErr, NO_DECODING_ERROR) << "Failed to decode the frames";
+    ASSERT_EQ(sfInfo.channels, mConfig->num_channels) << "Number of channels does not match";
+    ASSERT_EQ(sfInfo.samplerate, mConfig->samplingRate) << "Sample rate does not match";
+
+    mMp3Reader.close();
+    sf_close(outFileHandle);
+    if (decoderBuf) {
+        free(decoderBuf);
+        decoderBuf = nullptr;
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(Mp3DecoderTestAll, Mp3DecoderTest,
+                         ::testing::Values(("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3"),
+                                           ("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3"),
+                                           ("bbb_mp3_stereo_192kbps_48000hz.mp3")));
+
+int main(int argc, char **argv) {
+    gEnv = new Mp3DecoderTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.h b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.h
new file mode 100644
index 0000000..a54b34c
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/Mp3DecoderTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __MP3DECODER_TEST_ENVIRONMENT_H__
+#define __MP3DECODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mp3DecoderTestEnvironment : public ::testing::Environment {
+  public:
+    Mp3DecoderTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int Mp3DecoderTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __MP3DECODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/mp3dec/test/README.md b/media/libstagefright/codecs/mp3dec/test/README.md
new file mode 100644
index 0000000..019239e
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### Mp3Decoder :
+The Mp3Decoder Test Suite validates the mp3decoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m Mp3DecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/Mp3DecoderTest/Mp3DecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/Mp3DecoderTest/Mp3DecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
+Download mp3 folder and push all the files in this folder to /data/local/tmp/ on the device.
+```
+adb push mp3/. /data/local/tmp/
+```
+
+usage: Mp3DecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mp3DecoderTest -P /data/local/tmp/
+```
diff --git a/media/libstagefright/id3/test/Android.bp b/media/libstagefright/id3/test/Android.bp
new file mode 100644
index 0000000..9d26eec
--- /dev/null
+++ b/media/libstagefright/id3/test/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "ID3Test",
+    gtest: true,
+
+    srcs: ["ID3Test.cpp"],
+
+    static_libs: [
+        "libdatasource",
+        "libstagefright_id3",
+        "libstagefright",
+        "libstagefright_foundation",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+        "libbinder",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/id3/test/ID3Test.cpp b/media/libstagefright/id3/test/ID3Test.cpp
new file mode 100644
index 0000000..a8f1470
--- /dev/null
+++ b/media/libstagefright/id3/test/ID3Test.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ID3Test"
+#include <utils/Log.h>
+
+#include <ctype.h>
+#include <string>
+#include <sys/stat.h>
+#include <datasource/FileSource.h>
+
+#include <media/stagefright/foundation/hexdump.h>
+#include <ID3.h>
+
+#include "ID3TestEnvironment.h"
+
+using namespace android;
+
+static ID3TestEnvironment *gEnv = nullptr;
+
+class ID3tagTest : public ::testing::TestWithParam<string> {};
+class ID3versionTest : public ::testing::TestWithParam<pair<string, int>> {};
+class ID3textTagTest : public ::testing::TestWithParam<pair<string, int>> {};
+class ID3albumArtTest : public ::testing::TestWithParam<pair<string, bool>> {};
+class ID3multiAlbumArtTest : public ::testing::TestWithParam<pair<string, int>> {};
+
+TEST_P(ID3tagTest, TagTest) {
+    string path = gEnv->getRes() + GetParam();
+    sp<FileSource> file = new FileSource(path.c_str());
+    ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+    ID3 tag(file.get());
+    ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+
+    ID3::Iterator it(tag, nullptr);
+    while (!it.done()) {
+        String8 id;
+        it.getID(&id);
+        ASSERT_GT(id.length(), 0) << "No ID tag found! \n";
+        ALOGV("Found ID tag: %s\n", String8(id).c_str());
+        it.next();
+    }
+}
+
+TEST_P(ID3versionTest, VersionTest) {
+    int versionNumber = GetParam().second;
+    string path = gEnv->getRes() + GetParam().first;
+    sp<android::FileSource> file = new FileSource(path.c_str());
+    ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+    ID3 tag(file.get());
+    ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+    ASSERT_TRUE(tag.version() >= versionNumber)
+            << "Expected version: " << tag.version() << " Found version: " << versionNumber;
+}
+
+TEST_P(ID3textTagTest, TextTagTest) {
+    int numTextFrames = GetParam().second;
+    string path = gEnv->getRes() + GetParam().first;
+    sp<android::FileSource> file = new FileSource(path.c_str());
+    ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+    ID3 tag(file.get());
+    ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+    int countTextFrames = 0;
+    ID3::Iterator it(tag, nullptr);
+    while (!it.done()) {
+        String8 id;
+        it.getID(&id);
+        ASSERT_GT(id.length(), 0);
+        if (id[0] == 'T') {
+            String8 text;
+            countTextFrames++;
+            it.getString(&text);
+            ALOGV("Found text frame %s : %s \n", id.string(), text.string());
+        }
+        it.next();
+    }
+    ASSERT_EQ(countTextFrames, numTextFrames)
+            << "Expected " << numTextFrames << " text frames, found " << countTextFrames;
+}
+
+TEST_P(ID3albumArtTest, AlbumArtTest) {
+    bool albumArtPresent = GetParam().second;
+    string path = gEnv->getRes() + GetParam().first;
+    sp<android::FileSource> file = new FileSource(path.c_str());
+    ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+    ID3 tag(file.get());
+    ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+    size_t dataSize;
+    String8 mime;
+    const void *data = tag.getAlbumArt(&dataSize, &mime);
+
+    if (albumArtPresent) {
+        if (data) {
+            ALOGV("Found album art: size = %zu mime = %s \n", dataSize, mime.string());
+        }
+        ASSERT_NE(data, nullptr) << "Expected album art, found none!" << path;
+    } else {
+        ASSERT_EQ(data, nullptr) << "Found album art when expected none!";
+    }
+#if (LOG_NDEBUG == 0)
+    hexdump(data, dataSize > 128 ? 128 : dataSize);
+#endif
+}
+
+TEST_P(ID3multiAlbumArtTest, MultiAlbumArtTest) {
+    int numAlbumArt = GetParam().second;
+    string path = gEnv->getRes() + GetParam().first;
+    sp<android::FileSource> file = new FileSource(path.c_str());
+    ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
+
+    ID3 tag(file.get());
+    ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
+    int count = 0;
+    ID3::Iterator it(tag, nullptr);
+    while (!it.done()) {
+        String8 id;
+        it.getID(&id);
+        ASSERT_GT(id.length(), 0);
+        // Check if the tag is an "APIC/PIC" tag.
+        if (String8(id) == "APIC" || String8(id) == "PIC") {
+            count++;
+            size_t dataSize;
+            String8 mime;
+            const void *data = tag.getAlbumArt(&dataSize, &mime);
+            if (data) {
+                ALOGV("Found album art: size = %zu mime = %s \n", dataSize, mime.string());
+#if (LOG_NDEBUG == 0)
+                hexdump(data, dataSize > 128 ? 128 : dataSize);
+#endif
+            }
+            ASSERT_NE(data, nullptr) << "Expected album art, found none!" << path;
+        }
+        it.next();
+    }
+    ASSERT_EQ(count, numAlbumArt) << "Found " << count << " album arts, expected " << numAlbumArt
+                                  << " album arts! \n";
+}
+
+INSTANTIATE_TEST_SUITE_P(id3TestAll, ID3tagTest,
+                         ::testing::Values("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3",
+                                           "bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3",
+                                           "bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3",
+                                           "bbb_44100hz_2ch_128kbps_mp3_5mins.mp3",
+                                           "bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3",
+                                           "bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3",
+                                           "bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3",
+                                           "bbb_44100hz_2ch_128kbps_mp3_30sec_moreTextFrames.mp3"));
+
+INSTANTIATE_TEST_SUITE_P(
+        id3TestAll, ID3versionTest,
+        ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", 4),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", 4),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", 4),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 4),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", 4),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", 4),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", 4),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_moreTextFrames.mp3", 4)));
+
+INSTANTIATE_TEST_SUITE_P(
+        id3TestAll, ID3textTagTest,
+        ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_moreTextFrames.mp3", 5)));
+
+INSTANTIATE_TEST_SUITE_P(
+        id3TestAll, ID3albumArtTest,
+        ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", true),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", true),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", false),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", true),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", true),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", true)));
+
+INSTANTIATE_TEST_SUITE_P(
+        id3TestAll, ID3multiAlbumArtTest,
+        ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", 0),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_1_image.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_1_image.mp3", 1),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec_2_image.mp3", 2),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_2_image.mp3", 2),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_5mins_largeSize.mp3", 3)));
+
+int main(int argc, char **argv) {
+    gEnv = new ID3TestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGI("ID3 Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/id3/test/ID3TestEnvironment.h b/media/libstagefright/id3/test/ID3TestEnvironment.h
new file mode 100644
index 0000000..2229718
--- /dev/null
+++ b/media/libstagefright/id3/test/ID3TestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __ID3_TEST_ENVIRONMENT_H__
+#define __ID3_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class ID3TestEnvironment : public::testing::Environment {
+  public:
+    ID3TestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int ID3TestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P': {
+                setRes(optarg);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __ID3_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/id3/test/README.md b/media/libstagefright/id3/test/README.md
new file mode 100644
index 0000000..72f730c
--- /dev/null
+++ b/media/libstagefright/id3/test/README.md
@@ -0,0 +1,34 @@
+## Media Testing ##
+---
+#### ID3 Test :
+The ID3 Test Suite validates the ID3 parser available in libstagefright.
+
+Run the following command in the id3 folder to build the test suite:
+```
+m ID3Test
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/ID3Test/ID3Test /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/ID3Test/ID3Test /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/1pt5HFVSysbqfyqY1sVJ9MTupZKCdqjYZ). Push these files into device for testing.
+Download ID3 folder and push all the files in this folder to /data/local/tmp/ID3 on the device.
+```
+adb push ID3/. /data/local/tmp/ID3
+```
+
+usage: ID3Test -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/ID3Test -P /data/local/tmp/ID3/
+```
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index cd30347..01d0325 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -25,7 +25,7 @@
 #include <media/hardware/CryptoAPI.h>
 #include <media/MediaCodecInfo.h>
 #include <media/MediaResource.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetrics.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/FrameRenderTracker.h>
 #include <utils/Vector.h>
@@ -189,7 +189,7 @@
 
     status_t getCodecInfo(sp<MediaCodecInfo> *codecInfo) const;
 
-    status_t getMetrics(MediaAnalyticsItem * &reply);
+    status_t getMetrics(mediametrics_handle_t &reply);
 
     status_t setParameters(const sp<AMessage> &params);
 
@@ -328,11 +328,11 @@
     sp<Surface> mSurface;
     SoftwareRenderer *mSoftRenderer;
 
-    MediaAnalyticsItem *mAnalyticsItem;
-    void initAnalyticsItem();
-    void updateAnalyticsItem();
-    void flushAnalyticsItem();
-    void updateEphemeralAnalytics(MediaAnalyticsItem *item);
+    mediametrics_handle_t mMetricsHandle;
+    void initMediametrics();
+    void updateMediametrics();
+    void flushMediametrics();
+    void updateEphemeralMediametrics(mediametrics_handle_t item);
 
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index a507b91..cab841c 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -29,7 +29,6 @@
 
     shared_libs: [
         "libcrypto",
-        "libmedia",
         "libhidlmemory",
         "android.hardware.cas.native@1.0",
         "android.hidl.memory@1.0",
@@ -37,6 +36,8 @@
     ],
 
     header_libs: [
+        "libmedia_headers",
+        "libaudioclient_headers",
         "media_ndk_headers",
     ],
 
diff --git a/media/libstagefright/tests/writer/README.md b/media/libstagefright/tests/writer/README.md
index 52db6f0..ae07917 100644
--- a/media/libstagefright/tests/writer/README.md
+++ b/media/libstagefright/tests/writer/README.md
@@ -19,12 +19,13 @@
 
 adb push ${OUT}/data/nativetest/writerTest/writerTest /data/local/tmp/
 
-The resource file for the tests is taken from Codec2 VTS resource folder. Push these files into device for testing.
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/tests/writer/writerTestRes.zip).
+Download and extract the folder. Push all the files in this folder to /data/local/tmp/ on the device.
 ```
-adb push  $ANDROID_BUILD_TOP/frameworks/av/media/codec2/hidl/1.0/vts/functional/res /sdcard/
+adb push writerTestRes /data/local/tmp/
 ```
 
 usage: writerTest -P \<path_to_res_folder\>
 ```
-adb shell /data/local/tmp/writerTest -P /sdcard/res/
+adb shell /data/local/tmp/writerTest -P /data/local/tmp/
 ```
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index d68438c..409f141 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -29,9 +29,9 @@
 
 #include <media/stagefright/AACWriter.h>
 #include <media/stagefright/AMRWriter.h>
-#include <media/stagefright/OggWriter.h>
-#include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MPEG4Writer.h>
+#include <media/stagefright/OggWriter.h>
 #include <webm/WebmWriter.h>
 
 #include "WriterTestEnvironment.h"
@@ -89,19 +89,36 @@
 
 class WriterTest : public ::testing::TestWithParam<pair<string, int32_t>> {
   public:
+    WriterTest() : mWriter(nullptr), mFileMeta(nullptr), mCurrentTrack(nullptr) {}
+
+    ~WriterTest() {
+        if (mWriter) {
+            mWriter.clear();
+            mWriter = nullptr;
+        }
+        if (mFileMeta) {
+            mFileMeta.clear();
+            mFileMeta = nullptr;
+        }
+        if (mCurrentTrack) {
+            mCurrentTrack.clear();
+            mCurrentTrack = nullptr;
+        }
+    }
+
     virtual void SetUp() override {
         mNumCsds = 0;
         mInputFrameId = 0;
         mWriterName = unknown_comp;
         mDisableTest = false;
 
-        std::map<std::string, standardWriters> mapWriter = {
+        static const std::map<std::string, standardWriters> mapWriter = {
                 {"ogg", OGG},     {"aac", AAC},      {"aac_adts", AAC_ADTS}, {"webm", WEBM},
                 {"mpeg4", MPEG4}, {"amrnb", AMR_NB}, {"amrwb", AMR_WB},      {"mpeg2Ts", MPEG2TS}};
         // Find the component type
         string writerFormat = GetParam().first;
         if (mapWriter.find(writerFormat) != mapWriter.end()) {
-            mWriterName = mapWriter[writerFormat];
+            mWriterName = mapWriter.at(writerFormat);
         }
         if (mWriterName == standardWriters::unknown_comp) {
             cout << "[   WARN   ] Test Skipped. No specific writer mentioned\n";
@@ -110,10 +127,8 @@
     }
 
     virtual void TearDown() override {
-        mWriter.clear();
-        mFileMeta.clear();
         mBufferInfo.clear();
-        if (mInputStream) mInputStream.close();
+        if (mInputStream.is_open()) mInputStream.close();
     }
 
     void getInputBufferInfo(string inputFileName, string inputInfo);
@@ -149,7 +164,7 @@
 void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo) {
     std::ifstream eleInfo;
     eleInfo.open(inputInfo.c_str());
-    CHECK_EQ(eleInfo.is_open(), true);
+    ASSERT_EQ(eleInfo.is_open(), true);
     int32_t bytesCount = 0;
     uint32_t flags = 0;
     int64_t timestamp = 0;
@@ -162,7 +177,7 @@
     }
     eleInfo.close();
     mInputStream.open(inputFileName.c_str(), std::ifstream::binary);
-    CHECK_EQ(mInputStream.is_open(), true);
+    ASSERT_EQ(mInputStream.is_open(), true);
 }
 
 int32_t WriterTest::createWriter(int32_t fd) {
@@ -258,14 +273,11 @@
     string outputFile = OUTPUT_FILE_NAME;
     int32_t fd =
             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
-    if (fd < 0) return;
+    ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
 
     // Creating writer within a test scope. Destructor should be called when the test ends
-    int32_t status = createWriter(fd);
-    if (status) {
-        cout << "Failed to create writer for output format:" << GetParam().first << "\n";
-        ASSERT_TRUE(false);
-    }
+    ASSERT_EQ((status_t)OK, createWriter(fd))
+            << "Failed to create writer for output format:" << GetParam().first;
 }
 
 TEST_P(WriterTest, WriterTest) {
@@ -276,38 +288,32 @@
     string outputFile = OUTPUT_FILE_NAME;
     int32_t fd =
             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
-    if (fd < 0) return;
+    ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
     int32_t status = createWriter(fd);
-    if (status) {
-        cout << "Failed to create writer for output format:" << writerFormat << "\n";
-        ASSERT_TRUE(false);
-    }
+    ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
+
     string inputFile = gEnv->getRes();
     string inputInfo = gEnv->getRes();
     configFormat param;
     bool isAudio;
     int32_t inputFileIdx = GetParam().second;
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
-    if (!inputFile.compare(gEnv->getRes())) {
-        ALOGV("No input file specified");
-        return;
-    }
+    ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
     getInputBufferInfo(inputFile, inputInfo);
     status = addWriterSource(isAudio, param);
-    if (status) {
-        cout << "Failed to add source for " << writerFormat << "Writer \n";
-        ASSERT_TRUE(false);
-    }
-    CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+    ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+
+    status = mWriter->start(mFileMeta.get());
+    ASSERT_EQ((status_t)OK, status);
     status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
                                  mBufferInfo.size());
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
     mCurrentTrack->stop();
-    if (status) {
-        cout << writerFormat << " writer failed \n";
-        mWriter->stop();
-        ASSERT_TRUE(false);
-    }
-    CHECK_EQ((status_t)OK, mWriter->stop());
+
+    status = mWriter->stop();
+    ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
     close(fd);
 }
 
@@ -319,59 +325,125 @@
     string outputFile = OUTPUT_FILE_NAME;
     int32_t fd =
             open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
-    if (fd < 0) return;
+    ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
     int32_t status = createWriter(fd);
-    if (status) {
-        cout << "Failed to create writer for output format:" << writerFormat << "\n";
-        ASSERT_TRUE(false);
-    }
+    ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
+
     string inputFile = gEnv->getRes();
     string inputInfo = gEnv->getRes();
     configFormat param;
     bool isAudio;
     int32_t inputFileIdx = GetParam().second;
     getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
-    if (!inputFile.compare(gEnv->getRes())) {
-        ALOGV("No input file specified");
-        return;
-    }
+    ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
     getInputBufferInfo(inputFile, inputInfo);
     status = addWriterSource(isAudio, param);
-    if (status) {
-        cout << "Failed to add source for " << writerFormat << "Writer \n";
-        ASSERT_TRUE(false);
-    }
-    CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+    ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+
+    status = mWriter->start(mFileMeta.get());
+    ASSERT_EQ((status_t)OK, status);
     status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
                                  mBufferInfo.size() / 4);
-    if (status) {
-        cout << writerFormat << " writer failed \n";
-        mCurrentTrack->stop();
-        mWriter->stop();
-        ASSERT_TRUE(false);
-    }
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
 
     bool isPaused = false;
     if ((mWriterName != standardWriters::MPEG2TS) && (mWriterName != standardWriters::MPEG4)) {
-        CHECK_EQ((status_t)OK, mWriter->pause());
+        status = mWriter->pause();
+        ASSERT_EQ((status_t)OK, status);
         isPaused = true;
     }
     // In the pause state, writers shouldn't write anything. Testing the writers for the same
     int32_t numFramesPaused = mBufferInfo.size() / 4;
-    status |= sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
                                   mInputFrameId, numFramesPaused, isPaused);
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
     if (isPaused) {
-        CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+        status = mWriter->start(mFileMeta.get());
+        ASSERT_EQ((status_t)OK, status);
     }
-    status |= sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
                                   mInputFrameId, mBufferInfo.size());
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
     mCurrentTrack->stop();
-    if (status) {
-        cout << writerFormat << " writer failed \n";
-        mWriter->stop();
-        ASSERT_TRUE(false);
+
+    status = mWriter->stop();
+    ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
+    close(fd);
+}
+
+TEST_P(WriterTest, MultiStartStopPauseTest) {
+    // TODO: (b/144821804)
+    // Enable the test for MPE2TS writer
+    if (mDisableTest || mWriterName == standardWriters::MPEG2TS) return;
+    ALOGV("Test writers for multiple start, stop and pause calls");
+
+    string outputFile = OUTPUT_FILE_NAME;
+    int32_t fd =
+            open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+    ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
+    string writerFormat = GetParam().first;
+    int32_t status = createWriter(fd);
+    ASSERT_EQ(status, (status_t)OK) << "Failed to create writer for output format:" << writerFormat;
+
+    string inputFile = gEnv->getRes();
+    string inputInfo = gEnv->getRes();
+    configFormat param;
+    bool isAudio;
+    int32_t inputFileIdx = GetParam().second;
+    getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+    ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
+    getInputBufferInfo(inputFile, inputInfo);
+    status = addWriterSource(isAudio, param);
+    ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+
+    // first start should succeed.
+    status = mWriter->start(mFileMeta.get());
+    ASSERT_EQ((status_t)OK, status) << "Could not start the writer";
+
+    // Multiple start() may/may not succeed.
+    // Writers are expected to not crash on multiple start() calls.
+    for (int32_t count = 0; count < kMaxCount; count++) {
+        mWriter->start(mFileMeta.get());
     }
-    CHECK_EQ((status_t)OK, mWriter->stop());
+
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+                              mBufferInfo.size() / 4);
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+    for (int32_t count = 0; count < kMaxCount; count++) {
+        mWriter->pause();
+        mWriter->start(mFileMeta.get());
+    }
+
+    mWriter->pause();
+    int32_t numFramesPaused = mBufferInfo.size() / 4;
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+                              mInputFrameId, numFramesPaused, true);
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+    for (int32_t count = 0; count < kMaxCount; count++) {
+        mWriter->start(mFileMeta.get());
+    }
+
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+                              mInputFrameId, mBufferInfo.size());
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+
+    mCurrentTrack->stop();
+
+    // first stop should succeed.
+    status = mWriter->stop();
+    ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
+    // Multiple stop() may/may not succeed.
+    // Writers are expected to not crash on multiple stop() calls.
+    for (int32_t count = 0; count < kMaxCount; count++) {
+        mWriter->stop();
+    }
     close(fd);
 }
 
diff --git a/media/libstagefright/tests/writer/WriterTestEnvironment.h b/media/libstagefright/tests/writer/WriterTestEnvironment.h
index 34c2baa..99e686f 100644
--- a/media/libstagefright/tests/writer/WriterTestEnvironment.h
+++ b/media/libstagefright/tests/writer/WriterTestEnvironment.h
@@ -25,7 +25,7 @@
 
 class WriterTestEnvironment : public ::testing::Environment {
   public:
-    WriterTestEnvironment() : res("/sdcard/media/") {}
+    WriterTestEnvironment() : res("/data/local/tmp/") {}
 
     // Parses the command line arguments
     int initFromOptions(int argc, char **argv);
diff --git a/media/libstagefright/tests/writer/WriterUtility.cpp b/media/libstagefright/tests/writer/WriterUtility.cpp
index 2ba90a0..f24ccb6 100644
--- a/media/libstagefright/tests/writer/WriterUtility.cpp
+++ b/media/libstagefright/tests/writer/WriterUtility.cpp
@@ -26,7 +26,7 @@
                             int32_t &inputFrameId, sp<MediaAdapter> &currentTrack, int32_t offset,
                             int32_t range, bool isPaused) {
     while (1) {
-        if (inputFrameId == (int)bufferInfo.size() || inputFrameId >= (offset + range)) break;
+        if (inputFrameId >= (int)bufferInfo.size() || inputFrameId >= (offset + range)) break;
         int32_t size = bufferInfo[inputFrameId].size;
         char *data = (char *)malloc(size);
         if (!data) {
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
index d402798..cdd6246 100644
--- a/media/libstagefright/tests/writer/WriterUtility.h
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -33,6 +33,7 @@
 #define CODEC_CONFIG_FLAG 32
 
 constexpr uint32_t kMaxCSDStrlen = 16;
+constexpr uint32_t kMaxCount = 20;
 
 struct BufferInfo {
     int32_t size;
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index aac6d71..24cad4d 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -113,10 +113,6 @@
         symbol_file: "libmediandk.map.txt",
         versions: ["29"],
     },
-
-    // Bug: http://b/124522995 libmediandk has linker errors when built with
-    // coverage
-    native_coverage: false,
 }
 
 llndk_library {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
index 91b03f1..d80d9a5 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/Android.bp
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -17,11 +17,13 @@
 android_test {
     name: "MediaBenchmarkTest",
 
+    defaults: [
+        "MediaBenchmark-defaults",
+    ],
+
     // Include all the test code
     srcs: ["src/androidTest/**/*.java"],
 
-    sdk_version: "system_current",
-
     resource_dirs: ["res"],
 
     libs: [
@@ -29,6 +31,10 @@
         "android.test.base",
     ],
 
+    jni_libs: [
+        "libmediabenchmark_jni",
+    ],
+
     static_libs: [
         "libMediaBenchmark",
         "junit",
@@ -39,12 +45,22 @@
 android_library {
     name: "libMediaBenchmark",
 
+    defaults: [
+        "MediaBenchmark-defaults",
+    ],
+
     // Include all the libraries
     srcs: ["src/main/**/*.java"],
 
-    sdk_version: "system_current",
-
     static_libs: [
         "androidx.test.core",
     ],
 }
+
+java_defaults {
+    name: "MediaBenchmark-defaults",
+
+    sdk_version: "system_current",
+    min_sdk_version: "28",
+    target_sdk_version: "29",
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
index 89d6ce2..1179d6c 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
@@ -15,6 +15,7 @@
 -->
 <configuration description="Runs Media Benchmark Tests">
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="cleanup-apks" value="false" />
         <option name="test-file-name" value="MediaBenchmarkTest.apk" />
     </target_preparer>
 
diff --git a/media/tests/benchmark/MediaBenchmarkTest/build.gradle b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
index b0ee692..b2aee1a 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/build.gradle
+++ b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
@@ -30,7 +30,7 @@
     compileSdkVersion 29
     defaultConfig {
         applicationId "com.android.media.benchmark"
-        minSdkVersion 21
+        minSdkVersion 28
         targetSdkVersion 29
         versionCode 1
         versionName "1.0"
@@ -48,6 +48,18 @@
             manifest.srcFile 'AndroidManifest.xml'
         }
     }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "src/main/cpp/CMakeLists.txt"
+            version "3.10.2"
+        }
+    }
 }
 
 repositories {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
index be2633d..c41f198 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -27,7 +27,10 @@
 import com.android.media.benchmark.library.CodecUtils;
 import com.android.media.benchmark.library.Decoder;
 import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
 
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -44,12 +47,17 @@
 import java.util.Arrays;
 import java.util.Collection;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
 @RunWith(Parameterized.class)
 public class DecoderTest {
     private static final Context mContext =
             InstrumentationRegistry.getInstrumentation().getTargetContext();
     private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
     private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+    private static final String mStatsFile =
+            mContext.getExternalFilesDir(null) + "/Decoder." + System.currentTimeMillis() + ".csv";
     private static final String TAG = "DecoderTest";
     private static final long PER_TEST_TIMEOUT_MS = 60000;
     private static final boolean DEBUG = false;
@@ -101,97 +109,112 @@
                 {"crowd_1920x1080_25fps_4000kbps_h265.mkv", true}});
     }
 
+    @BeforeClass
+    public static void writeStatsHeaderToFile() throws IOException {
+        Stats mStats = new Stats();
+        boolean status = mStats.writeStatsHeader(mStatsFile);
+        assertTrue("Unable to open stats file for writing!", status);
+        Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+    }
+
     @Test(timeout = PER_TEST_TIMEOUT_MS)
     public void testDecoder() throws IOException {
         File inputFile = new File(mInputFilePath + mInputFile);
-        if (inputFile.exists()) {
-            FileInputStream fileInput = new FileInputStream(inputFile);
-            FileDescriptor fileDescriptor = fileInput.getFD();
-            Extractor extractor = new Extractor();
-            int trackCount = extractor.setUpExtractor(fileDescriptor);
-            ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
-            ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
-            if (trackCount <= 0) {
-                Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
-                return;
-            }
-            for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
-                extractor.selectExtractorTrack(currentTrack);
-                MediaFormat format = extractor.getFormat(currentTrack);
-                String mime = format.getString(MediaFormat.KEY_MIME);
-                ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
-                if (mediaCodecs.size() <= 0) {
-                    Log.e(TAG,
-                            "No suitable codecs found for file: " + mInputFile
-                                    + " track : " + currentTrack + " mime: " + mime);
-                    continue;
+        assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+                inputFile.exists());
+        FileInputStream fileInput = new FileInputStream(inputFile);
+        FileDescriptor fileDescriptor = fileInput.getFD();
+        Extractor extractor = new Extractor();
+        int trackCount = extractor.setUpExtractor(fileDescriptor);
+        assertTrue("Extraction failed. No tracks for file: " + mInputFile, (trackCount > 0));
+        ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+        ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+        for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+            extractor.selectExtractorTrack(currentTrack);
+            MediaFormat format = extractor.getFormat(currentTrack);
+            String mime = format.getString(MediaFormat.KEY_MIME);
+            ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+            assertTrue("No suitable codecs found for file: " + mInputFile + " track : " +
+                    currentTrack + " mime: " + mime, (mediaCodecs.size() > 0));
+
+            // Get samples from extractor
+            int sampleSize;
+            do {
+                sampleSize = extractor.getFrameSample();
+                MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+                MediaCodec.BufferInfo info = extractor.getBufferInfo();
+                ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+                dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+                bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+                inputBuffer.add(dataBuffer);
+                frameInfo.add(bufInfo);
+                if (DEBUG) {
+                    Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
+                            bufInfo.presentationTimeUs + " size = " + bufInfo.size);
                 }
-                // Get samples from extractor
-                int sampleSize;
-                do {
-                    sampleSize = extractor.getFrameSample();
-                    MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
-                    MediaCodec.BufferInfo info = extractor.getBufferInfo();
-                    ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
-                    dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
-                    bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
-                    inputBuffer.add(dataBuffer);
-                    frameInfo.add(bufInfo);
-                    if (DEBUG) {
-                        Log.d(TAG,
-                                "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = "
-                                        + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+            } while (sampleSize > 0);
+            for (String codecName : mediaCodecs) {
+                FileOutputStream decodeOutputStream = null;
+                if (WRITE_OUTPUT) {
+                    if (!Paths.get(mOutputFilePath).toFile().exists()) {
+                        Files.createDirectories(Paths.get(mOutputFilePath));
                     }
-                } while (sampleSize > 0);
-                for (String codecName : mediaCodecs) {
-                    FileOutputStream decodeOutputStream = null;
-                    if (WRITE_OUTPUT) {
-                        if (!Paths.get(mOutputFilePath).toFile().exists()) {
-                            Files.createDirectories(Paths.get(mOutputFilePath));
-                        }
-                        File outFile = new File(mOutputFilePath + "decoder.out");
-                        if (outFile.exists()) {
-                            if (!outFile.delete()) {
-                                Log.e(TAG, " Unable to delete existing file" + outFile.toString());
-                            }
-                        }
-                        if (outFile.createNewFile()) {
-                            decodeOutputStream = new FileOutputStream(outFile);
-                        } else {
-                            Log.e(TAG, "Unable to create file: " + outFile.toString());
-                        }
+                    File outFile = new File(mOutputFilePath + "decoder.out");
+                    if (outFile.exists()) {
+                        assertTrue(" Unable to delete existing file" + outFile.toString(),
+                                outFile.delete());
                     }
-                    Decoder decoder = new Decoder();
-                    decoder.setupDecoder(decodeOutputStream);
-                    int status =
-                            decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
-                    decoder.deInitCodec();
-                    if (status == 0) {
-                        decoder.dumpStatistics(
-                                mInputFile + " " + codecName, extractor.getClipDuration());
-                        Log.i(TAG,
-                                "Decoding Successful for file: " + mInputFile
-                                        + " with codec: " + codecName);
-                    } else {
-                        Log.e(TAG,
-                                "Decoder returned error " + status + " for file: " + mInputFile
-                                        + " with codec: " + codecName);
-                    }
-                    decoder.resetDecoder();
-                    if (decodeOutputStream != null) {
-                        decodeOutputStream.close();
-                    }
+                    assertTrue("Unable to create file: " + outFile.toString(),
+                            outFile.createNewFile());
+                    decodeOutputStream = new FileOutputStream(outFile);
                 }
-                extractor.unselectExtractorTrack(currentTrack);
-                inputBuffer.clear();
-                frameInfo.clear();
+                Decoder decoder = new Decoder();
+                decoder.setupDecoder(decodeOutputStream);
+                int status = decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
+                decoder.deInitCodec();
+                assertEquals("Decoder returned error " + status + " for file: " + mInputFile +
+                        " with codec: " + codecName, 0, status);
+                decoder.dumpStatistics(mInputFile, codecName, (mAsyncMode ? "async" : "sync"),
+                        extractor.getClipDuration(), mStatsFile);
+                Log.i(TAG, "Decoding Successful for file: " + mInputFile + " with codec: " +
+                        codecName);
+                decoder.resetDecoder();
+                if (decodeOutputStream != null) {
+                    decodeOutputStream.close();
+                }
             }
-            extractor.deinitExtractor();
-            fileInput.close();
-        } else {
-            Log.w(TAG,
-                    "Warning: Test Skipped. Cannot find " + mInputFile + " in directory "
-                            + mInputFilePath);
+            extractor.unselectExtractorTrack(currentTrack);
+            inputBuffer.clear();
+            frameInfo.clear();
         }
+        extractor.deinitExtractor();
+        fileInput.close();
+    }
+
+    @Test
+    public void testNativeDecoder() throws IOException {
+        File inputFile = new File(mInputFilePath + mInputFile);
+        assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+                inputFile.exists());
+        FileInputStream fileInput = new FileInputStream(inputFile);
+        FileDescriptor fileDescriptor = fileInput.getFD();
+        Extractor extractor = new Extractor();
+        int trackCount = extractor.setUpExtractor(fileDescriptor);
+        assertTrue("Extraction failed. No tracks for file: ", trackCount > 0);
+        for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+            extractor.selectExtractorTrack(currentTrack);
+            MediaFormat format = extractor.getFormat(currentTrack);
+            String mime = format.getString(MediaFormat.KEY_MIME);
+            ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+            for (String codecName : mediaCodecs) {
+                Log.i("Test: %s\n", mInputFile);
+                Native nativeDecoder = new Native();
+                int status = nativeDecoder.Decode(
+                        mInputFilePath, mInputFile, mStatsFile, codecName, mAsyncMode);
+                assertEquals("Decoder returned error " + status + " for file: " + mInputFile, 0,
+                        status);
+            }
+        }
+        fileInput.close();
     }
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
index 9db9c84..831467a 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
@@ -28,7 +28,10 @@
 import com.android.media.benchmark.library.Decoder;
 import com.android.media.benchmark.library.Encoder;
 import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
 
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -37,18 +40,24 @@
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.nio.ByteBuffer;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
 @RunWith(Parameterized.class)
 public class EncoderTest {
     private static final Context mContext =
             InstrumentationRegistry.getInstrumentation().getTargetContext();
     private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
     private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+    private static final String mStatsFile =
+            mContext.getExternalFilesDir(null) + "/Encoder." + System.currentTimeMillis() + ".csv";
     private static final String TAG = "EncoderTest";
     private static final long PER_TEST_TIMEOUT_MS = 120000;
     private static final boolean DEBUG = false;
@@ -56,7 +65,6 @@
     private static final int ENCODE_DEFAULT_FRAME_RATE = 25;
     private static final int ENCODE_DEFAULT_BIT_RATE = 8000000 /* 8 Mbps */;
     private static final int ENCODE_MIN_BIT_RATE = 600000 /* 600 Kbps */;
-
     private String mInputFile;
 
     @Parameterized.Parameters
@@ -81,192 +89,205 @@
         this.mInputFile = inputFileName;
     }
 
+    @BeforeClass
+    public static void writeStatsHeaderToFile() throws IOException {
+        Stats mStats = new Stats();
+        boolean status = mStats.writeStatsHeader(mStatsFile);
+        assertTrue("Unable to open stats file for writing!", status);
+        Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+    }
+
     @Test(timeout = PER_TEST_TIMEOUT_MS)
     public void sampleEncoderTest() throws Exception {
         int status;
         int frameSize;
-
         //Parameters for video
         int width = 0;
         int height = 0;
         int profile = 0;
         int level = 0;
         int frameRate = 0;
-
         //Parameters for audio
         int bitRate = 0;
         int sampleRate = 0;
         int numChannels = 0;
-
         File inputFile = new File(mInputFilePath + mInputFile);
-        if (inputFile.exists()) {
-            FileInputStream fileInput = new FileInputStream(inputFile);
-            FileDescriptor fileDescriptor = fileInput.getFD();
-            Extractor extractor = new Extractor();
-            int trackCount = extractor.setUpExtractor(fileDescriptor);
-            if (trackCount <= 0) {
-                Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
-                return;
+        assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+                inputFile.exists());
+        FileInputStream fileInput = new FileInputStream(inputFile);
+        FileDescriptor fileDescriptor = fileInput.getFD();
+        Extractor extractor = new Extractor();
+        int trackCount = extractor.setUpExtractor(fileDescriptor);
+        assertTrue("Extraction failed. No tracks for file: " + mInputFile, (trackCount > 0));
+        ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+        ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+        for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+            extractor.selectExtractorTrack(currentTrack);
+            MediaFormat format = extractor.getFormat(currentTrack);
+            // Get samples from extractor
+            int sampleSize;
+            do {
+                sampleSize = extractor.getFrameSample();
+                MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+                MediaCodec.BufferInfo info = extractor.getBufferInfo();
+                ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+                dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+                bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+                inputBuffer.add(dataBuffer);
+                frameInfo.add(bufInfo);
+                if (DEBUG) {
+                    Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
+                            bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+                }
+            } while (sampleSize > 0);
+            int tid = android.os.Process.myTid();
+            File decodedFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+            FileOutputStream decodeOutputStream = new FileOutputStream(decodedFile);
+            Decoder decoder = new Decoder();
+            decoder.setupDecoder(decodeOutputStream);
+            status = decoder.decode(inputBuffer, frameInfo, false, format, "");
+            assertEquals("Decoder returned error " + status + " for file: " + mInputFile, 0,
+                    status);
+            decoder.deInitCodec();
+            extractor.unselectExtractorTrack(currentTrack);
+            inputBuffer.clear();
+            frameInfo.clear();
+            if (decodeOutputStream != null) {
+                decodeOutputStream.close();
             }
-            ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
-            ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
-            for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
-                extractor.selectExtractorTrack(currentTrack);
-                MediaFormat format = extractor.getFormat(currentTrack);
-                // Get samples from extractor
-                int sampleSize;
-                do {
-                    sampleSize = extractor.getFrameSample();
-                    MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
-                    MediaCodec.BufferInfo info = extractor.getBufferInfo();
-                    ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
-                    dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
-                    bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
-                    inputBuffer.add(dataBuffer);
-                    frameInfo.add(bufInfo);
+            String mime = format.getString(MediaFormat.KEY_MIME);
+            ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
+            assertTrue("No suitable codecs found for file: " + mInputFile + " track : " +
+                    currentTrack + " mime: " + mime, (mediaCodecs.size() > 0));
+            Boolean[] encodeMode = {true, false};
+            /* Encoding the decoder's output */
+            for (Boolean asyncMode : encodeMode) {
+                for (String codecName : mediaCodecs) {
+                    FileOutputStream encodeOutputStream = null;
+                    if (WRITE_OUTPUT) {
+                        File outEncodeFile = new File(mOutputFilePath + "encoder.out");
+                        if (outEncodeFile.exists()) {
+                            assertTrue(" Unable to delete existing file" + outEncodeFile.toString(),
+                                    outEncodeFile.delete());
+                        }
+                        assertTrue("Unable to create file to write encoder output: " +
+                                outEncodeFile.toString(), outEncodeFile.createNewFile());
+                        encodeOutputStream = new FileOutputStream(outEncodeFile);
+                    }
+                    File rawFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+                    assertTrue("Cannot open file to write decoded output", rawFile.exists());
                     if (DEBUG) {
-                        Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
-                                bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+                        Log.i(TAG, "Path of decoded input file: " + rawFile.toString());
                     }
-                } while (sampleSize > 0);
-
-                int tid = android.os.Process.myTid();
-                File decodedFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
-                FileOutputStream decodeOutputStream = new FileOutputStream(decodedFile);
-                Decoder decoder = new Decoder();
-                decoder.setupDecoder(decodeOutputStream);
-                status = decoder.decode(inputBuffer, frameInfo, false, format, "");
-                if (status == 0) {
-                    Log.i(TAG, "Decoding complete.");
-                } else {
-                    Log.e(TAG, "Decode returned error. Encoding did not take place." + status);
-                    return;
-                }
-                decoder.deInitCodec();
-                extractor.unselectExtractorTrack(currentTrack);
-                inputBuffer.clear();
-                frameInfo.clear();
-                if (decodeOutputStream != null) {
-                    decodeOutputStream.close();
-                }
-                String mime = format.getString(MediaFormat.KEY_MIME);
-                ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
-                if (mediaCodecs.size() <= 0) {
-                    Log.e(TAG, "No suitable codecs found for file: " + mInputFile + " track : " +
-                            currentTrack + " mime: " + mime);
-                    return;
-                }
-                Boolean[] encodeMode = {true, false};
-                /* Encoding the decoder's output */
-                for (Boolean asyncMode : encodeMode) {
-                    for (String codecName : mediaCodecs) {
-                        FileOutputStream encodeOutputStream = null;
-                        if (WRITE_OUTPUT) {
-                            File outEncodeFile = new File(mOutputFilePath + "encoder.out");
-                            if (outEncodeFile.exists()) {
-                                if (!outEncodeFile.delete()) {
-                                    Log.e(TAG, "Unable to delete existing file" +
-                                            decodedFile.toString());
-                                }
-                            }
-                            if (outEncodeFile.createNewFile()) {
-                                encodeOutputStream = new FileOutputStream(outEncodeFile);
+                    FileInputStream eleStream = new FileInputStream(rawFile);
+                    if (mime.startsWith("video/")) {
+                        width = format.getInteger(MediaFormat.KEY_WIDTH);
+                        height = format.getInteger(MediaFormat.KEY_HEIGHT);
+                        if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
+                            frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+                        } else if (frameRate <= 0) {
+                            frameRate = ENCODE_DEFAULT_FRAME_RATE;
+                        }
+                        if (format.containsKey(MediaFormat.KEY_BIT_RATE)) {
+                            bitRate = format.getInteger(MediaFormat.KEY_BIT_RATE);
+                        } else if (bitRate <= 0) {
+                            if (mime.contains("video/3gpp") || mime.contains("video/mp4v-es")) {
+                                bitRate = ENCODE_MIN_BIT_RATE;
                             } else {
-                                Log.e(TAG, "Unable to create file to write encoder output: " +
-                                        outEncodeFile.toString());
+                                bitRate = ENCODE_DEFAULT_BIT_RATE;
                             }
                         }
-                        File rawFile =
-                                new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
-                        if (rawFile.exists()) {
-                            if (DEBUG) {
-                                Log.i(TAG, "Path of decoded input file: " + rawFile.toString());
-                            }
-                            FileInputStream eleStream = new FileInputStream(rawFile);
-                            if (mime.startsWith("video/")) {
-                                width = format.getInteger(MediaFormat.KEY_WIDTH);
-                                height = format.getInteger(MediaFormat.KEY_HEIGHT);
-                                if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
-                                    frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
-                                } else if (frameRate <= 0) {
-                                    frameRate = ENCODE_DEFAULT_FRAME_RATE;
-                                }
-                                if (format.containsKey(MediaFormat.KEY_BIT_RATE)) {
-                                    bitRate = format.getInteger(MediaFormat.KEY_BIT_RATE);
-                                } else if (bitRate <= 0) {
-                                    if (mime.contains("video/3gpp") ||
-                                            mime.contains("video/mp4v-es")) {
-                                        bitRate = ENCODE_MIN_BIT_RATE;
-                                    } else {
-                                        bitRate = ENCODE_DEFAULT_BIT_RATE;
-                                    }
-                                }
-                                if (format.containsKey(MediaFormat.KEY_PROFILE)) {
-                                    profile = format.getInteger(MediaFormat.KEY_PROFILE);
-                                }
-                                if (format.containsKey(MediaFormat.KEY_PROFILE)) {
-                                    level = format.getInteger(MediaFormat.KEY_LEVEL);
-                                }
-                            } else {
-                                sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
-                                numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
-                                bitRate = sampleRate * numChannels * 16;
-                            }
-                            /*Setup Encode Format*/
-                            MediaFormat encodeFormat;
-                            if (mime.startsWith("video/")) {
-                                frameSize = width * height * 3 / 2;
-                                encodeFormat = MediaFormat.createVideoFormat(mime, width, height);
-                                encodeFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
-                                encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
-                                encodeFormat.setInteger(MediaFormat.KEY_PROFILE, profile);
-                                encodeFormat.setInteger(MediaFormat.KEY_LEVEL, level);
-                                encodeFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
-                                encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, frameSize);
-                            } else {
-                                encodeFormat = MediaFormat
-                                        .createAudioFormat(mime, sampleRate, numChannels);
-                                encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
-                                frameSize = 4096;
-                            }
-                            Encoder encoder = new Encoder();
-                            encoder.setupEncoder(encodeOutputStream, eleStream);
-                            status = encoder.encode(codecName, encodeFormat, mime, frameRate,
-                                    sampleRate, frameSize, asyncMode);
-                            encoder.deInitEncoder();
-                            if (status == 0) {
-                                encoder.dumpStatistics(mInputFile + "with " + codecName + " for " +
-                                        "aSyncMode = " + asyncMode, extractor.getClipDuration());
-                                Log.i(TAG, "Encoding complete for file: " + mInputFile +
-                                        " with codec: " + codecName + " for aSyncMode = " +
-                                        asyncMode);
-                            } else {
-                                Log.e(TAG,
-                                        codecName + " encoder returned error " + status + " for " +
-                                                "file:" + " " + mInputFile);
-                            }
-                            encoder.resetEncoder();
-                            eleStream.close();
-                            if (encodeOutputStream != null) {
-                                encodeOutputStream.close();
-                            }
+                        if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+                            profile = format.getInteger(MediaFormat.KEY_PROFILE);
                         }
-                    }
-                }
-                //Cleanup temporary input file
-                if (decodedFile.exists()) {
-                    if (decodedFile.delete()) {
-                        Log.i(TAG, "Successfully deleted decoded file");
+                        if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+                            level = format.getInteger(MediaFormat.KEY_LEVEL);
+                        }
                     } else {
-                        Log.e(TAG, "Unable to delete decoded file");
+                        sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+                        numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+                        bitRate = sampleRate * numChannels * 16;
                     }
+                    /*Setup Encode Format*/
+                    MediaFormat encodeFormat;
+                    if (mime.startsWith("video/")) {
+                        frameSize = width * height * 3 / 2;
+                        encodeFormat = MediaFormat.createVideoFormat(mime, width, height);
+                        encodeFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+                        encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+                        encodeFormat.setInteger(MediaFormat.KEY_PROFILE, profile);
+                        encodeFormat.setInteger(MediaFormat.KEY_LEVEL, level);
+                        encodeFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
+                        encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, frameSize);
+                    } else {
+                        encodeFormat = MediaFormat.createAudioFormat(mime, sampleRate, numChannels);
+                        encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+                        frameSize = 4096;
+                    }
+                    Encoder encoder = new Encoder();
+                    encoder.setupEncoder(encodeOutputStream, eleStream);
+                    status = encoder.encode(codecName, encodeFormat, mime, frameRate, sampleRate,
+                            frameSize, asyncMode);
+                    encoder.deInitEncoder();
+                    assertEquals(
+                            codecName + " encoder returned error " + status + " for " + "file:" +
+                                    " " + mInputFile, 0, status);
+                    encoder.dumpStatistics(mInputFile, codecName, (asyncMode ? "async" : "sync"),
+                            extractor.getClipDuration(), mStatsFile);
+                    Log.i(TAG, "Encoding complete for file: " + mInputFile + " with codec: " +
+                            codecName + " for aSyncMode = " + asyncMode);
+                    encoder.resetEncoder();
+                    eleStream.close();
+                    if (encodeOutputStream != null) {
+                        encodeOutputStream.close();
+                    }
+
                 }
             }
-            extractor.deinitExtractor();
-            fileInput.close();
-        } else {
-            Log.w(TAG, "Warning: Test Skipped. Cannot find " + mInputFile + " in directory " +
-                    mInputFilePath);
+            //Cleanup temporary input file
+            if (decodedFile.exists()) {
+                assertTrue(" Unable to delete decoded file" + decodedFile.toString(),
+                        decodedFile.delete());
+                Log.i(TAG, "Successfully deleted decoded file");
+            }
         }
+        extractor.deinitExtractor();
+        fileInput.close();
+    }
+
+    @Test
+    public void testNativeEncoder() throws Exception {
+        File inputFile = new File(mInputFilePath + mInputFile);
+        assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
+                inputFile.exists());
+        int tid = android.os.Process.myTid();
+        final String mDecodedFile = mContext.getFilesDir() + "/decoder_" + tid + ".out";
+        FileInputStream fileInput = new FileInputStream(inputFile);
+        FileDescriptor fileDescriptor = fileInput.getFD();
+        Extractor extractor = new Extractor();
+        int trackCount = extractor.setUpExtractor(fileDescriptor);
+        assertTrue("Extraction failed. No tracks for file: ", trackCount > 0);
+        for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+            extractor.selectExtractorTrack(currentTrack);
+            MediaFormat format = extractor.getFormat(currentTrack);
+            String mime = format.getString(MediaFormat.KEY_MIME);
+            ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
+            // Encoding the decoder's output
+            for (String codecName : mediaCodecs) {
+                Native nativeEncoder = new Native();
+                int status = nativeEncoder.Encode(
+                        mInputFilePath, mInputFile, mDecodedFile, mStatsFile, codecName);
+                assertEquals(
+                        codecName + " encoder returned error " + status + " for " + "file:" + " " +
+                                mInputFile, 0, status);
+            }
+        }
+        File decodedFile = new File(mDecodedFile);
+        // Cleanup temporary input file
+        if (decodedFile.exists()) {
+            assertTrue("Unable to delete - " + mDecodedFile, decodedFile.delete());
+            Log.i(TAG, "Successfully deleted - " + mDecodedFile);
+        }
+        fileInput.close();
     }
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
index a02011c..6b7aad1 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
@@ -18,12 +18,16 @@
 
 import com.android.media.benchmark.R;
 import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
 
 import android.content.Context;
+import android.media.MediaFormat;
 import android.util.Log;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -31,19 +35,23 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
 
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import static org.junit.Assert.assertTrue;
 
 @RunWith(Parameterized.class)
 public class ExtractorTest {
     private static Context mContext =
             InstrumentationRegistry.getInstrumentation().getTargetContext();
     private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+    private static final String mStatsFile = mContext.getExternalFilesDir(null) + "/Extractor."
+            + System.currentTimeMillis() + ".csv";
     private static final String TAG = "ExtractorTest";
     private String mInputFileName;
     private int mTrackId;
@@ -71,22 +79,43 @@
         this.mTrackId = track;
     }
 
+    @BeforeClass
+    public static void writeStatsHeaderToFile() throws IOException {
+        Stats mStats = new Stats();
+        boolean status = mStats.writeStatsHeader(mStatsFile);
+        assertTrue("Unable to open stats file for writing!", status);
+        Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+    }
+
     @Test
     public void sampleExtractTest() throws IOException {
-        int status = -1;
         File inputFile = new File(mInputFilePath + mInputFileName);
-        if (inputFile.exists()) {
-            FileInputStream fileInput = new FileInputStream(inputFile);
-            FileDescriptor fileDescriptor = fileInput.getFD();
-            Extractor extractor = new Extractor();
-            extractor.setUpExtractor(fileDescriptor);
-            status = extractor.extractSample(mTrackId);
-            extractor.deinitExtractor();
-            extractor.dumpStatistics(mInputFileName);
-            fileInput.close();
-        } else {
-            Log.e(TAG, "Cannot find " + mInputFileName + " in directory " + mInputFilePath);
-        }
-        assertThat(status, is(equalTo(0)));
+        assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+                inputFile.exists());
+        FileInputStream fileInput = new FileInputStream(inputFile);
+        FileDescriptor fileDescriptor = fileInput.getFD();
+        Extractor extractor = new Extractor();
+        extractor.setUpExtractor(fileDescriptor);
+        MediaFormat format = extractor.getFormat(mTrackId);
+        String mime = format.getString(MediaFormat.KEY_MIME);
+        int status = extractor.extractSample(mTrackId);
+        assertEquals("Extraction failed for " + mInputFileName, 0, status);
+        Log.i(TAG, "Extracted " + mInputFileName + " successfully.");
+        extractor.deinitExtractor();
+        extractor.dumpStatistics(mInputFileName, mime, mStatsFile);
+        fileInput.close();
+    }
+
+    @Test
+    public void sampleExtractNativeTest() throws IOException {
+        Native nativeExtractor = new Native();
+        File inputFile = new File(mInputFilePath + mInputFileName);
+        assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+                inputFile.exists());
+        FileInputStream fileInput = new FileInputStream(inputFile);
+        int status = nativeExtractor.Extract(mInputFilePath, mInputFileName, mStatsFile);
+        fileInput.close();
+        assertEquals("Extraction failed for " + mInputFileName, 0, status);
+        Log.i(TAG, "Extracted " + mInputFileName + " successfully.");
     }
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
index 8c3080c..2efdba2 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
@@ -18,6 +18,8 @@
 import com.android.media.benchmark.R;
 import com.android.media.benchmark.library.Extractor;
 import com.android.media.benchmark.library.Muxer;
+import com.android.media.benchmark.library.Native;
+import com.android.media.benchmark.library.Stats;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -27,6 +29,7 @@
 import android.media.MediaMuxer;
 import android.util.Log;
 
+import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -34,6 +37,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -42,15 +46,19 @@
 import java.util.Hashtable;
 import java.util.Map;
 
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import static org.junit.Assert.assertTrue;
 
 @RunWith(Parameterized.class)
 public class MuxerTest {
     private static Context mContext =
             InstrumentationRegistry.getInstrumentation().getTargetContext();
     private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+    private static final String mStatsFile =
+            mContext.getExternalFilesDir(null) + "/Muxer." + System.currentTimeMillis() + ".csv";
     private static final String TAG = "MuxerTest";
     private static final Map<String, Integer> mMapFormat = new Hashtable<String, Integer>() {
         {
@@ -93,60 +101,80 @@
         this.mFormat = outputFormat;
     }
 
+    @BeforeClass
+    public static void writeStatsHeaderToFile() throws IOException {
+        Stats mStats = new Stats();
+        boolean status = mStats.writeStatsHeader(mStatsFile);
+        assertTrue("Unable to open stats file for writing!", status);
+        Log.d(TAG, "Saving Benchmark results in: " + mStatsFile);
+    }
+
     @Test
     public void sampleMuxerTest() throws IOException {
-        int status = -1;
         File inputFile = new File(mInputFilePath + mInputFileName);
-        if (inputFile.exists()) {
-            FileInputStream fileInput = new FileInputStream(inputFile);
-            FileDescriptor fileDescriptor = fileInput.getFD();
-            ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
-            ArrayList<MediaCodec.BufferInfo> inputBufferInfo = new ArrayList<>();
-            Extractor extractor = new Extractor();
-            int trackCount = extractor.setUpExtractor(fileDescriptor);
-            for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
-                extractor.selectExtractorTrack(currentTrack);
-                while (true) {
-                    int sampleSize = extractor.getFrameSample();
-                    MediaCodec.BufferInfo bufferInfo = extractor.getBufferInfo();
-                    MediaCodec.BufferInfo tempBufferInfo = new MediaCodec.BufferInfo();
-                    tempBufferInfo
-                            .set(bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs,
-                                    bufferInfo.flags);
-                    inputBufferInfo.add(tempBufferInfo);
-                    ByteBuffer tempSampleBuffer = ByteBuffer.allocate(tempBufferInfo.size);
-                    tempSampleBuffer.put(extractor.getFrameBuffer().array(), 0, bufferInfo.size);
-                    inputBuffer.add(tempSampleBuffer);
-                    if (sampleSize < 0) {
-                        break;
-                    }
-                }
-                MediaFormat format = extractor.getFormat(currentTrack);
-                int outputFormat = mMapFormat.getOrDefault(mFormat, -1);
-                if (outputFormat != -1) {
-                    Muxer muxer = new Muxer();
-                    int trackIndex = muxer.setUpMuxer(mContext, outputFormat, format);
-                    status = muxer.mux(trackIndex, inputBuffer, inputBufferInfo);
-                    if (status != 0) {
-                        Log.e(TAG, "Cannot perform write operation for " + mInputFileName);
-                    }
-                    muxer.deInitMuxer();
-                    muxer.dumpStatistics(mInputFileName, extractor.getClipDuration());
-                    muxer.resetMuxer();
-                    extractor.unselectExtractorTrack(currentTrack);
-                    inputBufferInfo.clear();
-                    inputBuffer.clear();
-                } else {
-                    Log.e(TAG, "Test failed for " + mInputFileName + ". Returned invalid " +
-                            "output format for given " + mFormat + " format.");
+        assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+                inputFile.exists());
+        FileInputStream fileInput = new FileInputStream(inputFile);
+        FileDescriptor fileDescriptor = fileInput.getFD();
+        ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+        ArrayList<MediaCodec.BufferInfo> inputBufferInfo = new ArrayList<>();
+        Extractor extractor = new Extractor();
+        int trackCount = extractor.setUpExtractor(fileDescriptor);
+        for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+            extractor.selectExtractorTrack(currentTrack);
+            while (true) {
+                int sampleSize = extractor.getFrameSample();
+                MediaCodec.BufferInfo bufferInfo = extractor.getBufferInfo();
+                MediaCodec.BufferInfo tempBufferInfo = new MediaCodec.BufferInfo();
+                tempBufferInfo
+                        .set(bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs,
+                                bufferInfo.flags);
+                inputBufferInfo.add(tempBufferInfo);
+                ByteBuffer tempSampleBuffer = ByteBuffer.allocate(tempBufferInfo.size);
+                tempSampleBuffer.put(extractor.getFrameBuffer().array(), 0, bufferInfo.size);
+                inputBuffer.add(tempSampleBuffer);
+                if (sampleSize < 0) {
+                    break;
                 }
             }
-            extractor.deinitExtractor();
-            fileInput.close();
-        } else {
-            Log.w(TAG, "Warning: Test Skipped. Cannot find " + mInputFileName + " in directory " +
-                    mInputFilePath);
+            MediaFormat format = extractor.getFormat(currentTrack);
+            int outputFormat = mMapFormat.getOrDefault(mFormat, -1);
+            assertNotEquals("Test failed for " + mInputFileName + ". Returned invalid " +
+                    "output format for given " + mFormat + " format.", -1, outputFormat);
+            Muxer muxer = new Muxer();
+            int trackIndex = muxer.setUpMuxer(mContext, outputFormat, format);
+            int status = muxer.mux(trackIndex, inputBuffer, inputBufferInfo);
+            assertEquals("Cannot perform write operation for " + mInputFileName, 0, status);
+            Log.i(TAG, "Muxed " + mInputFileName + " successfully.");
+            muxer.deInitMuxer();
+            muxer.dumpStatistics(mInputFileName, mFormat, extractor.getClipDuration(), mStatsFile);
+            muxer.resetMuxer();
+            extractor.unselectExtractorTrack(currentTrack);
+            inputBufferInfo.clear();
+            inputBuffer.clear();
+
         }
-        assertThat(status, is(equalTo(0)));
+        extractor.deinitExtractor();
+        fileInput.close();
+    }
+
+    @Test
+    public void sampleMuxerNativeTest() {
+        Native nativeMuxer = new Native();
+        File inputFile = new File(mInputFilePath + mInputFileName);
+        assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath,
+                inputFile.exists());
+        int tid = android.os.Process.myTid();
+        String mMuxOutputFile = (mContext.getFilesDir() + "/mux_" + tid + ".out");
+        int status = nativeMuxer.Mux(
+                mInputFilePath, mInputFileName, mMuxOutputFile, mStatsFile, mFormat);
+        assertEquals("Cannot perform write operation for " + mInputFileName, 0, status);
+        Log.i(TAG, "Muxed " + mInputFileName + " successfully.");
+        File muxedFile = new File(mMuxOutputFile);
+        // Cleanup temporary output file
+        if (muxedFile.exists()) {
+            assertTrue("Unable to delete" + mMuxOutputFile + " file.",
+                    muxedFile.delete());
+        }
     }
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp
new file mode 100644
index 0000000..c72eb55
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp
@@ -0,0 +1,32 @@
+cc_test_library {
+    name: "libmediabenchmark_jni",
+
+    defaults: [
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
+    ],
+
+    srcs: [
+        "NativeExtractor.cpp",
+        "NativeMuxer.cpp",
+        "NativeEncoder.cpp",
+        "NativeDecoder.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    static_libs: [
+        "libmediabenchmark_common",
+        "libmediabenchmark_extractor",
+        "libmediabenchmark_muxer",
+        "libmediabenchmark_decoder",
+        "libmediabenchmark_encoder",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/CMakeLists.txt b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000..5823883
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,44 @@
+#
+# Copyright (C) 2019 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.
+#
+
+cmake_minimum_required(VERSION 3.4.1)
+
+set(native_source_path "../../../../src/native")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror")
+
+add_library(
+  mediabenchmark_jni SHARED
+  NativeExtractor.cpp
+  NativeMuxer.cpp
+  NativeDecoder.cpp
+  NativeEncoder.cpp
+  ${native_source_path}/common/BenchmarkCommon.cpp
+  ${native_source_path}/common/Stats.cpp
+  ${native_source_path}/common/utils/Timers.cpp
+  ${native_source_path}/extractor/Extractor.cpp
+  ${native_source_path}/muxer/Muxer.cpp
+  ${native_source_path}/decoder/Decoder.cpp
+  ${native_source_path}/encoder/Encoder.cpp)
+
+include_directories(${native_source_path}/common)
+include_directories(${native_source_path}/extractor)
+include_directories(${native_source_path}/muxer)
+include_directories(${native_source_path}/decoder)
+include_directories(${native_source_path}/encoder)
+
+find_library(log-lib log)
+
+target_link_libraries(mediabenchmark_jni mediandk ${log-lib})
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeDecoder.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeDecoder.cpp
new file mode 100644
index 0000000..043bc9e
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeDecoder.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeDecoder"
+
+#include <jni.h>
+#include <fstream>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <android/log.h>
+
+#include "Decoder.h"
+
+extern "C" JNIEXPORT int JNICALL Java_com_android_media_benchmark_library_Native_Decode(
+        JNIEnv *env, jobject thiz, jstring jFilePath, jstring jFileName, jstring jStatsFile,
+        jstring jCodecName, jboolean asyncMode) {
+    const char *filePath = env->GetStringUTFChars(jFilePath, nullptr);
+    const char *fileName = env->GetStringUTFChars(jFileName, nullptr);
+    string sFilePath = string(filePath) + string(fileName);
+    UNUSED(thiz);
+    FILE *inputFp = fopen(sFilePath.c_str(), "rb");
+    env->ReleaseStringUTFChars(jFileName, fileName);
+    env->ReleaseStringUTFChars(jFilePath, filePath);
+    if (!inputFp) {
+        ALOGE("Unable to open input file for reading");
+        return -1;
+    }
+
+    Decoder *decoder = new Decoder();
+    Extractor *extractor = decoder->getExtractor();
+    if (!extractor) {
+        ALOGE("Extractor creation failed");
+        return -1;
+    }
+
+    // Read file properties
+    struct stat buf;
+    stat(sFilePath.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    if (fileSize > kMaxBufferSize) {
+        ALOGE("File size greater than maximum buffer size");
+        return -1;
+    }
+    int32_t fd = fileno(inputFp);
+    int32_t trackCount = extractor->initExtractor(fd, fileSize);
+    if (trackCount <= 0) {
+        ALOGE("initExtractor failed");
+        return -1;
+    }
+    for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+        int32_t status = extractor->setupTrackFormat(curTrack);
+        if (status != 0) {
+            ALOGE("Track Format invalid");
+            return -1;
+        }
+
+        uint8_t *inputBuffer = (uint8_t *) malloc(fileSize);
+        if (!inputBuffer) {
+            ALOGE("Insufficient memory");
+            return -1;
+        }
+
+        vector<AMediaCodecBufferInfo> frameInfo;
+        AMediaCodecBufferInfo info;
+        uint32_t inputBufferOffset = 0;
+
+        // Get frame data
+        while (1) {
+            status = extractor->getFrameSample(info);
+            if (status || !info.size) break;
+            // copy the meta data and buffer to be passed to decoder
+            if (inputBufferOffset + info.size > kMaxBufferSize) {
+                ALOGE("Memory allocated not sufficient");
+                free(inputBuffer);
+                return -1;
+            }
+            memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+            frameInfo.push_back(info);
+            inputBufferOffset += info.size;
+        }
+
+        const char *codecName = env->GetStringUTFChars(jCodecName, nullptr);
+        string sCodecName = string(codecName);
+        decoder->setupDecoder();
+        status = decoder->decode(inputBuffer, frameInfo, sCodecName, asyncMode);
+        if (status != AMEDIA_OK) {
+            ALOGE("Decode returned error");
+            free(inputBuffer);
+            env->ReleaseStringUTFChars(jCodecName, codecName);
+            return -1;
+        }
+        decoder->deInitCodec();
+        const char *inputReference = env->GetStringUTFChars(jFileName, nullptr);
+        const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+        string sInputReference = string(inputReference);
+        decoder->dumpStatistics(sInputReference, sCodecName, (asyncMode ? "async" : "sync"),
+                                statsFile);
+        env->ReleaseStringUTFChars(jCodecName, codecName);
+        env->ReleaseStringUTFChars(jStatsFile, statsFile);
+        env->ReleaseStringUTFChars(jFileName, inputReference);
+        if (inputBuffer) {
+            free(inputBuffer);
+            inputBuffer = nullptr;
+        }
+        decoder->resetDecoder();
+    }
+    if (inputFp) {
+        fclose(inputFp);
+        inputFp = nullptr;
+    }
+    extractor->deInitExtractor();
+    delete decoder;
+    return 0;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeEncoder.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeEncoder.cpp
new file mode 100644
index 0000000..271b852
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeEncoder.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeEncoder"
+
+#include <jni.h>
+#include <fstream>
+#include <iostream>
+#include <sys/stat.h>
+
+#include <android/log.h>
+
+#include "Decoder.h"
+#include "Encoder.h"
+
+#include <stdio.h>
+
+extern "C" JNIEXPORT int JNICALL Java_com_android_media_benchmark_library_Native_Encode(
+        JNIEnv *env, jobject thiz, jstring jFilePath, jstring jFileName, jstring jOutFilePath,
+        jstring jStatsFile, jstring jCodecName) {
+    const char *filePath = env->GetStringUTFChars(jFilePath, nullptr);
+    const char *fileName = env->GetStringUTFChars(jFileName, nullptr);
+    string sFilePath = string(filePath) + string(fileName);
+    UNUSED(thiz);
+    FILE *inputFp = fopen(sFilePath.c_str(), "rb");
+    env->ReleaseStringUTFChars(jFileName, fileName);
+    env->ReleaseStringUTFChars(jFilePath, filePath);
+    if (!inputFp) {
+        ALOGE("Unable to open input file for reading");
+        return -1;
+    }
+
+    Decoder *decoder = new Decoder();
+    Extractor *extractor = decoder->getExtractor();
+    if (!extractor) {
+        ALOGE("Extractor creation failed");
+        return -1;
+    }
+
+    // Read file properties
+    struct stat buf;
+    stat(sFilePath.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    if (fileSize > kMaxBufferSize) {
+        ALOGE("File size greater than maximum buffer size");
+        return -1;
+    }
+    int32_t fd = fileno(inputFp);
+    int32_t trackCount = extractor->initExtractor(fd, fileSize);
+    if (trackCount <= 0) {
+        ALOGE("initExtractor failed");
+        return -1;
+    }
+
+    for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+        int32_t status = extractor->setupTrackFormat(curTrack);
+        if (status != 0) {
+            ALOGE("Track Format invalid");
+            return -1;
+        }
+        uint8_t *inputBuffer = (uint8_t *) malloc(fileSize);
+        if (!inputBuffer) {
+            ALOGE("Insufficient memory");
+            return -1;
+        }
+        vector<AMediaCodecBufferInfo> frameInfo;
+        AMediaCodecBufferInfo info;
+        uint32_t inputBufferOffset = 0;
+
+        // Get frame data
+        while (1) {
+            status = extractor->getFrameSample(info);
+            if (status || !info.size) break;
+            // copy the meta data and buffer to be passed to decoder
+            if (inputBufferOffset + info.size > kMaxBufferSize) {
+                ALOGE("Memory allocated not sufficient");
+                free(inputBuffer);
+                return -1;
+            }
+            memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+            frameInfo.push_back(info);
+            inputBufferOffset += info.size;
+        }
+        string decName = "";
+        const char *outputFilePath = env->GetStringUTFChars(jOutFilePath, nullptr);
+        FILE *outFp = fopen(outputFilePath, "wb");
+        if (outFp == nullptr) {
+            ALOGE("%s - File failed to open for writing!", outputFilePath);
+            free(inputBuffer);
+            return -1;
+        }
+        decoder->setupDecoder();
+        status = decoder->decode(inputBuffer, frameInfo, decName, false /*asyncMode */, outFp);
+        if (status != AMEDIA_OK) {
+            ALOGE("Decode returned error");
+            free(inputBuffer);
+            return -1;
+        }
+        AMediaFormat *format = extractor->getFormat();
+        if (inputBuffer) {
+            free(inputBuffer);
+            inputBuffer = nullptr;
+        }
+        const char *mime = nullptr;
+        AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+        if (!mime) {
+            ALOGE("Error in AMediaFormat_getString");
+            return -1;
+        }
+        ifstream eleStream;
+        eleStream.open(outputFilePath, ifstream::binary | ifstream::ate);
+        if (!eleStream.is_open()) {
+            ALOGE("%s - File failed to open for reading!", outputFilePath);
+            env->ReleaseStringUTFChars(jOutFilePath, outputFilePath);
+            return -1;
+        }
+        const char *codecName = env->GetStringUTFChars(jCodecName, NULL);
+        const char *inputReference = env->GetStringUTFChars(jFileName, nullptr);
+        string sCodecName = string(codecName);
+        string sInputReference = string(inputReference);
+
+        bool asyncMode[2] = {true, false};
+        for (int i = 0; i < 2; i++) {
+            size_t eleSize = eleStream.tellg();
+            eleStream.seekg(0, ifstream::beg);
+
+            // Get encoder params
+            encParameter encParams;
+            if (!strncmp(mime, "video/", 6)) {
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &encParams.width);
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &encParams.height);
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &encParams.frameRate);
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &encParams.bitrate);
+                if (encParams.bitrate <= 0 || encParams.frameRate <= 0) {
+                    encParams.frameRate = 25;
+                    if (!strcmp(mime, "video/3gpp") || !strcmp(mime, "video/mp4v-es")) {
+                        encParams.bitrate = 600000 /* 600 Kbps */;
+                    } else {
+                        encParams.bitrate = 8000000 /* 8 Mbps */;
+                    }
+                }
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_PROFILE, &encParams.profile);
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_LEVEL, &encParams.level);
+            } else {
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &encParams.sampleRate);
+                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+                                      &encParams.numChannels);
+                encParams.bitrate =
+                        encParams.sampleRate * encParams.numChannels * 16 /* bitsPerSample */;
+            }
+            Encoder *encoder = new Encoder();
+            encoder->setupEncoder();
+            status = encoder->encode(sCodecName, eleStream, eleSize, asyncMode[i], encParams,
+                                     (char *) mime);
+            encoder->deInitCodec();
+            cout << "codec : " << codecName << endl;
+            ALOGV(" asyncMode = %d \n", asyncMode[i]);
+            const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+            encoder->dumpStatistics(sInputReference, extractor->getClipDuration(), sCodecName,
+                                    (asyncMode[i] ? "async" : "sync"), statsFile);
+            env->ReleaseStringUTFChars(jStatsFile, statsFile);
+            encoder->resetEncoder();
+            delete encoder;
+            encoder = nullptr;
+        }
+        eleStream.close();
+        if (outFp) {
+            fclose(outFp);
+            outFp = nullptr;
+        }
+        env->ReleaseStringUTFChars(jFileName, inputReference);
+        env->ReleaseStringUTFChars(jCodecName, codecName);
+        env->ReleaseStringUTFChars(jOutFilePath, outputFilePath);
+        if (format) {
+            AMediaFormat_delete(format);
+            format = nullptr;
+        }
+        decoder->deInitCodec();
+        decoder->resetDecoder();
+    }
+    if (inputFp) {
+        fclose(inputFp);
+        inputFp = nullptr;
+    }
+    extractor->deInitExtractor();
+    delete decoder;
+    return 0;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeExtractor.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeExtractor.cpp
new file mode 100644
index 0000000..a762760
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeExtractor.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeExtractor"
+
+#include <jni.h>
+#include <fstream>
+#include <string>
+#include <sys/stat.h>
+
+#include "Extractor.h"
+
+extern "C" JNIEXPORT int32_t JNICALL Java_com_android_media_benchmark_library_Native_Extract(
+        JNIEnv *env, jobject thiz, jstring jInputFilePath, jstring jInputFileName,
+        jstring jStatsFile) {
+    UNUSED(thiz);
+    const char *inputFilePath = env->GetStringUTFChars(jInputFilePath, nullptr);
+    const char *inputFileName = env->GetStringUTFChars(jInputFileName, nullptr);
+    string sFilePath = string(inputFilePath) + string(inputFileName);
+    FILE *inputFp = fopen(sFilePath.c_str(), "rb");
+
+    // Read file properties
+    struct stat buf;
+    stat(sFilePath.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    int32_t fd = fileno(inputFp);
+
+    Extractor *extractObj = new Extractor();
+    int32_t trackCount = extractObj->initExtractor((long) fd, fileSize);
+    if (trackCount <= 0) {
+        ALOGE("initExtractor failed");
+        return -1;
+    }
+
+    int32_t trackID = 0;
+    const char *mime = nullptr;
+    int32_t status = extractObj->extract(trackID);
+    if (status != AMEDIA_OK) {
+        ALOGE("Extraction failed");
+        return -1;
+    }
+
+    if (inputFp) {
+        fclose(inputFp);
+        inputFp = nullptr;
+    }
+    status = extractObj->setupTrackFormat(trackID);
+    AMediaFormat *format = extractObj->getFormat();
+    if (!format) {
+        ALOGE("format is null!");
+        return -1;
+    }
+    AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+    if (!mime) {
+        ALOGE("mime is null!");
+        return -1;
+    }
+    extractObj->deInitExtractor();
+    const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+    extractObj->dumpStatistics(string(inputFileName), string(mime), statsFile);
+    env->ReleaseStringUTFChars(jStatsFile, statsFile);
+    env->ReleaseStringUTFChars(jInputFilePath, inputFilePath);
+    env->ReleaseStringUTFChars(jInputFileName, inputFileName);
+
+    delete extractObj;
+    return status;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeMuxer.cpp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeMuxer.cpp
new file mode 100644
index 0000000..a5ef5b8
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/NativeMuxer.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeMuxer"
+
+#include <jni.h>
+#include <fstream>
+#include <string>
+#include <sys/stat.h>
+
+#include "Muxer.h"
+
+MUXER_OUTPUT_T getMuxerOutFormat(const char *fmt);
+
+extern "C" JNIEXPORT int32_t JNICALL Java_com_android_media_benchmark_library_Native_Mux(
+        JNIEnv *env, jobject thiz, jstring jInputFilePath, jstring jInputFileName,
+        jstring jOutputFilePath, jstring jStatsFile, jstring jFormat) {
+    UNUSED(thiz);
+    ALOGV("Mux the samples given by extractor");
+    const char *inputFilePath = env->GetStringUTFChars(jInputFilePath, nullptr);
+    const char *inputFileName = env->GetStringUTFChars(jInputFileName, nullptr);
+    string sInputFile = string(inputFilePath) + string(inputFileName);
+    FILE *inputFp = fopen(sInputFile.c_str(), "rb");
+    if (!inputFp) {
+        ALOGE("Unable to open input file for reading");
+        return -1;
+    }
+
+    const char *fmt = env->GetStringUTFChars(jFormat, nullptr);
+    MUXER_OUTPUT_T outputFormat = getMuxerOutFormat(fmt);
+    if (outputFormat == MUXER_OUTPUT_FORMAT_INVALID) {
+        ALOGE("output format is MUXER_OUTPUT_FORMAT_INVALID");
+        return MUXER_OUTPUT_FORMAT_INVALID;
+    }
+
+    Muxer *muxerObj = new Muxer();
+    Extractor *extractor = muxerObj->getExtractor();
+    if (!extractor) {
+        ALOGE("Extractor creation failed");
+        return -1;
+    }
+
+    // Read file properties
+    struct stat buf;
+    stat(sInputFile.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    int32_t fd = fileno(inputFp);
+
+    int32_t trackCount = extractor->initExtractor(fd, fileSize);
+    if (trackCount <= 0) {
+        ALOGE("initExtractor failed");
+        return -1;
+    }
+
+    for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+        int32_t status = extractor->setupTrackFormat(curTrack);
+        if (status != 0) {
+            ALOGE("Track Format invalid");
+            return -1;
+        }
+
+        uint8_t *inputBuffer = (uint8_t *) malloc(fileSize);
+        if (!inputBuffer) {
+            ALOGE("Allocation Failed");
+            return -1;
+        }
+        vector<AMediaCodecBufferInfo> frameInfos;
+        AMediaCodecBufferInfo info;
+        uint32_t inputBufferOffset = 0;
+
+        // Get Frame Data
+        while (1) {
+            status = extractor->getFrameSample(info);
+            if (status || !info.size) break;
+            // copy the meta data and buffer to be passed to muxer
+            if (inputBufferOffset + info.size > fileSize) {
+                ALOGE("Memory allocated not sufficient");
+                if (inputBuffer) {
+                    free(inputBuffer);
+                    inputBuffer = nullptr;
+                }
+                return -1;
+            }
+            memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(),
+                   static_cast<size_t>(info.size));
+            info.offset = inputBufferOffset;
+            frameInfos.push_back(info);
+            inputBufferOffset += info.size;
+        }
+
+        const char *outputFilePath = env->GetStringUTFChars(jOutputFilePath, nullptr);
+        FILE *outputFp = fopen(((string) outputFilePath).c_str(), "w+b");
+        env->ReleaseStringUTFChars(jOutputFilePath, outputFilePath);
+
+        if (!outputFp) {
+            ALOGE("Unable to open output file for writing");
+            if (inputBuffer) {
+                free(inputBuffer);
+                inputBuffer = nullptr;
+            }
+            return -1;
+        }
+        int32_t outFd = fileno(outputFp);
+
+        status = muxerObj->initMuxer(outFd, (MUXER_OUTPUT_T) outputFormat);
+        if (status != 0) {
+            ALOGE("initMuxer failed");
+            if (inputBuffer) {
+                free(inputBuffer);
+                inputBuffer = nullptr;
+            }
+            return -1;
+        }
+
+        status = muxerObj->mux(inputBuffer, frameInfos);
+        if (status != 0) {
+            ALOGE("Mux failed");
+            if (inputBuffer) {
+                free(inputBuffer);
+                inputBuffer = nullptr;
+            }
+            return -1;
+        }
+        muxerObj->deInitMuxer();
+        const char *statsFile = env->GetStringUTFChars(jStatsFile, nullptr);
+        string muxFormat(fmt);
+        muxerObj->dumpStatistics(string(inputFileName), muxFormat, statsFile);
+        env->ReleaseStringUTFChars(jStatsFile, statsFile);
+        env->ReleaseStringUTFChars(jInputFilePath, inputFilePath);
+        env->ReleaseStringUTFChars(jInputFileName, inputFileName);
+
+        if (inputBuffer) {
+            free(inputBuffer);
+            inputBuffer = nullptr;
+        }
+        if (outputFp) {
+            fclose(outputFp);
+            outputFp = nullptr;
+        }
+        muxerObj->resetMuxer();
+    }
+    if (inputFp) {
+        fclose(inputFp);
+        inputFp = nullptr;
+    }
+    env->ReleaseStringUTFChars(jFormat, fmt);
+    extractor->deInitExtractor();
+    delete muxerObj;
+
+    return 0;
+}
+
+MUXER_OUTPUT_T getMuxerOutFormat(const char *fmt) {
+    static const struct {
+        const char *name;
+        int value;
+    } kFormatMaps[] = {{"mp4",  MUXER_OUTPUT_FORMAT_MPEG_4},
+                       {"webm", MUXER_OUTPUT_FORMAT_WEBM},
+                       {"3gpp", MUXER_OUTPUT_FORMAT_3GPP},
+                       {"ogg",  MUXER_OUTPUT_FORMAT_OGG}};
+
+    int32_t muxOutputFormat = MUXER_OUTPUT_FORMAT_INVALID;
+    for (auto kFormatMap : kFormatMaps) {
+        if (!strcmp(fmt, kFormatMap.name)) {
+            muxOutputFormat = kFormatMap.value;
+            break;
+        }
+    }
+    return (MUXER_OUTPUT_T) muxOutputFormat;
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
index 2cd27c2..3b1eed4 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -239,11 +239,16 @@
      * Prints out the statistics in the information log
      *
      * @param inputReference The operation being performed, in this case decode
+     * @param componentName  Name of the component/codec
+     * @param mode           The operating mode: Sync/Async
      * @param durationUs     Duration of the clip in microseconds
+     * @param statsFile      The output file where the stats data is written
      */
-    public void dumpStatistics(String inputReference, long durationUs) {
+    public void dumpStatistics(String inputReference, String componentName, String mode,
+            long durationUs, String statsFile) throws IOException {
         String operation = "decode";
-        mStats.dumpStatistics(operation, inputReference, durationUs);
+        mStats.dumpStatistics(
+                inputReference, operation, componentName, mode, durationUs, statsFile);
     }
 
     /**
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
index 03db294..40cf8bd 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -326,12 +326,17 @@
     /**
      * Prints out the statistics in the information log
      *
-     * @param inputReference The operation being performed, in this case encode
+     * @param inputReference The operation being performed, in this case decode
+     * @param componentName  Name of the component/codec
+     * @param mode           The operating mode: Sync/Async
      * @param durationUs     Duration of the clip in microseconds
+     * @param statsFile      The output file where the stats data is written
      */
-    public void dumpStatistics(String inputReference, long durationUs) {
+    public void dumpStatistics(String inputReference, String componentName, String mode,
+                               long durationUs, String statsFile) throws IOException {
         String operation = "encode";
-        mStats.dumpStatistics(operation, inputReference, durationUs);
+        mStats.dumpStatistics(
+                inputReference, operation, componentName, mode, durationUs, statsFile);
     }
 
     /**
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
index 459e2a9..f3024e7 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
@@ -167,9 +167,12 @@
      * Write the benchmark logs for the given input file
      *
      * @param inputReference Name of the input file
+     * @param mimeType       Mime type of the muxed file
+     * @param statsFile      The output file where the stats data is written
      */
-    public void dumpStatistics(String inputReference) {
+    public void dumpStatistics(String inputReference, String mimeType, String statsFile)
+            throws IOException {
         String operation = "extract";
-        mStats.dumpStatistics(operation, inputReference, mDurationUs);
+        mStats.dumpStatistics(inputReference, operation, mimeType, "", mDurationUs, statsFile);
     }
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
index 49eaa1c..340b539 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
@@ -101,10 +101,13 @@
      * Write the benchmark logs for the given input file
      *
      * @param inputReference Name of the input file
+     * @param muxFormat      Format of the muxed output
      * @param clipDuration   Duration of the given inputReference file
+     * @param statsFile      The output file where the stats data is written
      */
-    public void dumpStatistics(String inputReference, long clipDuration) {
+    public void dumpStatistics(String inputReference, String muxFormat, long clipDuration,
+                               String statsFile) throws IOException {
         String operation = "mux";
-        mStats.dumpStatistics(operation, inputReference, clipDuration);
+        mStats.dumpStatistics(inputReference, operation, muxFormat, "", clipDuration, statsFile);
     }
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Native.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Native.java
new file mode 100644
index 0000000..38b608a
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Native.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 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 com.android.media.benchmark.library;
+
+public class Native {
+    static { System.loadLibrary("mediabenchmark_jni"); }
+
+    public native int Extract(String inputFilePath, String inputFileName, String statsFile);
+
+    public native int Mux(String inputFilePath, String inputFileName, String outputFilePath,
+            String statsFile, String format);
+
+    public native int Decode(String inputFilePath, String inputFileName, String statsFile,
+            String codecName, boolean asyncMode);
+
+    public native int Encode(String inputFilePath, String inputFileName, String outputFilePath,
+            String statsFile, String codecName);
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
index 18ab5be..7245a3a 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
@@ -18,6 +18,10 @@
 
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 
 /**
@@ -91,14 +95,38 @@
     }
 
     /**
+     * Writes the stats header to a file
+     * <p>
+     * \param statsFile    file where the stats data is to be written
+     **/
+    public boolean writeStatsHeader(String statsFile) throws IOException {
+        File outputFile = new File(statsFile);
+        FileOutputStream out = new FileOutputStream(outputFile, true);
+        if (!outputFile.exists())
+            return false;
+        String statsHeader =
+                "currentTime, fileName, operation, componentName, NDK/SDK, sync/async, setupTime, "
+                        + "destroyTime, minimumTime, maximumTime, "
+                        + "averageTime, timeToProcess1SecContent, totalBytesProcessedPerSec, "
+                        + "timeToFirstFrame, totalSizeInBytes, totalTime\n";
+        out.write(statsHeader.getBytes());
+        out.close();
+        return true;
+    }
+
+    /**
      * Dumps the stats of the operation for a given input media.
      * <p>
+     * \param inputReference input media
      * \param operation      describes the operation performed on the input media
      * (i.e. extract/mux/decode/encode)
-     * \param inputReference input media
-     * \param durationUs    is a duration of the input media in microseconds.
+     * \param componentName  name of the codec/muxFormat/mime
+     * \param mode           the operating mode: sync/async.
+     * \param durationUs     is a duration of the input media in microseconds.
+     * \param statsFile      the file where the stats data is to be written.
      */
-    public void dumpStatistics(String operation, String inputReference, long durationUs) {
+    public void dumpStatistics(String inputReference, String operation, String componentName,
+            String mode, long durationUs, String statsFile) throws IOException {
         if (mOutputTimer.size() == 0) {
             Log.e(TAG, "No output produced");
             return;
@@ -121,18 +149,30 @@
                 maxTimeTakenNs = intervalNs;
             }
         }
-        // Print the Stats
-        Log.i(TAG, "Input Reference : " + inputReference);
-        Log.i(TAG, "Setup Time in nano sec : " + mInitTimeNs);
-        Log.i(TAG, "Average Time in nano sec : " + totalTimeTakenNs / mOutputTimer.size());
-        Log.i(TAG, "Time to first frame in nano sec : " + timeToFirstFrameNs);
-        Log.i(TAG, "Time taken (in nano sec) to " + operation + " 1 sec of content : " +
-                timeTakenPerSec);
-        Log.i(TAG, "Total bytes " + operation + "ed : " + size);
-        Log.i(TAG, "Number of bytes " + operation + "ed per second : " +
-                (size * 1000000000) / totalTimeTakenNs);
-        Log.i(TAG, "Minimum Time in nano sec : " + minTimeTakenNs);
-        Log.i(TAG, "Maximum Time in nano sec : " + maxTimeTakenNs);
-        Log.i(TAG, "Destroy Time in nano sec : " + mDeInitTimeNs);
+
+        // Write the stats row data to file
+        String rowData = "";
+        rowData += System.nanoTime() + ", ";
+        rowData += inputReference + ", ";
+        rowData += operation + ", ";
+        rowData += componentName + ", ";
+        rowData += "SDK, ";
+        rowData += mode + ", ";
+        rowData += mInitTimeNs + ", ";
+        rowData += mDeInitTimeNs + ", ";
+        rowData += minTimeTakenNs + ", ";
+        rowData += maxTimeTakenNs + ", ";
+        rowData += totalTimeTakenNs / mOutputTimer.size() + ", ";
+        rowData += timeTakenPerSec + ", ";
+        rowData += (size * 1000000000) / totalTimeTakenNs + ", ";
+        rowData += timeToFirstFrameNs + ", ";
+        rowData += size + ", ";
+        rowData += totalTimeTakenNs + "\n";
+
+        File outputFile = new File(statsFile);
+        FileOutputStream out = new FileOutputStream(outputFile, true);
+        assert outputFile.exists() : "Failed to open the stats file for writing!";
+        out.write(rowData.getBytes());
+        out.close();
     }
-}
\ No newline at end of file
+}
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 6627462..05fbe6f 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -145,3 +145,12 @@
 ```
 adb shell /data/local/tmp/C2DecoderTest -P /data/local/tmp/MediaBenchmark/res/
 ```
+## C2 Encoder
+
+The test encodes input stream and benchmarks the codec2 encoders available in device.
+
+Setup steps are same as [extractor](#extractor).
+
+```
+adb shell /data/local/tmp/C2EncoderTest -P /data/local/tmp/MediaBenchmark/res/
+```
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index babc329..f8ea25c 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -29,7 +29,7 @@
 
     export_include_dirs: ["."],
 
-    ldflags: ["-Wl,-Bsymbolic"]
+    ldflags: ["-Wl,-Bsymbolic"],
 }
 
 cc_defaults {
@@ -55,7 +55,7 @@
     cflags: [
         "-Wall",
         "-Werror",
-    ]
+    ],
 }
 
 cc_library_static {
@@ -66,18 +66,20 @@
 
     srcs: [
         "BenchmarkC2Common.cpp",
+        "BenchmarkCommon.cpp",
+        "Stats.cpp",
+        "utils/Timers.cpp",
     ],
 
     export_include_dirs: ["."],
 
-    ldflags: ["-Wl,-Bsymbolic"]
+    ldflags: ["-Wl,-Bsymbolic"],
 }
 
 cc_defaults {
     name: "libmediabenchmark_codec2_common-defaults",
 
     defaults: [
-        "libmediabenchmark_common-defaults",
         "libcodec2-hidl-client-defaults",
         "libmediabenchmark_soft_sanitize_all-defaults",
     ],
@@ -88,7 +90,14 @@
 
     shared_libs: [
         "libcodec2_client",
-    ]
+        "libmediandk",
+        "liblog",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
 }
 
 // public dependency for native implementation
@@ -102,5 +111,5 @@
             "signed-integer-overflow",
         ],
         cfi: true,
-    }
+    },
 }
diff --git a/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp b/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp
index 622a0e1..e09f468 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp
+++ b/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp
@@ -22,6 +22,9 @@
 int32_t BenchmarkC2Common::setupCodec2() {
     ALOGV("In %s", __func__);
     mClient = android::Codec2Client::CreateFromService("default");
+    if (!mClient) {
+        mClient = android::Codec2Client::CreateFromService("software");
+    }
     if (!mClient) return -1;
 
     std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
index ab74508..cb49b8e 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
@@ -56,6 +56,7 @@
 
 void OnErrorCB(AMediaCodec *codec, void *userdata, media_status_t err, int32_t actionCode,
                const char *detail) {
+    (void)codec;
     ALOGE("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
     CallBackHandle *self = (CallBackHandle *)userdata;
     self->mSawError = true;
@@ -91,7 +92,7 @@
 
     /* Configure codec with the given format*/
     const char *s = AMediaFormat_toString(format);
-    ALOGV("Input format: %s\n", s);
+    ALOGI("Input format: %s\n", s);
 
     media_status_t status = AMediaCodec_configure(codec, format, nullptr, nullptr, isEncoder);
     if (status != AMEDIA_OK) {
@@ -99,4 +100,4 @@
         return nullptr;
     }
     return codec;
-}
\ No newline at end of file
+}
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.h b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
index 8153a86..c11fe36 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.h
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
@@ -17,15 +17,18 @@
 #ifndef __BENCHMARK_COMMON_H__
 #define __BENCHMARK_COMMON_H__
 
+#include <sys/stat.h>
 #include <inttypes.h>
 #include <mutex>
 #include <queue>
 #include <thread>
+#include <iostream>
 
 #include <media/NdkMediaCodec.h>
 #include <media/NdkMediaError.h>
 
 #include "Stats.h"
+#define UNUSED(x) (void)(x)
 
 using namespace std;
 
diff --git a/media/tests/benchmark/src/native/common/Stats.cpp b/media/tests/benchmark/src/native/common/Stats.cpp
index 2d9bb31..bfde125 100644
--- a/media/tests/benchmark/src/native/common/Stats.cpp
+++ b/media/tests/benchmark/src/native/common/Stats.cpp
@@ -17,8 +17,10 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "Stats"
 
+#include <ctime>
 #include <iostream>
 #include <stdint.h>
+#include <fstream>
 
 #include "Stats.h"
 
@@ -28,16 +30,20 @@
  * \param operation      describes the operation performed on the input media
  *                       (i.e. extract/mux/decode/encode)
  * \param inputReference input media
- * \param duarationUs    is a duration of the input media in microseconds.
+ * \param durationUs     is a duration of the input media in microseconds.
+ * \param componentName  describes the codecName/muxFormat/mimeType.
+ * \param mode           the operating mode: sync/async.
+ * \param statsFile      the file where the stats data is to be written.
  */
-void Stats::dumpStatistics(std::string operation, std::string inputReference, int64_t duarationUs) {
+void Stats::dumpStatistics(string operation, string inputReference, int64_t durationUs,
+                           string componentName, string mode, string statsFile) {
     ALOGV("In %s", __func__);
     if (!mOutputTimer.size()) {
         ALOGE("No output produced");
         return;
     }
     nsecs_t totalTimeTakenNs = getTotalTime();
-    nsecs_t timeTakenPerSec = (totalTimeTakenNs * 1000000) / duarationUs;
+    nsecs_t timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs;
     nsecs_t timeToFirstFrameNs = *mOutputTimer.begin() - mStartTimeNs;
     int32_t size = std::accumulate(mFrameSizes.begin(), mFrameSizes.end(), 0);
     // get min and max output intervals.
@@ -52,15 +58,32 @@
         else if (maxTimeTakenNs < intervalNs) maxTimeTakenNs = intervalNs;
     }
 
-    // Print the Stats
-    std::cout << "Input Reference : " << inputReference << endl;
-    std::cout << "Setup Time in nano sec : " << mInitTimeNs << endl;
-    std::cout << "Average Time in nano sec : " << totalTimeTakenNs / mOutputTimer.size() << endl;
-    std::cout << "Time to first frame in nano sec : " << timeToFirstFrameNs << endl;
-    std::cout << "Time taken (in nano sec) to " << operation
-              << " 1 sec of content : " << timeTakenPerSec << endl;
-    std::cout << "Total bytes " << operation << "ed : " << size << endl;
-    std::cout << "Minimum Time in nano sec : " << minTimeTakenNs << endl;
-    std::cout << "Maximum Time in nano sec : " << maxTimeTakenNs << endl;
-    std::cout << "Destroy Time in nano sec : " << mDeInitTimeNs << endl;
+    // Write the stats data to file.
+    int64_t dataSize = size;
+    int64_t bytesPerSec = ((int64_t)dataSize * 1000000000) / totalTimeTakenNs;
+    string rowData = "";
+    rowData.append(to_string(systemTime(CLOCK_MONOTONIC)) + ", ");
+    rowData.append(inputReference + ", ");
+    rowData.append(operation + ", ");
+    rowData.append(componentName + ", ");
+    rowData.append("NDK, ");
+    rowData.append(mode + ", ");
+    rowData.append(to_string(mInitTimeNs) + ", ");
+    rowData.append(to_string(mDeInitTimeNs) + ", ");
+    rowData.append(to_string(minTimeTakenNs) + ", ");
+    rowData.append(to_string(maxTimeTakenNs) + ", ");
+    rowData.append(to_string(totalTimeTakenNs / mOutputTimer.size()) + ", ");
+    rowData.append(to_string(timeTakenPerSec) + ", ");
+    rowData.append(to_string(bytesPerSec) + ", ");
+    rowData.append(to_string(timeToFirstFrameNs) + ", ");
+    rowData.append(to_string(size) + ",");
+    rowData.append(to_string(totalTimeTakenNs) + ",\n");
+
+    ofstream out(statsFile, ios::out | ios::app);
+    if(out.bad()) {
+        ALOGE("Failed to open stats file for writing!");
+        return;
+    }
+    out << rowData;
+    out.close();
 }
diff --git a/media/tests/benchmark/src/native/common/Stats.h b/media/tests/benchmark/src/native/common/Stats.h
index 2f556ee..18e4b06 100644
--- a/media/tests/benchmark/src/native/common/Stats.h
+++ b/media/tests/benchmark/src/native/common/Stats.h
@@ -18,6 +18,7 @@
 #define __STATS_H__
 
 #include <android/log.h>
+#include <inttypes.h>
 
 #ifndef ALOG
 #define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
@@ -25,6 +26,12 @@
 #define ALOGI(...) ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)
 #define ALOGE(...) ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)
 #define ALOGD(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define ALOGW(...) ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)
+
+#ifndef LOG_NDEBUG
+#define LOG_NDEBUG 1
+#endif
+
 #if LOG_NDEBUG
 #define ALOGV(cond, ...)   ((void)0)
 #else
@@ -95,7 +102,8 @@
         return (*(mOutputTimer.end() - 1) - mStartTimeNs);
     }
 
-    void dumpStatistics(std::string operation, std::string inputReference, int64_t duarationUs);
+    void dumpStatistics(string operation, string inputReference, int64_t duarationUs,
+                        string codecName = "", string mode = "", string statsFile = "");
 };
 
 #endif  // __STATS_H__
diff --git a/media/tests/benchmark/src/native/decoder/Android.bp b/media/tests/benchmark/src/native/decoder/Android.bp
index b5072ab..9791c11 100644
--- a/media/tests/benchmark/src/native/decoder/Android.bp
+++ b/media/tests/benchmark/src/native/decoder/Android.bp
@@ -27,24 +27,26 @@
 
     export_include_dirs: ["."],
 
-    ldflags: ["-Wl,-Bsymbolic"]
+    ldflags: ["-Wl,-Bsymbolic"],
 }
 
 cc_library_static {
     name: "libmediabenchmark_codec2_decoder",
     defaults: [
-        "libmediabenchmark_common-defaults",
         "libmediabenchmark_codec2_common-defaults",
     ],
 
-    srcs: ["C2Decoder.cpp"],
+    srcs: [
+        "C2Decoder.cpp",
+        "Decoder.cpp",
+    ],
 
     static_libs: [
         "libmediabenchmark_codec2_common",
-        "libmediabenchmark_extractor",
+        "libmediabenchmark_codec2_extractor",
     ],
 
     export_include_dirs: ["."],
 
-    ldflags: ["-Wl,-Bsymbolic"]
+    ldflags: ["-Wl,-Bsymbolic"],
 }
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.cpp b/media/tests/benchmark/src/native/decoder/Decoder.cpp
index ac0d525..2171589 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.cpp
+++ b/media/tests/benchmark/src/native/decoder/Decoder.cpp
@@ -225,12 +225,12 @@
 }
 
 void Decoder::deInitCodec() {
-    int64_t sTime = mStats->getCurTime();
     if (mFormat) {
         AMediaFormat_delete(mFormat);
         mFormat = nullptr;
     }
     if (!mCodec) return;
+    int64_t sTime = mStats->getCurTime();
     AMediaCodec_stop(mCodec);
     AMediaCodec_delete(mCodec);
     int64_t eTime = mStats->getCurTime();
@@ -238,10 +238,11 @@
     mStats->setDeInitTime(timeTaken);
 }
 
-void Decoder::dumpStatistics(string inputReference) {
+void Decoder::dumpStatistics(string inputReference, string componentName, string mode,
+                             string statsFile) {
     int64_t durationUs = mExtractor->getClipDuration();
     string operation = "decode";
-    mStats->dumpStatistics(operation, inputReference, durationUs);
+    mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
 }
 
 void Decoder::resetDecoder() {
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.h b/media/tests/benchmark/src/native/decoder/Decoder.h
index aeda080..f3fa6a1 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.h
+++ b/media/tests/benchmark/src/native/decoder/Decoder.h
@@ -71,7 +71,8 @@
     int32_t decode(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo,
                    string &codecName, bool asyncMode, FILE *outFp = nullptr);
 
-    void dumpStatistics(string inputReference);
+    void dumpStatistics(string inputReference, string componentName = "", string mode = "",
+                        string statsFile = "");
 
   private:
     AMediaCodec *mCodec;
diff --git a/media/tests/benchmark/src/native/encoder/Android.bp b/media/tests/benchmark/src/native/encoder/Android.bp
index 239f378..8de7823 100644
--- a/media/tests/benchmark/src/native/encoder/Android.bp
+++ b/media/tests/benchmark/src/native/encoder/Android.bp
@@ -23,11 +23,31 @@
 
     srcs: ["Encoder.cpp"],
 
-    static_libs: ["libmediabenchmark_extractor",
-                  "libmediabenchmark_decoder",
+    static_libs: [
+        "libmediabenchmark_extractor",
+        "libmediabenchmark_decoder",
     ],
 
     export_include_dirs: ["."],
 
-    ldflags: ["-Wl,-Bsymbolic"]
+    ldflags: ["-Wl,-Bsymbolic"],
+}
+
+cc_library_static {
+    name: "libmediabenchmark_codec2_encoder",
+    defaults: [
+        "libmediabenchmark_codec2_common-defaults",
+    ],
+
+    srcs: ["C2Encoder.cpp"],
+
+    static_libs: [
+        "libmediabenchmark_codec2_common",
+        "libmediabenchmark_codec2_extractor",
+        "libmediabenchmark_codec2_decoder",
+    ],
+
+    export_include_dirs: ["."],
+
+    ldflags: ["-Wl,-Bsymbolic"],
 }
diff --git a/media/tests/benchmark/src/native/encoder/C2Encoder.cpp b/media/tests/benchmark/src/native/encoder/C2Encoder.cpp
new file mode 100644
index 0000000..33429ef
--- /dev/null
+++ b/media/tests/benchmark/src/native/encoder/C2Encoder.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2Encoder"
+
+#include "C2Encoder.h"
+
+int32_t C2Encoder::createCodec2Component(string compName, AMediaFormat *format) {
+    ALOGV("In %s", __func__);
+    mListener.reset(new CodecListener(
+            [this](std::list<std::unique_ptr<C2Work>> &workItems) { handleWorkDone(workItems); }));
+    if (!mListener) return -1;
+
+    const char *mime = nullptr;
+    AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+    if (!mime) {
+        ALOGE("Error in AMediaFormat_getString");
+        return -1;
+    }
+    // Configure the plugin with Input properties
+    std::vector<C2Param *> configParam;
+    if (!strncmp(mime, "audio/", 6)) {
+        mIsAudioEncoder = true;
+        int32_t numChannels;
+        if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate)) {
+            ALOGE("AMEDIAFORMAT_KEY_SAMPLE_RATE not set");
+            return -1;
+        }
+        if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &numChannels)) {
+            ALOGE("AMEDIAFORMAT_KEY_CHANNEL_COUNT not set");
+            return -1;
+        }
+        C2StreamSampleRateInfo::input sampleRateInfo(0u, mSampleRate);
+        C2StreamChannelCountInfo::input channelCountInfo(0u, numChannels);
+        configParam.push_back(&sampleRateInfo);
+        configParam.push_back(&channelCountInfo);
+    } else {
+        mIsAudioEncoder = false;
+        if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth)) {
+            ALOGE("AMEDIAFORMAT_KEY_WIDTH not set");
+            return -1;
+        }
+        if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight)) {
+            ALOGE("AMEDIAFORMAT_KEY_HEIGHT not set");
+            return -1;
+        }
+        C2StreamPictureSizeInfo::input inputSize(0u, mWidth, mHeight);
+        configParam.push_back(&inputSize);
+
+        if (!AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mFrameRate) ||
+            (mFrameRate <= 0)) {
+            mFrameRate = KDefaultFrameRate;
+        }
+    }
+
+    int64_t sTime = mStats->getCurTime();
+    mComponent = mClient->CreateComponentByName(compName.c_str(), mListener, &mClient);
+    if (mComponent == nullptr) {
+        ALOGE("Create component failed for %s", compName.c_str());
+        return -1;
+    }
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    int32_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
+    if (failures.size() != 0) {
+        ALOGE("Invalid Configuration");
+        return -1;
+    }
+
+    status |= mComponent->start();
+    int64_t eTime = mStats->getCurTime();
+    int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+    mStats->setInitTime(timeTaken);
+    return status;
+}
+
+// In encoder components, fetch the size of input buffer allocated
+int32_t C2Encoder::getInputMaxBufSize() {
+    int32_t bitStreamInfo[1] = {0};
+    std::vector<std::unique_ptr<C2Param>> inParams;
+    c2_status_t status = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
+                                           C2_DONT_BLOCK, &inParams);
+    if (status != C2_OK && inParams.size() == 0) {
+        ALOGE("Query MaxBufferSizeInfo failed => %d", status);
+        return status;
+    } else {
+        size_t offset = sizeof(C2Param);
+        for (size_t i = 0; i < inParams.size(); ++i) {
+            C2Param *param = inParams[i].get();
+            bitStreamInfo[i] = *(int32_t *)((uint8_t *)param + offset);
+        }
+    }
+    mInputMaxBufSize = bitStreamInfo[0];
+    if (mInputMaxBufSize < 0) {
+        ALOGE("Invalid mInputMaxBufSize %d\n", mInputMaxBufSize);
+        return -1;
+    }
+    return status;
+}
+
+int32_t C2Encoder::encodeFrames(ifstream &eleStream, size_t inputBufferSize) {
+    ALOGV("In %s", __func__);
+    int32_t frameSize = 0;
+    if (!mIsAudioEncoder) {
+        frameSize = mWidth * mHeight * 3 / 2;
+    } else {
+        frameSize = DEFAULT_AUDIO_FRAME_SIZE;
+        if (getInputMaxBufSize() != 0) return -1;
+        if (frameSize > mInputMaxBufSize) {
+            frameSize = mInputMaxBufSize;
+        }
+    }
+    int32_t numFrames = (inputBufferSize + frameSize - 1) / frameSize;
+    // Temporary buffer to read data from the input file
+    char *data = (char *)malloc(frameSize);
+    if (!data) {
+        ALOGE("Insufficient memory to read from input file");
+        return -1;
+    }
+
+    typedef std::unique_lock<std::mutex> ULock;
+    uint64_t presentationTimeUs = 0;
+    size_t offset = 0;
+    c2_status_t status = C2_OK;
+
+    mStats->setStartTime();
+    while (numFrames > 0) {
+        std::unique_ptr<C2Work> work;
+        // Prepare C2Work
+        {
+            ULock l(mQueueLock);
+            if (mWorkQueue.empty()) mQueueCondition.wait_for(l, MAX_RETRY * TIME_OUT);
+            if (!mWorkQueue.empty()) {
+                mStats->addInputTime();
+                work.swap(mWorkQueue.front());
+                mWorkQueue.pop_front();
+            } else {
+                cout << "Wait for generating C2Work exceeded timeout" << endl;
+                return -1;
+            }
+        }
+
+        if (mIsAudioEncoder) {
+            presentationTimeUs = mNumInputFrame * frameSize * (1000000 / mSampleRate);
+        } else {
+            presentationTimeUs = mNumInputFrame * (1000000 / mFrameRate);
+        }
+        uint32_t flags = 0;
+        if (numFrames == 1) flags |= C2FrameData::FLAG_END_OF_STREAM;
+
+        work->input.flags = (C2FrameData::flags_t)flags;
+        work->input.ordinal.timestamp = presentationTimeUs;
+        work->input.ordinal.frameIndex = mNumInputFrame;
+        work->input.buffers.clear();
+
+        if (inputBufferSize - offset < frameSize) {
+            frameSize = inputBufferSize - offset;
+        }
+        eleStream.read(data, frameSize);
+        if (eleStream.gcount() != frameSize) {
+            ALOGE("read() from file failed. Incorrect bytes read");
+            return -1;
+        }
+        offset += frameSize;
+
+        if (frameSize) {
+            if (mIsAudioEncoder) {
+                std::shared_ptr<C2LinearBlock> block;
+                status = mLinearPool->fetchLinearBlock(
+                        frameSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+                if (status != C2_OK || !block) {
+                    cout << "fetchLinearBlock failed : " << status << endl;
+                    return status;
+                }
+                C2WriteView view = block->map().get();
+                if (view.error() != C2_OK) {
+                    cout << "C2LinearBlock::map() failed : " << view.error() << endl;
+                    return view.error();
+                }
+
+                memcpy(view.base(), data, frameSize);
+                work->input.buffers.emplace_back(new LinearBuffer(block));
+            } else {
+                std::shared_ptr<C2GraphicBlock> block;
+                status = mGraphicPool->fetchGraphicBlock(
+                        mWidth, mHeight, HAL_PIXEL_FORMAT_YV12,
+                        {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+                if (status != C2_OK || !block) {
+                    cout << "fetchGraphicBlock failed : " << status << endl;
+                    return status;
+                }
+                C2GraphicView view = block->map().get();
+                if (view.error() != C2_OK) {
+                    cout << "C2GraphicBlock::map() failed : " << view.error() << endl;
+                    return view.error();
+                }
+
+                uint8_t *pY = view.data()[C2PlanarLayout::PLANE_Y];
+                uint8_t *pU = view.data()[C2PlanarLayout::PLANE_U];
+                uint8_t *pV = view.data()[C2PlanarLayout::PLANE_V];
+                memcpy(pY, data, mWidth * mHeight);
+                memcpy(pU, data + mWidth * mHeight, (mWidth * mHeight >> 2));
+                memcpy(pV, data + (mWidth * mHeight * 5 >> 2), mWidth * mHeight >> 2);
+                work->input.buffers.emplace_back(new GraphicBuffer(block));
+            }
+            mStats->addFrameSize(frameSize);
+        }
+
+        work->worklets.clear();
+        work->worklets.emplace_back(new C2Worklet);
+
+        std::list<std::unique_ptr<C2Work>> items;
+        items.push_back(std::move(work));
+        // queue() invokes process() function of C2 Plugin.
+        status = mComponent->queue(&items);
+        if (status != C2_OK) {
+            ALOGE("queue failed");
+            return status;
+        }
+        ALOGV("Frame #%d size = %d queued", mNumInputFrame, frameSize);
+        numFrames--;
+        mNumInputFrame++;
+    }
+    free(data);
+    return status;
+}
+
+void C2Encoder::deInitCodec() {
+    ALOGV("In %s", __func__);
+    if (!mComponent) return;
+
+    int64_t sTime = mStats->getCurTime();
+    mComponent->stop();
+    mComponent->release();
+    mComponent = nullptr;
+    int64_t eTime = mStats->getCurTime();
+    int64_t timeTaken = mStats->getTimeDiff(sTime, eTime);
+    mStats->setDeInitTime(timeTaken);
+}
+
+void C2Encoder::dumpStatistics(string inputReference, int64_t durationUs) {
+    string operation = "c2encode";
+    mStats->dumpStatistics(operation, inputReference, durationUs);
+}
+
+void C2Encoder::resetEncoder() {
+    mIsAudioEncoder = false;
+    mNumInputFrame = 0;
+    mEos = false;
+    if (mStats) mStats->reset();
+}
diff --git a/media/tests/benchmark/src/native/encoder/C2Encoder.h b/media/tests/benchmark/src/native/encoder/C2Encoder.h
new file mode 100644
index 0000000..a4ca097
--- /dev/null
+++ b/media/tests/benchmark/src/native/encoder/C2Encoder.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __C2_ENCODER_H__
+#define __C2_ENCODER_H__
+
+#include <stdio.h>
+#include <algorithm>
+#include <fstream>
+
+#include "BenchmarkC2Common.h"
+
+#define DEFAULT_AUDIO_FRAME_SIZE 4096
+
+constexpr int32_t KDefaultFrameRate = 25;
+
+class C2Encoder : public BenchmarkC2Common {
+  public:
+    C2Encoder()
+        : mIsAudioEncoder(false),
+          mWidth(0),
+          mHeight(0),
+          mNumInputFrame(0),
+          mComponent(nullptr) {}
+
+    int32_t createCodec2Component(string codecName, AMediaFormat *format);
+
+    int32_t encodeFrames(ifstream &eleStream, size_t inputBufferSize);
+
+    int32_t getInputMaxBufSize();
+
+    void deInitCodec();
+
+    void dumpStatistics(string inputReference, int64_t durationUs);
+
+    void resetEncoder();
+
+  private:
+    bool mIsAudioEncoder;
+
+    int32_t mWidth;
+    int32_t mHeight;
+    int32_t mFrameRate;
+    int32_t mSampleRate;
+
+    int32_t mNumInputFrame;
+    int32_t mInputMaxBufSize;
+
+    std::shared_ptr<android::Codec2Client::Listener> mListener;
+    std::shared_ptr<android::Codec2Client::Component> mComponent;
+};
+
+#endif  // __C2_ENCODER_H__
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.cpp b/media/tests/benchmark/src/native/encoder/Encoder.cpp
index a5605de..2db612c 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.cpp
+++ b/media/tests/benchmark/src/native/encoder/Encoder.cpp
@@ -154,11 +154,12 @@
 }
 
 void Encoder::deInitCodec() {
-    int64_t sTime = mStats->getCurTime();
     if (mFormat) {
         AMediaFormat_delete(mFormat);
         mFormat = nullptr;
     }
+    if (!mCodec) return;
+    int64_t sTime = mStats->getCurTime();
     AMediaCodec_stop(mCodec);
     AMediaCodec_delete(mCodec);
     int64_t eTime = mStats->getCurTime();
@@ -174,9 +175,10 @@
     memset(&mParams, 0, sizeof mParams);
 }
 
-void Encoder::dumpStatistics(string inputReference, int64_t durationUs) {
+void Encoder::dumpStatistics(string inputReference, int64_t durationUs, string componentName,
+                             string mode, string statsFile) {
     string operation = "encode";
-    mStats->dumpStatistics(operation, inputReference, durationUs);
+    mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
 }
 
 int32_t Encoder::encode(string &codecName, ifstream &eleStream, size_t eleSize,
@@ -206,7 +208,7 @@
         AMediaFormat_setInt32(mFormat, AMEDIAFORMAT_KEY_BIT_RATE, mParams.bitrate);
     }
     const char *s = AMediaFormat_toString(mFormat);
-    ALOGV("Input format: %s\n", s);
+    ALOGI("Input format: %s\n", s);
 
     int64_t sTime = mStats->getCurTime();
     mCodec = createMediaCodec(mFormat, mMime, codecName, true /*isEncoder*/);
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.h b/media/tests/benchmark/src/native/encoder/Encoder.h
index 6059c4a..3d12600 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.h
+++ b/media/tests/benchmark/src/native/encoder/Encoder.h
@@ -75,7 +75,8 @@
     int32_t encode(std::string &codecName, std::ifstream &eleStream, size_t eleSize, bool asyncMode,
                    encParameter encParams, char *mime);
 
-    void dumpStatistics(string inputReference, int64_t durationUs);
+    void dumpStatistics(string inputReference, int64_t durationUs, string codecName = "",
+                        string mode = "", string statsFile = "");
 
   private:
     AMediaCodec *mCodec;
diff --git a/media/tests/benchmark/src/native/extractor/Android.bp b/media/tests/benchmark/src/native/extractor/Android.bp
index dfd0d49..7ed9476 100644
--- a/media/tests/benchmark/src/native/extractor/Android.bp
+++ b/media/tests/benchmark/src/native/extractor/Android.bp
@@ -27,3 +27,20 @@
 
     ldflags: ["-Wl,-Bsymbolic"]
 }
+
+cc_library_static {
+    name: "libmediabenchmark_codec2_extractor",
+    defaults: [
+        "libmediabenchmark_codec2_common-defaults",
+    ],
+
+    srcs: ["Extractor.cpp"],
+
+    static_libs: [
+        "libmediabenchmark_codec2_common",
+    ],
+
+    export_include_dirs: ["."],
+
+    ldflags: ["-Wl,-Bsymbolic"]
+}
diff --git a/media/tests/benchmark/src/native/extractor/Extractor.cpp b/media/tests/benchmark/src/native/extractor/Extractor.cpp
index b4cad0b..f0bb3b9 100644
--- a/media/tests/benchmark/src/native/extractor/Extractor.cpp
+++ b/media/tests/benchmark/src/native/extractor/Extractor.cpp
@@ -111,9 +111,9 @@
     return AMEDIA_OK;
 }
 
-void Extractor::dumpStatistics(string inputReference) {
+void Extractor::dumpStatistics(string inputReference, string componentName, string statsFile) {
     string operation = "extract";
-    mStats->dumpStatistics(operation, inputReference, mDurationUs);
+    mStats->dumpStatistics(operation, inputReference, mDurationUs, componentName, "", statsFile);
 }
 
 void Extractor::deInitExtractor() {
diff --git a/media/tests/benchmark/src/native/extractor/Extractor.h b/media/tests/benchmark/src/native/extractor/Extractor.h
index 4c39a72..1694fc7 100644
--- a/media/tests/benchmark/src/native/extractor/Extractor.h
+++ b/media/tests/benchmark/src/native/extractor/Extractor.h
@@ -45,7 +45,7 @@
 
     int32_t extract(int32_t trackId);
 
-    void dumpStatistics(std::string inputReference);
+    void dumpStatistics(string inputReference, string componentName = "", string statsFile = "");
 
     void deInitExtractor();
 
diff --git a/media/tests/benchmark/src/native/muxer/Muxer.cpp b/media/tests/benchmark/src/native/muxer/Muxer.cpp
index b297a66..3e150ca 100644
--- a/media/tests/benchmark/src/native/muxer/Muxer.cpp
+++ b/media/tests/benchmark/src/native/muxer/Muxer.cpp
@@ -29,7 +29,7 @@
     int64_t sTime = mStats->getCurTime();
     mMuxer = AMediaMuxer_new(fd, (OutputFormat)outputFormat);
     if (!mMuxer) {
-        cout << "[   WARN   ] Test Skipped. Unable to create muxer \n";
+        ALOGV("Unable to create muxer");
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
     /*
@@ -38,7 +38,7 @@
      */
     ssize_t index = AMediaMuxer_addTrack(mMuxer, mFormat);
     if (index < 0) {
-        cout << "[   WARN   ] Test Skipped. Format not supported \n";
+        ALOGV("Format not supported");
         return index;
     }
     AMediaMuxer_start(mMuxer);
@@ -49,12 +49,12 @@
 }
 
 void Muxer::deInitMuxer() {
-    int64_t sTime = mStats->getCurTime();
     if (mFormat) {
         AMediaFormat_delete(mFormat);
         mFormat = nullptr;
     }
     if (!mMuxer) return;
+    int64_t sTime = mStats->getCurTime();
     AMediaMuxer_stop(mMuxer);
     AMediaMuxer_delete(mMuxer);
     int64_t eTime = mStats->getCurTime();
@@ -66,9 +66,10 @@
     if (mStats) mStats->reset();
 }
 
-void Muxer::dumpStatistics(string inputReference) {
+void Muxer::dumpStatistics(string inputReference, string componentName, string statsFile) {
     string operation = "mux";
-    mStats->dumpStatistics(operation, inputReference, mExtractor->getClipDuration());
+    mStats->dumpStatistics(operation, inputReference, mExtractor->getClipDuration(), componentName,
+                           "", statsFile);
 }
 
 int32_t Muxer::mux(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfos) {
diff --git a/media/tests/benchmark/src/native/muxer/Muxer.h b/media/tests/benchmark/src/native/muxer/Muxer.h
index eee3146..860fdaf 100644
--- a/media/tests/benchmark/src/native/muxer/Muxer.h
+++ b/media/tests/benchmark/src/native/muxer/Muxer.h
@@ -51,7 +51,7 @@
     /* Process the frames and give Muxed output */
     int32_t mux(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameSizes);
 
-    void dumpStatistics(string inputReference);
+    void dumpStatistics(string inputReference, string codecName = "", string statsFile = "");
 
   private:
     AMediaFormat *mFormat;
diff --git a/media/tests/benchmark/tests/Android.bp b/media/tests/benchmark/tests/Android.bp
index 128d055..f46fa4a 100644
--- a/media/tests/benchmark/tests/Android.bp
+++ b/media/tests/benchmark/tests/Android.bp
@@ -87,8 +87,25 @@
     srcs: ["C2DecoderTest.cpp"],
 
     static_libs: [
-        "libmediabenchmark_extractor",
+        "libmediabenchmark_codec2_extractor",
         "libmediabenchmark_codec2_common",
         "libmediabenchmark_codec2_decoder",
     ],
 }
+
+cc_test {
+    name: "C2EncoderTest",
+    gtest: true,
+    defaults: [
+        "libmediabenchmark_codec2_common-defaults",
+    ],
+
+    srcs: ["C2EncoderTest.cpp"],
+
+    static_libs: [
+        "libmediabenchmark_codec2_extractor",
+        "libmediabenchmark_codec2_decoder",
+        "libmediabenchmark_codec2_common",
+        "libmediabenchmark_codec2_encoder",
+    ],
+}
diff --git a/media/tests/benchmark/tests/C2DecoderTest.cpp b/media/tests/benchmark/tests/C2DecoderTest.cpp
index 3531d8a..ecd9759 100644
--- a/media/tests/benchmark/tests/C2DecoderTest.cpp
+++ b/media/tests/benchmark/tests/C2DecoderTest.cpp
@@ -29,82 +29,64 @@
 
 class C2DecoderTest : public ::testing::TestWithParam<pair<string, string>> {
   public:
-    C2DecoderTest() : mDecoder(nullptr), disableTest(false) { setupC2DecoderTest(); }
+    C2DecoderTest() : mDecoder(nullptr) {}
+
+    ~C2DecoderTest() {
+        if (!mCodecList.empty()) {
+            mCodecList.clear();
+        }
+        if (mDecoder) {
+            delete mDecoder;
+            mDecoder = nullptr;
+        }
+    }
+
+    virtual void SetUp() override { setupC2DecoderTest(); }
 
     void setupC2DecoderTest();
 
     vector<string> mCodecList;
     C2Decoder *mDecoder;
-    bool disableTest;
 };
 
 void C2DecoderTest::setupC2DecoderTest() {
     mDecoder = new C2Decoder();
-    if (!mDecoder) {
-        cout << "[   WARN   ] Test Skipped. C2Decoder creation failed\n";
-        disableTest = true;
-        return;
-    }
+    ASSERT_NE(mDecoder, nullptr) << "C2Decoder creation failed";
+
     int32_t status = mDecoder->setupCodec2();
-    if (status != 0) {
-        cout << "[   WARN   ] Test Skipped. Codec2 setup failed \n";
-        disableTest = true;
-        return;
-    }
+    ASSERT_EQ(status, 0) << "Codec2 setup failed";
+
     mCodecList = mDecoder->getSupportedComponentList(false /* isEncoder*/);
-    if (!mCodecList.size()) {
-        cout << "[   WARN   ] Test Skipped. Codec2 client didn't recognise any component \n";
-        disableTest = true;
-        return;
-    }
+    ASSERT_GT(mCodecList.size(), 0) << "Codec2 client didn't recognise any component";
 }
 
 TEST_P(C2DecoderTest, Codec2Decode) {
-    if (disableTest) return;
-
     ALOGV("Decode the samples given by extractor using codec2");
     string inputFile = gEnv->getRes() + GetParam().first;
     FILE *inputFp = fopen(inputFile.c_str(), "rb");
-    if (!inputFp) {
-        cout << "[   WARN   ] Test Skipped. Unable to open input file" << inputFile
-             << " for reading \n";
-        return;
-    }
+    ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
 
     Extractor *extractor = new Extractor();
-    if (!extractor) {
-        cout << "[   WARN   ] Test Skipped. Extractor creation failed \n";
-        return;
-    }
+    ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
 
     // Read file properties
-    fseek(inputFp, 0, SEEK_END);
-    size_t fileSize = ftell(inputFp);
-    fseek(inputFp, 0, SEEK_SET);
+    struct stat buf;
+    stat(inputFile.c_str(), &buf);
+    size_t fileSize = buf.st_size;
     int32_t fd = fileno(inputFp);
 
-    if (fileSize > kMaxBufferSize) {
-        cout << "[   WARN   ] Test Skipped. Input file size is greater than the threshold memory "
-                "dedicated to the test \n";
-    }
+    ASSERT_LE(fileSize, kMaxBufferSize)
+            << "Input file size is greater than the threshold memory dedicated to the test";
 
     int32_t trackCount = extractor->initExtractor(fd, fileSize);
-    if (trackCount <= 0) {
-        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
-        return;
-    }
+    ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
     for (int32_t curTrack = 0; curTrack < trackCount; curTrack++) {
         int32_t status = extractor->setupTrackFormat(curTrack);
-        if (status != 0) {
-            cout << "[   WARN   ] Test Skipped. Track Format invalid \n";
-            return;
-        }
+        ASSERT_EQ(status, 0) << "Track Format invalid";
 
         uint8_t *inputBuffer = (uint8_t *)malloc(fileSize);
-        if (!inputBuffer) {
-            cout << "[   WARN   ] Test Skipped. Insufficient memory \n";
-            return;
-        }
+        ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
 
         vector<AMediaCodecBufferInfo> frameInfo;
         AMediaCodecBufferInfo info;
@@ -116,11 +98,8 @@
             void *csdBuffer = extractor->getCSDSample(info, idx);
             if (!csdBuffer || !info.size) break;
             // copy the meta data and buffer to be passed to decoder
-            if (inputBufferOffset + info.size > fileSize) {
-                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
-                free(inputBuffer);
-                return;
-            }
+            ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
+
             memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
             frameInfo.push_back(info);
             inputBufferOffset += info.size;
@@ -132,11 +111,8 @@
             status = extractor->getFrameSample(info);
             if (status || !info.size) break;
             // copy the meta data and buffer to be passed to decoder
-            if (inputBufferOffset + info.size > fileSize) {
-                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
-                free(inputBuffer);
-                return;
-            }
+            ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
+
             memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
             frameInfo.push_back(info);
             inputBufferOffset += info.size;
@@ -148,21 +124,18 @@
             if (codecName.find(GetParam().second) != string::npos &&
                 codecName.find("secure") == string::npos) {
                 status = mDecoder->createCodec2Component(codecName, format);
-                if (status != 0) {
-                    cout << "[   WARN   ] Test Skipped. Create component failed for " << codecName
-                         << "\n";
-                    continue;
-                }
+                ASSERT_EQ(status, 0) << "Create component failed for " << codecName;
 
                 // Send the inputs to C2 Decoder and wait till all buffers are returned.
-                mDecoder->decodeFrames(inputBuffer, frameInfo);
+                status = mDecoder->decodeFrames(inputBuffer, frameInfo);
+                ASSERT_EQ(status, 0) << "Decoder failed for " << codecName;
+
                 mDecoder->waitOnInputConsumption();
-                if (!mDecoder->mEos) {
-                    cout << "[   WARN   ] Test Failed. Didn't receive EOS \n";
-                }
+                ASSERT_TRUE(mDecoder->mEos) << "Test Failed. Didn't receive EOS \n";
+
                 mDecoder->deInitCodec();
                 int64_t durationUs = extractor->getClipDuration();
-                cout << "codec: " << codecName << endl;
+                ALOGV("codec : %s", codecName.c_str());
                 mDecoder->dumpStatistics(GetParam().first, durationUs);
                 mDecoder->resetDecoder();
             }
@@ -172,6 +145,7 @@
         extractor->deInitExtractor();
         delete extractor;
         delete mDecoder;
+        mDecoder = nullptr;
     }
 }
 
@@ -179,26 +153,24 @@
 // Add wav files
 INSTANTIATE_TEST_SUITE_P(
         AudioDecoderTest, C2DecoderTest,
-        ::testing::Values(
-                make_pair("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "aac"),
-                make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "mp3"),
-                make_pair("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "amrnb"),
-                make_pair("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "amrnb"),
-                make_pair("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "vorbis"),
-                make_pair("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "flac"),
-                make_pair("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "opus")));
+        ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "aac"),
+                          make_pair("bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", "mp3"),
+                          make_pair("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "amrnb"),
+                          make_pair("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "amrnb"),
+                          make_pair("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "vorbis"),
+                          make_pair("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "flac"),
+                          make_pair("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "opus")));
 
 INSTANTIATE_TEST_SUITE_P(
         VideoDecoderTest, C2DecoderTest,
-        ::testing::Values(
-                make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "vp9"),
-                make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "vp8"),
-                make_pair("crowd_1920x1080_25fps_4000kbps_av1.webm", "av1"),
-                make_pair("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "mpeg2"),
-                make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mpeg4"),
-                make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "h263"),
-                make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "avc"),
-                make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "hevc")));
+        ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "vp9"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "vp8"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_av1.webm", "av1"),
+                          make_pair("crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", "mpeg2"),
+                          make_pair("crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mpeg4"),
+                          make_pair("crowd_352x288_25fps_6000kbps_h263.3gp", "h263"),
+                          make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "avc"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "hevc")));
 
 int main(int argc, char **argv) {
     gEnv = new BenchmarkTestEnvironment();
diff --git a/media/tests/benchmark/tests/C2EncoderTest.cpp b/media/tests/benchmark/tests/C2EncoderTest.cpp
new file mode 100644
index 0000000..98eb17a
--- /dev/null
+++ b/media/tests/benchmark/tests/C2EncoderTest.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2EncoderTest"
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+
+#include "BenchmarkTestEnvironment.h"
+#include "C2Encoder.h"
+#include "Decoder.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class C2EncoderTest : public ::testing::TestWithParam<pair<string, string>> {
+  public:
+    C2EncoderTest() : mEncoder(nullptr) {}
+
+    ~C2EncoderTest() {
+        if (!mCodecList.empty()) {
+            mCodecList.clear();
+        }
+        if (mEncoder) {
+            delete mEncoder;
+            mEncoder = nullptr;
+        }
+    }
+
+    virtual void SetUp() override { setupC2EncoderTest(); }
+
+    void setupC2EncoderTest();
+
+    vector<string> mCodecList;
+    C2Encoder *mEncoder;
+};
+
+void C2EncoderTest::setupC2EncoderTest() {
+    mEncoder = new C2Encoder();
+    ASSERT_NE(mEncoder, nullptr) << "C2Encoder creation failed";
+
+    int32_t status = mEncoder->setupCodec2();
+    ASSERT_EQ(status, 0) << "Codec2 setup failed";
+
+    mCodecList = mEncoder->getSupportedComponentList(true /* isEncoder*/);
+    ASSERT_GT(mCodecList.size(), 0) << "Codec2 client didn't recognise any component";
+}
+
+TEST_P(C2EncoderTest, Codec2Encode) {
+    ALOGV("Encodes the input using codec2 framework");
+    string inputFile = gEnv->getRes() + GetParam().first;
+    FILE *inputFp = fopen(inputFile.c_str(), "rb");
+    ASSERT_NE(inputFp, nullptr) << "Unable to open input file for reading";
+
+    Decoder *decoder = new Decoder();
+    ASSERT_NE(decoder, nullptr) << "Decoder creation failed";
+
+    Extractor *extractor = decoder->getExtractor();
+    ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
+
+    // Read file properties
+    struct stat buf;
+    stat(inputFile.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    int32_t fd = fileno(inputFp);
+
+    ASSERT_LE(fileSize, kMaxBufferSize)
+            << "Input file size is greater than the threshold memory dedicated to the test";
+
+    int32_t trackCount = extractor->initExtractor(fd, fileSize);
+    ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
+    for (int curTrack = 0; curTrack < trackCount; curTrack++) {
+        int32_t status = extractor->setupTrackFormat(curTrack);
+        ASSERT_EQ(status, 0) << "Track Format invalid";
+
+        uint8_t *inputBuffer = (uint8_t *)malloc(fileSize);
+        ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
+        vector<AMediaCodecBufferInfo> frameInfo;
+        AMediaCodecBufferInfo info;
+        uint32_t inputBufferOffset = 0;
+
+        // Get frame data
+        while (1) {
+            status = extractor->getFrameSample(info);
+            if (status || !info.size) break;
+            // copy the meta data and buffer to be passed to decoder
+            ASSERT_LE(inputBufferOffset + info.size, fileSize) << "Memory allocated not sufficient";
+
+            memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+            frameInfo.push_back(info);
+            inputBufferOffset += info.size;
+        }
+
+        string decName = "";
+        string outputFileName = "decode.out";
+        FILE *outFp = fopen(outputFileName.c_str(), "wb");
+        ASSERT_NE(outFp, nullptr) << "Unable to open output file" << outputFileName
+                                  << " for dumping decoder's output";
+
+        decoder->setupDecoder();
+        status = decoder->decode(inputBuffer, frameInfo, decName, false /*asyncMode */, outFp);
+        ASSERT_EQ(status, AMEDIA_OK) << "Decode returned error : " << status;
+
+        // Encode the given input stream for all C2 codecs supported by device
+        AMediaFormat *format = extractor->getFormat();
+        ifstream eleStream;
+        eleStream.open(outputFileName.c_str(), ifstream::binary | ifstream::ate);
+        ASSERT_EQ(eleStream.is_open(), true) << outputFileName.c_str() << " - file not found";
+        size_t eleSize = eleStream.tellg();
+
+        for (string codecName : mCodecList) {
+            if (codecName.find(GetParam().second) != string::npos) {
+                status = mEncoder->createCodec2Component(codecName, format);
+                ASSERT_EQ(status, 0) << "Create component failed for " << codecName;
+
+                // Send the inputs to C2 Encoder and wait till all buffers are returned.
+                eleStream.seekg(0, ifstream::beg);
+                status = mEncoder->encodeFrames(eleStream, eleSize);
+                ASSERT_EQ(status, 0) << "Encoder failed for " << codecName;
+
+                mEncoder->waitOnInputConsumption();
+                ASSERT_TRUE(mEncoder->mEos) << "Test Failed. Didn't receive EOS \n";
+
+                mEncoder->deInitCodec();
+                int64_t durationUs = extractor->getClipDuration();
+                ALOGV("codec : %s", codecName.c_str());
+                mEncoder->dumpStatistics(GetParam().first, durationUs);
+                mEncoder->resetEncoder();
+            }
+        }
+
+        // Destroy the decoder for the given input
+        decoder->deInitCodec();
+        decoder->resetDecoder();
+        free(inputBuffer);
+    }
+    fclose(inputFp);
+    extractor->deInitExtractor();
+    delete decoder;
+    delete mEncoder;
+    mEncoder = nullptr;
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        AudioEncoderTest, C2EncoderTest,
+        ::testing::Values(make_pair("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "aac"),
+                          make_pair("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "amrnb"),
+                          make_pair("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "amrwb"),
+                          make_pair("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "flac"),
+                          make_pair("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "opus")));
+
+INSTANTIATE_TEST_SUITE_P(
+        VideoEncoderTest, C2EncoderTest,
+        ::testing::Values(make_pair("crowd_1920x1080_25fps_4000kbps_vp9.webm", "vp9"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_vp8.webm", "vp8"),
+                          make_pair("crowd_176x144_25fps_6000kbps_mpeg4.mp4", "mpeg4"),
+                          make_pair("crowd_176x144_25fps_6000kbps_h263.3gp", "h263"),
+                          make_pair("crowd_1920x1080_25fps_6700kbps_h264.ts", "avc"),
+                          make_pair("crowd_1920x1080_25fps_4000kbps_h265.mkv", "hevc")));
+
+int main(int argc, char **argv) {
+    gEnv = new BenchmarkTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("C2 Encoder Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index fa37435..5c6aa5b 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -21,8 +21,8 @@
 #include <iostream>
 #include <limits>
 
-#include "Decoder.h"
 #include "BenchmarkTestEnvironment.h"
+#include "Decoder.h"
 
 static BenchmarkTestEnvironment *gEnv = nullptr;
 
@@ -34,41 +34,30 @@
 
     string inputFile = gEnv->getRes() + get<0>(params);
     FILE *inputFp = fopen(inputFile.c_str(), "rb");
-    if (!inputFp) {
-        cout << "[   WARN   ] Test Skipped. Unable to open input file for reading \n";
-        return;
-    }
+    ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
 
     Decoder *decoder = new Decoder();
+    ASSERT_NE(decoder, nullptr) << "Decoder creation failed";
+
     Extractor *extractor = decoder->getExtractor();
-    if (!extractor) {
-        cout << "[   WARN   ] Test Skipped. Extractor creation failed \n";
-        return;
-    }
+    ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
 
     // Read file properties
-    fseek(inputFp, 0, SEEK_END);
-    size_t fileSize = ftell(inputFp);
-    fseek(inputFp, 0, SEEK_SET);
+    struct stat buf;
+    stat(inputFile.c_str(), &buf);
+    size_t fileSize = buf.st_size;
     int32_t fd = fileno(inputFp);
 
     int32_t trackCount = extractor->initExtractor(fd, fileSize);
-    if (trackCount <= 0) {
-        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
-        return;
-    }
+    ASSERT_GT(trackCount, 0) << "initExtractor failed";
+
     for (int curTrack = 0; curTrack < trackCount; curTrack++) {
         int32_t status = extractor->setupTrackFormat(curTrack);
-        if (status != 0) {
-            cout << "[   WARN   ] Test Skipped. Track Format invalid \n";
-            return;
-        }
+        ASSERT_EQ(status, 0) << "Track Format invalid";
 
         uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
-        if (!inputBuffer) {
-            cout << "[   WARN   ] Test Skipped. Insufficient memory \n";
-            return;
-        }
+        ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
         vector<AMediaCodecBufferInfo> frameInfo;
         AMediaCodecBufferInfo info;
         uint32_t inputBufferOffset = 0;
@@ -78,11 +67,9 @@
             status = extractor->getFrameSample(info);
             if (status || !info.size) break;
             // copy the meta data and buffer to be passed to decoder
-            if (inputBufferOffset + info.size > kMaxBufferSize) {
-                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
-                free(inputBuffer);
-                return;
-            }
+            ASSERT_LE(inputBufferOffset + info.size, kMaxBufferSize)
+                    << "Memory allocated not sufficient";
+
             memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
             frameInfo.push_back(info);
             inputBufferOffset += info.size;
@@ -92,13 +79,10 @@
         bool asyncMode = get<2>(params);
         decoder->setupDecoder();
         status = decoder->decode(inputBuffer, frameInfo, codecName, asyncMode);
-        if (status != AMEDIA_OK) {
-            cout << "[   WARN   ] Test Failed. Decode returned error " << status << endl;
-            free(inputBuffer);
-            return;
-        }
+        ASSERT_EQ(status, AMEDIA_OK) << "Decoder failed for " << codecName;
+
         decoder->deInitCodec();
-        cout << "codec : " << codecName << endl;
+        ALOGV("codec : %s", codecName.c_str());
         string inputReference = get<0>(params);
         decoder->dumpStatistics(inputReference);
         free(inputBuffer);
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index c3963f8..dc2a2dd 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -20,8 +20,8 @@
 #include <fstream>
 
 #include "BenchmarkTestEnvironment.h"
-#include "Encoder.h"
 #include "Decoder.h"
+#include "Encoder.h"
 
 static BenchmarkTestEnvironment *gEnv = nullptr;
 
@@ -33,42 +33,33 @@
 
     string inputFile = gEnv->getRes() + get<0>(params);
     FILE *inputFp = fopen(inputFile.c_str(), "rb");
-    if (!inputFp) {
-        cout << "[   WARN   ] Test Skipped. Unable to open input file for reading \n";
-        return;
-    }
+    ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
 
     Decoder *decoder = new Decoder();
+    ASSERT_NE(decoder, nullptr) << "Decoder creation failed";
+
     Extractor *extractor = decoder->getExtractor();
-    if (!extractor) {
-        cout << "[   WARN   ] Test Skipped. Extractor creation failed \n";
-        return;
-    }
+    ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
+
     // Read file properties
-    fseek(inputFp, 0, SEEK_END);
-    size_t fileSize = ftell(inputFp);
-    fseek(inputFp, 0, SEEK_SET);
+    struct stat buf;
+    stat(inputFile.c_str(), &buf);
+    size_t fileSize = buf.st_size;
     int32_t fd = fileno(inputFp);
 
     int32_t trackCount = extractor->initExtractor(fd, fileSize);
-    if (trackCount <= 0) {
-        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
-        return;
-    }
+    ASSERT_GT(trackCount, 0) << "initExtractor failed";
 
     Encoder *encoder = new Encoder();
+    ASSERT_NE(encoder, nullptr) << "Decoder creation failed";
+
     for (int curTrack = 0; curTrack < trackCount; curTrack++) {
         int32_t status = extractor->setupTrackFormat(curTrack);
-        if (status != 0) {
-            cout << "[   WARN   ] Test Skipped. Track Format invalid \n";
-            return;
-        }
+        ASSERT_EQ(status, 0) << "Track Format invalid";
 
         uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
-        if (!inputBuffer) {
-            cout << "[   WARN   ] Test Skipped. Insufficient memory \n";
-            return;
-        }
+        ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
         vector<AMediaCodecBufferInfo> frameInfo;
         AMediaCodecBufferInfo info;
         uint32_t inputBufferOffset = 0;
@@ -78,11 +69,9 @@
             status = extractor->getFrameSample(info);
             if (status || !info.size) break;
             // copy the meta data and buffer to be passed to decoder
-            if (inputBufferOffset + info.size > kMaxBufferSize) {
-                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
-                free(inputBuffer);
-                return;
-            }
+            ASSERT_LE(inputBufferOffset + info.size, kMaxBufferSize)
+                    << "Memory allocated not sufficient";
+
             memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
             frameInfo.push_back(info);
             inputBufferOffset += info.size;
@@ -91,16 +80,12 @@
         string decName = "";
         string outputFileName = "decode.out";
         FILE *outFp = fopen(outputFileName.c_str(), "wb");
-        if (outFp == nullptr) {
-            ALOGE("Unable to open output file for writing");
-            return;
-        }
+        ASSERT_NE(outFp, nullptr) << "Unable to open output file" << outputFileName
+                                  << " for dumping decoder's output";
+
         decoder->setupDecoder();
         status = decoder->decode(inputBuffer, frameInfo, decName, false /*asyncMode */, outFp);
-        if (status != AMEDIA_OK) {
-            cout << "[   WARN   ] Test Skipped. Decode returned error \n";
-            return;
-        }
+        ASSERT_EQ(status, AMEDIA_OK) << "Decode returned error : " << status;
 
         ifstream eleStream;
         eleStream.open(outputFileName.c_str(), ifstream::binary | ifstream::ate);
@@ -111,15 +96,13 @@
         AMediaFormat *format = extractor->getFormat();
         const char *mime = nullptr;
         AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
-        if (!mime) {
-            ALOGE("Error in AMediaFormat_getString");
-            return;
-        }
+        ASSERT_NE(mime, nullptr) << "Invalid mime type";
+
         // Get encoder params
         encParameter encParams;
         if (!strncmp(mime, "video/", 6)) {
-            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &encParams.width);
-            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &encParams.height);
+            ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &encParams.width));
+            ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &encParams.height));
             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &encParams.frameRate);
             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &encParams.bitrate);
             if (encParams.bitrate <= 0 || encParams.frameRate <= 0) {
@@ -133,8 +116,10 @@
             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_PROFILE, &encParams.profile);
             AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_LEVEL, &encParams.level);
         } else {
-            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &encParams.sampleRate);
-            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &encParams.numChannels);
+            ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE,
+                                              &encParams.sampleRate));
+            ASSERT_TRUE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+                                              &encParams.numChannels));
             encParams.bitrate =
                     encParams.sampleRate * encParams.numChannels * 16 /* bitsPerSample */;
         }
@@ -143,13 +128,10 @@
         string codecName = get<1>(params);
         bool asyncMode = get<2>(params);
         status = encoder->encode(codecName, eleStream, eleSize, asyncMode, encParams, (char *)mime);
-        if (status != AMEDIA_OK) {
-            cout << "[   WARN   ] Test Failed. Encode returned error " << status << endl;
-            free(inputBuffer);
-            return;
-        }
+        ASSERT_EQ(status, 0) << "Encoder failed for " << codecName;
+
         encoder->deInitCodec();
-        cout << "codec : " << codecName << endl;
+        ALOGV("codec : %s", codecName.c_str());
         string inputReference = get<0>(params);
         encoder->dumpStatistics(inputReference, extractor->getClipDuration());
         eleStream.close();
diff --git a/media/tests/benchmark/tests/ExtractorTest.cpp b/media/tests/benchmark/tests/ExtractorTest.cpp
index dd0d711..c2d72ff 100644
--- a/media/tests/benchmark/tests/ExtractorTest.cpp
+++ b/media/tests/benchmark/tests/ExtractorTest.cpp
@@ -19,8 +19,8 @@
 
 #include <gtest/gtest.h>
 
-#include "Extractor.h"
 #include "BenchmarkTestEnvironment.h"
+#include "Extractor.h"
 
 static BenchmarkTestEnvironment *gEnv = nullptr;
 
@@ -28,33 +28,24 @@
 
 TEST_P(ExtractorTest, Extract) {
     Extractor *extractObj = new Extractor();
+    ASSERT_NE(extractObj, nullptr) << "Extractor creation failed";
 
     string inputFile = gEnv->getRes() + GetParam().first;
     FILE *inputFp = fopen(inputFile.c_str(), "rb");
-    if (!inputFp) {
-        cout << "[   WARN   ] Test Skipped. Unable to open input file for reading \n";
-        return;
-    }
+    ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
 
     // Read file properties
-    size_t fileSize = 0;
-    fseek(inputFp, 0, SEEK_END);
-    fileSize = ftell(inputFp);
-    fseek(inputFp, 0, SEEK_SET);
+    struct stat buf;
+    stat(inputFile.c_str(), &buf);
+    size_t fileSize = buf.st_size;
     int32_t fd = fileno(inputFp);
 
     int32_t trackCount = extractObj->initExtractor(fd, fileSize);
-    if (trackCount <= 0) {
-        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
-        return;
-    }
+    ASSERT_GT(trackCount, 0) << "initExtractor failed";
 
     int32_t trackID = GetParam().second;
     int32_t status = extractObj->extract(trackID);
-    if (status != AMEDIA_OK) {
-        cout << "[   WARN   ] Test Skipped. Extraction failed \n";
-        return;
-    }
+    ASSERT_EQ(status, AMEDIA_OK) << "Extraction failed \n";
 
     extractObj->deInitExtractor();
 
@@ -79,7 +70,8 @@
                                            make_pair("bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", 0),
                                            make_pair("bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", 0),
                                            make_pair("bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", 0),
-                                           make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm", 0)));
+                                           make_pair("bbb_48000hz_2ch_100kbps_opus_5mins.webm",
+                                                     0)));
 
 int main(int argc, char **argv) {
     gEnv = new BenchmarkTestEnvironment();
diff --git a/media/tests/benchmark/tests/MuxerTest.cpp b/media/tests/benchmark/tests/MuxerTest.cpp
index e814f90..7b01732 100644
--- a/media/tests/benchmark/tests/MuxerTest.cpp
+++ b/media/tests/benchmark/tests/MuxerTest.cpp
@@ -21,8 +21,8 @@
 #include <fstream>
 #include <iostream>
 
-#include "Muxer.h"
 #include "BenchmarkTestEnvironment.h"
+#include "Muxer.h"
 
 #define OUTPUT_FILE_NAME "/data/local/tmp/mux.out"
 
@@ -53,49 +53,34 @@
     ALOGV("Mux the samples given by extractor");
     string inputFile = gEnv->getRes() + GetParam().first;
     FILE *inputFp = fopen(inputFile.c_str(), "rb");
-    if (!inputFp) {
-        cout << "[   WARN   ] Test Skipped. Unable to open input file for reading \n";
-        return;
-    }
+    ASSERT_NE(inputFp, nullptr) << "Unable to open " << inputFile << " file for reading";
+
     string fmt = GetParam().second;
     MUXER_OUTPUT_T outputFormat = getMuxerOutFormat(fmt);
-    if (outputFormat == MUXER_OUTPUT_FORMAT_INVALID) {
-        ALOGE("output format is MUXER_OUTPUT_FORMAT_INVALID");
-        return;
-    }
+    ASSERT_NE(outputFormat, MUXER_OUTPUT_FORMAT_INVALID) << "Invalid muxer output format";
 
     Muxer *muxerObj = new Muxer();
+    ASSERT_NE(muxerObj, nullptr) << "Muxer creation failed";
+
     Extractor *extractor = muxerObj->getExtractor();
-    if (!extractor) {
-        cout << "[   WARN   ] Test Skipped. Extractor creation failed \n";
-        return;
-    }
+    ASSERT_NE(extractor, nullptr) << "Extractor creation failed";
 
     // Read file properties
-    size_t fileSize = 0;
-    fseek(inputFp, 0, SEEK_END);
-    fileSize = ftell(inputFp);
-    fseek(inputFp, 0, SEEK_SET);
+    struct stat buf;
+    stat(inputFile.c_str(), &buf);
+    size_t fileSize = buf.st_size;
     int32_t fd = fileno(inputFp);
 
     int32_t trackCount = extractor->initExtractor(fd, fileSize);
-    if (trackCount <= 0) {
-        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
-        return;
-    }
+    ASSERT_GT(trackCount, 0) << "initExtractor failed";
 
     for (int curTrack = 0; curTrack < trackCount; curTrack++) {
         int32_t status = extractor->setupTrackFormat(curTrack);
-        if (status != 0) {
-            cout << "[   WARN   ] Test Skipped. Track Format invalid \n";
-            return;
-        }
+        ASSERT_EQ(status, 0) << "Track Format invalid";
 
         uint8_t *inputBuffer = (uint8_t *)malloc(kMaxBufferSize);
-        if (!inputBuffer) {
-            std::cout << "[   WARN   ] Test Skipped. Insufficient memory \n";
-            return;
-        }
+        ASSERT_NE(inputBuffer, nullptr) << "Insufficient memory";
+
         // AMediaCodecBufferInfo : <size of frame> <flags> <presentationTimeUs> <offset>
         vector<AMediaCodecBufferInfo> frameInfos;
         AMediaCodecBufferInfo info;
@@ -106,11 +91,9 @@
             status = extractor->getFrameSample(info);
             if (status || !info.size) break;
             // copy the meta data and buffer to be passed to muxer
-            if (inputBufferOffset + info.size > kMaxBufferSize) {
-                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
-                free(inputBuffer);
-                return;
-            }
+            ASSERT_LE(inputBufferOffset + info.size, kMaxBufferSize)
+                    << "Memory allocated not sufficient";
+
             memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
             info.offset = inputBufferOffset;
             frameInfos.push_back(info);
@@ -119,22 +102,16 @@
 
         string outputFileName = OUTPUT_FILE_NAME;
         FILE *outputFp = fopen(outputFileName.c_str(), "w+b");
-        if (!outputFp) {
-            cout << "[   WARN   ] Test Skipped. Unable to open output file for writing \n";
-            return;
-        }
+        ASSERT_NE(outputFp, nullptr)
+                << "Unable to open output file" << outputFileName << " for writing";
+
         int32_t fd = fileno(outputFp);
         status = muxerObj->initMuxer(fd, outputFormat);
-        if (status != 0) {
-            cout << "[   WARN   ] Test Skipped. initMuxer failed\n";
-            return;
-        }
+        ASSERT_EQ(status, 0) << "initMuxer failed";
 
         status = muxerObj->mux(inputBuffer, frameInfos);
-        if (status != 0) {
-            cout << "[   WARN   ] Test Skipped. Mux failed \n";
-            return;
-        }
+        ASSERT_EQ(status, 0) << "Mux failed";
+
         muxerObj->deInitMuxer();
         muxerObj->dumpStatistics(GetParam().first + "." + fmt.c_str());
         free(inputBuffer);
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 27f1a79..113e4a7 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -23,6 +23,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IProcessInfoService.h>
 #include <binder/IServiceManager.h>
+#include <private/android_filesystem_config.h>
 
 namespace android {
 
@@ -55,8 +56,9 @@
 
 bool ProcessInfo::isValidPid(int pid) {
     int callingPid = IPCThreadState::self()->getCallingPid();
+    int callingUid = IPCThreadState::self()->getCallingUid();
     // Trust it if this is called from the same process otherwise pid has to match the calling pid.
-    return (callingPid == getpid()) || (callingPid == pid);
+    return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
 }
 
 ProcessInfo::~ProcessInfo() {}
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 02141a8..a661470 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -174,12 +174,19 @@
 }
 
 bool modifyDefaultAudioEffectsAllowed() {
+    return modifyDefaultAudioEffectsAllowed(
+        IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+}
+
+bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid) {
+    if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
+
     static const String16 sModifyDefaultAudioEffectsAllowed(
             "android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
     // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
-    bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed);
-
-    if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+    bool ok = PermissionCache::checkPermission(sModifyDefaultAudioEffectsAllowed, pid, uid);
+    ALOGE_IF(!ok, "%s(): android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS denied for uid %d",
+            __func__, uid);
     return ok;
 }
 
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index e1089d5..f5768bd 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -85,6 +85,7 @@
 bool settingsAllowed();
 bool modifyAudioRoutingAllowed();
 bool modifyDefaultAudioEffectsAllowed();
+bool modifyDefaultAudioEffectsAllowed(pid_t pid, uid_t uid);
 bool dumpAllowed();
 bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
 bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid);
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index de8c7e7..46472c9 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -3,12 +3,15 @@
 cc_library_shared {
     name: "libaudioflinger",
 
+    tidy: false, // b/146435095, segmentation fault with Effects.cpp
+
     srcs: [
         "AudioFlinger.cpp",
         "AudioHwDevice.cpp",
         "AudioStreamOut.cpp",
         "AudioWatchdog.cpp",
         "BufLog.cpp",
+        "DeviceEffectManager.cpp",
         "Effects.cpp",
         "FastCapture.cpp",
         "FastCaptureDumpState.cpp",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 525ac68..10a9c63 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -170,6 +170,7 @@
       mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes),
       mGlobalEffectEnableTime(0),
       mPatchPanel(this),
+      mDeviceEffectManager(this),
       mSystemReady(false)
 {
     // unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
@@ -382,6 +383,24 @@
     }
 }
 
+status_t AudioFlinger::addEffectToHal(audio_port_handle_t deviceId,
+        audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
+    if (audioHwDevice == nullptr) {
+        return NO_INIT;
+    }
+    return audioHwDevice->hwDevice()->addDeviceEffect(deviceId, effect);
+}
+
+status_t AudioFlinger::removeEffectFromHal(audio_port_handle_t deviceId,
+        audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+    AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
+    if (audioHwDevice == nullptr) {
+        return NO_INIT;
+    }
+    return audioHwDevice->hwDevice()->removeDeviceEffect(deviceId, effect);
+}
+
 static const char * const audio_interfaces[] = {
     AUDIO_HARDWARE_MODULE_ID_PRIMARY,
     AUDIO_HARDWARE_MODULE_ID_A2DP,
@@ -558,6 +577,8 @@
 
         mPatchPanel.dump(fd);
 
+        mDeviceEffectManager.dump(fd);
+
         // dump external setParameters
         auto dumpLogger = [fd](SimpleLog& logger, const char* name) {
             dprintf(fd, "\n%s setParameters:\n", name);
@@ -2944,7 +2965,7 @@
         Mutex::Autolock _l(t->mLock);
         for (size_t j = 0; j < t->mEffectChains.size(); j++) {
             sp<EffectChain> ec = t->mEffectChains[j];
-            if (ec->sessionId() > AUDIO_SESSION_OUTPUT_MIX) {
+            if (!audio_is_global_session(ec->sessionId())) {
                 chains.push(ec);
             }
         }
@@ -2971,7 +2992,7 @@
     for (size_t i = 0; i < chains.size(); i++) {
         sp<EffectChain> ec = chains[i];
         int sessionid = ec->sessionId();
-        sp<ThreadBase> t = ec->mThread.promote();
+        sp<ThreadBase> t = ec->thread().promote();
         if (t == 0) {
             continue;
         }
@@ -2994,7 +3015,7 @@
                 effect->unPin();
                 t->removeEffect_l(effect, /*release*/ true);
                 if (effect->purgeHandles()) {
-                    t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
+                    effect->checkSuspendOnEffectEnabled(false, true /*threadLocked*/);
                 }
                 removedEffects.push_back(effect);
             }
@@ -3294,6 +3315,7 @@
         int32_t priority,
         audio_io_handle_t io,
         audio_session_t sessionId,
+        const AudioDeviceTypeAddr& device,
         const String16& opPackageName,
         pid_t pid,
         status_t *status,
@@ -3346,6 +3368,17 @@
             lStatus = BAD_VALUE;
             goto Exit;
         }
+    } else if (sessionId == AUDIO_SESSION_DEVICE) {
+        if (!modifyDefaultAudioEffectsAllowed(pid, callingUid)) {
+            ALOGE("%s: device effect permission denied for uid %d", __func__, callingUid);
+            lStatus = PERMISSION_DENIED;
+            goto Exit;
+        }
+        if (io != AUDIO_IO_HANDLE_NONE) {
+            ALOGE("%s: io handle should not be specified for device effect", __func__);
+            lStatus = BAD_VALUE;
+            goto Exit;
+        }
     } else {
         // general sessionId.
 
@@ -3381,7 +3414,7 @@
         // check recording permission for visualizer
         if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
             // TODO: Do we need to start/stop op - i.e. is there recording being performed?
-            !recordingAllowed(opPackageName, pid, IPCThreadState::self()->getCallingUid())) {
+            !recordingAllowed(opPackageName, pid, callingUid)) {
             lStatus = PERMISSION_DENIED;
             goto Exit;
         }
@@ -3398,6 +3431,23 @@
 
         Mutex::Autolock _l(mLock);
 
+        if (sessionId == AUDIO_SESSION_DEVICE) {
+            sp<Client> client = registerPid(pid);
+            ALOGV("%s device type %d address %s", __func__, device.mType, device.getAddress());
+            handle = mDeviceEffectManager.createEffect_l(
+                    &desc, device, client, effectClient, mPatchPanel.patches_l(),
+                    enabled, &lStatus);
+            if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
+                // remove local strong reference to Client with mClientLock held
+                Mutex::Autolock _cl(mClientLock);
+                client.clear();
+            } else {
+                // handle must be valid here, but check again to be safe.
+                if (handle.get() != nullptr && id != nullptr) *id = handle->id();
+            }
+            goto Register;
+        }
+
         // If output is not specified try to find a matching audio session ID in one of the
         // output threads.
         // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
@@ -3479,7 +3529,7 @@
         sp<Client> client = registerPid(pid);
 
         // create effect on selected output thread
-        bool pinned = (sessionId > AUDIO_SESSION_OUTPUT_MIX) && isSessionAcquired_l(sessionId);
+        bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
         handle = thread->createEffect_l(client, effectClient, priority, sessionId,
                 &desc, enabled, &lStatus, pinned);
         if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
@@ -3492,9 +3542,10 @@
         }
     }
 
+Register:
     if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
         // Check CPU and memory usage
-        sp<EffectModule> effect = handle->effect().promote();
+        sp<EffectBase> effect = handle->effect().promote();
         if (effect != nullptr) {
             status_t rStatus = effect->updatePolicyState();
             if (rStatus != NO_ERROR) {
@@ -3604,7 +3655,7 @@
         // if the move request is not received from audio policy manager, the effect must be
         // re-registered with the new strategy and output
         if (dstChain == 0) {
-            dstChain = effect->chain().promote();
+            dstChain = effect->callback()->chain().promote();
             if (dstChain == 0) {
                 ALOGW("moveEffectChain_l() cannot get chain from effect %p", effect.get());
                 status = NO_INIT;
@@ -3654,7 +3705,7 @@
             goto Exit;
         }
 
-        dstChain = effect->chain().promote();
+        dstChain = effect->callback()->chain().promote();
         if (dstChain == 0) {
             thread->addEffect_l(effect);
             status = INVALID_OPERATION;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9e3ec92..a43a6dc 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -232,6 +232,7 @@
                         int32_t priority,
                         audio_io_handle_t io,
                         audio_session_t sessionId,
+                        const AudioDeviceTypeAddr& device,
                         const String16& opPackageName,
                         pid_t pid,
                         status_t *status /*non-NULL*/,
@@ -307,6 +308,12 @@
 
     static int onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration);
     static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
+
+    status_t addEffectToHal(audio_port_handle_t deviceId,
+            audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect);
+    status_t removeEffectFromHal(audio_port_handle_t deviceId,
+            audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect);
+
 private:
     // FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
     static const size_t kLogMemorySize = 400 * 1024;
@@ -532,9 +539,14 @@
     class AsyncCallbackThread;
     class Track;
     class RecordTrack;
+    class EffectBase;
     class EffectModule;
     class EffectHandle;
     class EffectChain;
+    class DeviceEffectProxy;
+    class DeviceEffectManager;
+    class PatchPanel;
+    class DeviceEffectManagerCallback;
 
     struct AudioStreamIn;
     struct TeePatch;
@@ -572,9 +584,11 @@
 
 #include "Threads.h"
 
+#include "PatchPanel.h"
+
 #include "Effects.h"
 
-#include "PatchPanel.h"
+#include "DeviceEffectManager.h"
 
     // Find io handle by session id.
     // Preference is given to an io handle with a matching effect chain to session id.
@@ -920,6 +934,8 @@
     PatchPanel mPatchPanel;
     sp<EffectsFactoryHalInterface> mEffectsFactoryHal;
 
+    DeviceEffectManager mDeviceEffectManager;
+
     bool       mSystemReady;
 
     SimpleLog  mRejectedSetParameterLog;
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
new file mode 100644
index 0000000..87a4c6e
--- /dev/null
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -0,0 +1,277 @@
+/*
+**
+** Copyright 2019, 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.
+*/
+
+
+#define LOG_TAG "AudioFlinger::DeviceEffectManager"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <audio_utils/primitives.h>
+
+#include "AudioFlinger.h"
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+
+// ----------------------------------------------------------------------------
+
+
+namespace android {
+
+void AudioFlinger::DeviceEffectManager::createAudioPatch(audio_patch_handle_t handle,
+        const PatchPanel::Patch& patch) {
+    ALOGV("%s handle %d mHalHandle %d num sinks %d device sink %08x",
+            __func__, handle, patch.mHalHandle,
+            patch.mAudioPatch.num_sinks,
+            patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
+
+    mCommandThread->createAudioPatchCommand(handle, patch);
+}
+
+void AudioFlinger::DeviceEffectManager::onCreateAudioPatch(audio_patch_handle_t handle,
+        const PatchPanel::Patch& patch) {
+    ALOGV("%s handle %d mHalHandle %d device sink %08x",
+            __func__, handle, patch.mHalHandle,
+            patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
+    Mutex::Autolock _l(mLock);
+    for (auto& effect : mDeviceEffects) {
+        status_t status = effect.second->onCreatePatch(handle, patch);
+        ALOGV("%s Effect onCreatePatch status %d", __func__, status);
+        ALOGW_IF(status == BAD_VALUE, "%s onCreatePatch error %d", __func__, status);
+    }
+}
+
+void AudioFlinger::DeviceEffectManager::releaseAudioPatch(audio_patch_handle_t handle) {
+    ALOGV("%s", __func__);
+    mCommandThread->releaseAudioPatchCommand(handle);
+}
+
+void AudioFlinger::DeviceEffectManager::onReleaseAudioPatch(audio_patch_handle_t handle) {
+    ALOGV("%s", __func__);
+    Mutex::Autolock _l(mLock);
+    for (auto& effect : mDeviceEffects) {
+        effect.second->onReleasePatch(handle);
+    }
+}
+
+// DeviceEffectManager::createEffect_l() must be called with AudioFlinger::mLock held
+sp<AudioFlinger::EffectHandle> AudioFlinger::DeviceEffectManager::createEffect_l(
+        effect_descriptor_t *descriptor,
+        const AudioDeviceTypeAddr& device,
+        const sp<AudioFlinger::Client>& client,
+        const sp<IEffectClient>& effectClient,
+        const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches,
+        int *enabled,
+        status_t *status) {
+    sp<DeviceEffectProxy> effect;
+    sp<EffectHandle> handle;
+    status_t lStatus;
+
+    lStatus = checkEffectCompatibility(descriptor);
+    if (lStatus != NO_ERROR) {
+       *status = lStatus;
+       return handle;
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+        auto iter = mDeviceEffects.find(device);
+        if (iter != mDeviceEffects.end()) {
+            effect = iter->second;
+        } else {
+            effect = new DeviceEffectProxy(device, mMyCallback,
+                    descriptor, mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT));
+        }
+        // create effect handle and connect it to effect module
+        handle = new EffectHandle(effect, client, effectClient, 0 /*priority*/);
+        lStatus = handle->initCheck();
+        if (lStatus == NO_ERROR) {
+            lStatus = effect->addHandle(handle.get());
+            if (lStatus == NO_ERROR) {
+                effect->init(patches);
+                mDeviceEffects.emplace(device, effect);
+            }
+        }
+    }
+    if (enabled != NULL) {
+        *enabled = (int)effect->isEnabled();
+    }
+    *status = lStatus;
+    return handle;
+}
+
+status_t AudioFlinger::DeviceEffectManager::checkEffectCompatibility(
+        const effect_descriptor_t *desc) {
+
+    if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC
+        && (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) {
+        ALOGW("%s() non pre/post processing device effect %s", __func__, desc->name);
+        return BAD_VALUE;
+    }
+
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::DeviceEffectManager::createEffectHal(
+        const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
+        sp<EffectHalInterface> *effect) {
+    status_t status = NO_INIT;
+    sp<EffectsFactoryHalInterface> effectsFactory = mAudioFlinger.getEffectsFactory();
+    if (effectsFactory != 0) {
+        status = effectsFactory->createEffect(
+                pEffectUuid, sessionId, AUDIO_IO_HANDLE_NONE, deviceId, effect);
+    }
+    return status;
+}
+
+void AudioFlinger::DeviceEffectManager::dump(int fd) {
+    const bool locked = dumpTryLock(mLock);
+    if (!locked) {
+        String8 result("DeviceEffectManager may be deadlocked\n");
+        write(fd, result.string(), result.size());
+    }
+
+    write(fd, "\nDevice Effects:\n", sizeof("\nDevice Effects:\n"));
+    for (const auto& iter : mDeviceEffects) {
+        String8 outStr;
+        outStr.appendFormat("%*sEffect for device %s address %s:\n", 2, "",
+                ::android::toString(iter.first.mType).c_str(), iter.first.getAddress());
+        write(fd, outStr.string(), outStr.size());
+        iter.second->dump(fd, 4);
+    }
+
+    if (locked) {
+        mLock.unlock();
+    }
+}
+
+
+size_t AudioFlinger::DeviceEffectManager::removeEffect(const sp<DeviceEffectProxy>& effect)
+{
+    Mutex::Autolock _l(mLock);
+    mDeviceEffects.erase(effect->device());
+    return mDeviceEffects.size();
+}
+
+bool AudioFlinger::DeviceEffectManagerCallback::disconnectEffectHandle(
+        EffectHandle *handle, bool unpinIfLast) {
+    sp<EffectBase> effectBase = handle->effect().promote();
+    if (effectBase == nullptr) {
+        return false;
+    }
+
+    sp<DeviceEffectProxy> effect = effectBase->asDeviceEffectProxy();
+    if (effect == nullptr) {
+        return false;
+    }
+    // restore suspended effects if the disconnected handle was enabled and the last one.
+    bool remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
+    if (remove) {
+        mManager.removeEffect(effect);
+        if (handle->enabled()) {
+            effectBase->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
+        }
+    }
+    return true;
+}
+
+// -----------  DeviceEffectManager::CommandThread implementation ----------
+
+
+AudioFlinger::DeviceEffectManager::CommandThread::~CommandThread()
+{
+    Mutex::Autolock _l(mLock);
+    mCommands.clear();
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::onFirstRef()
+{
+    run("DeviceEffectManage_CommandThread", ANDROID_PRIORITY_AUDIO);
+}
+
+bool AudioFlinger::DeviceEffectManager::CommandThread::threadLoop()
+{
+    mLock.lock();
+    while (!exitPending())
+    {
+        while (!mCommands.empty() && !exitPending()) {
+            sp<Command> command = mCommands.front();
+            mCommands.pop_front();
+            mLock.unlock();
+
+            switch (command->mCommand) {
+            case CREATE_AUDIO_PATCH: {
+                CreateAudioPatchData *data = (CreateAudioPatchData *)command->mData.get();
+                ALOGV("CommandThread() processing create audio patch handle %d", data->mHandle);
+                mManager.onCreateAudioPatch(data->mHandle, data->mPatch);
+                } break;
+            case RELEASE_AUDIO_PATCH: {
+                ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mData.get();
+                ALOGV("CommandThread() processing release audio patch handle %d", data->mHandle);
+                mManager.onReleaseAudioPatch(data->mHandle);
+                } break;
+            default:
+                ALOGW("CommandThread() unknown command %d", command->mCommand);
+            }
+            mLock.lock();
+        }
+
+        // At this stage we have either an empty command queue or the first command in the queue
+        // has a finite delay. So unless we are exiting it is safe to wait.
+        if (!exitPending()) {
+            ALOGV("CommandThread() going to sleep");
+            mWaitWorkCV.wait(mLock);
+        }
+    }
+    mLock.unlock();
+    return false;
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::sendCommand(sp<Command> command) {
+    Mutex::Autolock _l(mLock);
+    mCommands.push_back(command);
+    mWaitWorkCV.signal();
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::createAudioPatchCommand(
+        audio_patch_handle_t handle, const PatchPanel::Patch& patch)
+{
+    sp<Command> command = new Command(CREATE_AUDIO_PATCH, new CreateAudioPatchData(handle, patch));
+    ALOGV("CommandThread() adding create patch handle %d mHalHandle %d.", handle, patch.mHalHandle);
+    sendCommand(command);
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::releaseAudioPatchCommand(
+        audio_patch_handle_t handle)
+{
+    sp<Command> command = new Command(RELEASE_AUDIO_PATCH, new ReleaseAudioPatchData(handle));
+    ALOGV("CommandThread() adding release patch");
+    sendCommand(command);
+}
+
+void AudioFlinger::DeviceEffectManager::CommandThread::exit()
+{
+    ALOGV("CommandThread::exit");
+    {
+        AutoMutex _l(mLock);
+        requestExit();
+        mWaitWorkCV.signal();
+    }
+    // Note that we can call it from the thread loop if all other references have been released
+    // but it will safely return WOULD_BLOCK in this case
+    requestExitAndWait();
+}
+
+} // namespace android
diff --git a/services/audioflinger/DeviceEffectManager.h b/services/audioflinger/DeviceEffectManager.h
new file mode 100644
index 0000000..14ff14d
--- /dev/null
+++ b/services/audioflinger/DeviceEffectManager.h
@@ -0,0 +1,203 @@
+/*
+**
+** Copyright 2019, 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.
+*/
+
+#ifndef INCLUDING_FROM_AUDIOFLINGER_H
+    #error This header file should only be included from AudioFlinger.h
+#endif
+
+// DeviceEffectManager is concealed within AudioFlinger, their lifetimes are the same.
+class DeviceEffectManager {
+public:
+    explicit DeviceEffectManager(AudioFlinger* audioFlinger)
+        : mCommandThread(new CommandThread(*this)), mAudioFlinger(*audioFlinger),
+        mMyCallback(new DeviceEffectManagerCallback(this)) {}
+
+            ~DeviceEffectManager() {
+                mCommandThread->exit();
+            }
+
+    sp<EffectHandle> createEffect_l(effect_descriptor_t *descriptor,
+                const AudioDeviceTypeAddr& device,
+                const sp<AudioFlinger::Client>& client,
+                const sp<IEffectClient>& effectClient,
+                const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches,
+                int *enabled,
+                status_t *status);
+    void createAudioPatch(audio_patch_handle_t handle, const PatchPanel::Patch& patch);
+    void releaseAudioPatch(audio_patch_handle_t handle);
+
+    size_t removeEffect(const sp<DeviceEffectProxy>& effect);
+    status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+           int32_t sessionId, int32_t deviceId,
+           sp<EffectHalInterface> *effect);
+    status_t addEffectToHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
+            sp<EffectHalInterface> effect) {
+        return mAudioFlinger.addEffectToHal(deviceId, hwModuleId, effect);
+    };
+    status_t removeEffectFromHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
+            sp<EffectHalInterface> effect) {
+        return mAudioFlinger.removeEffectFromHal(deviceId, hwModuleId, effect);
+    };
+
+    AudioFlinger& audioFlinger() const { return mAudioFlinger; }
+
+    void dump(int fd);
+
+private:
+
+    // Thread to execute create and release patch commands asynchronously. This is needed because
+    // PatchPanel::createAudioPatch and releaseAudioPatch are executed from audio policy service
+    // with mutex locked and effect management requires to call back into audio policy service
+    class Command;
+    class CommandThread : public Thread {
+    public:
+
+        enum {
+            CREATE_AUDIO_PATCH,
+            RELEASE_AUDIO_PATCH,
+        };
+
+        CommandThread(DeviceEffectManager& manager)
+            : Thread(false), mManager(manager) {}
+        ~CommandThread() override;
+
+        // Thread virtuals
+        void onFirstRef() override;
+        bool threadLoop() override;
+
+                void exit();
+
+                void createAudioPatchCommand(audio_patch_handle_t handle,
+                        const PatchPanel::Patch& patch);
+                void releaseAudioPatchCommand(audio_patch_handle_t handle);
+
+    private:
+        class CommandData;
+
+        // descriptor for requested tone playback event
+        class Command: public RefBase {
+        public:
+            Command() = default;
+            Command(int command, sp<CommandData> data)
+                : mCommand(command), mData(data) {}
+
+            int mCommand = -1;
+            sp<CommandData> mData;
+        };
+
+        class CommandData: public RefBase {
+        public:
+            virtual ~CommandData() = default;
+        };
+
+        class CreateAudioPatchData : public CommandData {
+        public:
+            CreateAudioPatchData(audio_patch_handle_t handle, const PatchPanel::Patch& patch)
+                :   mHandle(handle), mPatch(patch) {}
+
+            audio_patch_handle_t mHandle;
+            const PatchPanel::Patch mPatch;
+        };
+
+        class ReleaseAudioPatchData : public CommandData {
+        public:
+            ReleaseAudioPatchData(audio_patch_handle_t handle)
+                :   mHandle(handle) {}
+
+            audio_patch_handle_t mHandle;
+        };
+
+        void sendCommand(sp<Command> command);
+
+        Mutex   mLock;
+        Condition mWaitWorkCV;
+        std::deque <sp<Command>> mCommands; // list of pending commands
+        DeviceEffectManager& mManager;
+    };
+
+    void onCreateAudioPatch(audio_patch_handle_t handle, const PatchPanel::Patch& patch);
+    void onReleaseAudioPatch(audio_patch_handle_t handle);
+
+    status_t checkEffectCompatibility(const effect_descriptor_t *desc);
+
+    Mutex mLock;
+    sp<CommandThread> mCommandThread;
+    AudioFlinger &mAudioFlinger;
+    const sp<DeviceEffectManagerCallback> mMyCallback;
+    std::map<AudioDeviceTypeAddr, sp<DeviceEffectProxy>> mDeviceEffects;
+};
+
+class DeviceEffectManagerCallback :  public EffectCallbackInterface {
+public:
+            DeviceEffectManagerCallback(DeviceEffectManager *manager)
+                : mManager(*manager) {}
+
+    status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+           int32_t sessionId, int32_t deviceId,
+           sp<EffectHalInterface> *effect) override {
+                return mManager.createEffectHal(pEffectUuid, sessionId, deviceId, effect);
+            }
+    status_t allocateHalBuffer(size_t size __unused,
+            sp<EffectBufferHalInterface>* buffer __unused) override { return NO_ERROR; }
+    bool updateOrphanEffectChains(const sp<EffectBase>& effect __unused) override { return false; }
+
+    audio_io_handle_t io() const override  { return AUDIO_IO_HANDLE_NONE; }
+    bool isOutput() const override { return false; }
+    bool isOffload() const override { return false; }
+    bool isOffloadOrDirect() const override { return false; }
+    bool isOffloadOrMmap() const override { return false; }
+
+    uint32_t  sampleRate() const override { return 0; }
+    audio_channel_mask_t channelMask() const override { return AUDIO_CHANNEL_NONE; }
+    uint32_t channelCount() const override { return 0; }
+    size_t    frameCount() const override  { return 0; }
+    uint32_t  latency() const override  { return 0; }
+
+    status_t addEffectToHal(sp<EffectHalInterface> effect __unused) override {
+        return NO_ERROR;
+    }
+    status_t removeEffectFromHal(sp<EffectHalInterface> effect __unused) override {
+        return NO_ERROR;
+    }
+
+    bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
+    void setVolumeForOutput(float left __unused, float right __unused) const override {}
+
+    // check if effects should be suspended or restored when a given effect is enable or disabled
+    void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect __unused,
+                          bool enabled __unused, bool threadLocked __unused) override {}
+    void resetVolume() override {}
+    uint32_t strategy() const override  { return 0; }
+    int32_t activeTrackCnt() const override { return 0; }
+    void onEffectEnable(const sp<EffectBase>& effect __unused) override {}
+    void onEffectDisable(const sp<EffectBase>& effect __unused) override {}
+
+    wp<EffectChain> chain() const override { return nullptr; }
+
+    int newEffectId() { return mManager.audioFlinger().nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT); }
+
+    status_t addEffectToHal(audio_port_handle_t deviceId,
+            audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+        return mManager.addEffectToHal(deviceId, hwModuleId, effect);
+    }
+    status_t removeEffectFromHal(audio_port_handle_t deviceId,
+            audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+        return mManager.removeEffectFromHal(deviceId, hwModuleId, effect);
+    }
+private:
+    DeviceEffectManager& mManager;
+};
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index ee7a6d6..ca8fd2d 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -58,81 +58,115 @@
 namespace android {
 
 // ----------------------------------------------------------------------------
-//  EffectModule implementation
+//  EffectBase implementation
 // ----------------------------------------------------------------------------
 
 #undef LOG_TAG
-#define LOG_TAG "AudioFlinger::EffectModule"
+#define LOG_TAG "AudioFlinger::EffectBase"
 
-AudioFlinger::EffectModule::EffectModule(ThreadBase *thread,
-                                        const wp<AudioFlinger::EffectChain>& chain,
+AudioFlinger::EffectBase::EffectBase(const sp<AudioFlinger::EffectCallbackInterface>& callback,
                                         effect_descriptor_t *desc,
                                         int id,
                                         audio_session_t sessionId,
                                         bool pinned)
     : mPinned(pinned),
-      mThread(thread), mChain(chain), mId(id), mSessionId(sessionId),
-      mDescriptor(*desc),
-      // clear mConfig to ensure consistent initial value of buffer framecount
-      // in case buffers are associated by setInBuffer() or setOutBuffer()
-      // prior to configure().
-      mConfig{{}, {}},
-      mStatus(NO_INIT), mState(IDLE),
-      mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
-      mDisableWaitCnt(0),    // set by process() and updateState()
-      mSuspended(false),
-      mOffloaded(false),
-      mAudioFlinger(thread->mAudioFlinger)
-#ifdef FLOAT_EFFECT_CHAIN
-      , mSupportsFloat(false)
-#endif
+      mCallback(callback), mId(id), mSessionId(sessionId),
+      mDescriptor(*desc)
 {
-    ALOGV("Constructor %p pinned %d", this, pinned);
-    int lStatus;
+}
 
-    // create effect engine from effect factory
-    mStatus = -ENODEV;
-    sp<AudioFlinger> audioFlinger = mAudioFlinger.promote();
-    if (audioFlinger != 0) {
-        sp<EffectsFactoryHalInterface> effectsFactory = audioFlinger->getEffectsFactory();
-        if (effectsFactory != 0) {
-            mStatus = effectsFactory->createEffect(
-                    &desc->uuid, sessionId, thread->id(), &mEffectInterface);
+// must be called with EffectModule::mLock held
+status_t AudioFlinger::EffectBase::setEnabled_l(bool enabled)
+{
+
+    ALOGV("setEnabled %p enabled %d", this, enabled);
+
+    if (enabled != isEnabled()) {
+        switch (mState) {
+        // going from disabled to enabled
+        case IDLE:
+            mState = STARTING;
+            break;
+        case STOPPED:
+            mState = RESTART;
+            break;
+        case STOPPING:
+            mState = ACTIVE;
+            break;
+
+        // going from enabled to disabled
+        case RESTART:
+            mState = STOPPED;
+            break;
+        case STARTING:
+            mState = IDLE;
+            break;
+        case ACTIVE:
+            mState = STOPPING;
+            break;
+        case DESTROYED:
+            return NO_ERROR; // simply ignore as we are being destroyed
+        }
+        for (size_t i = 1; i < mHandles.size(); i++) {
+            EffectHandle *h = mHandles[i];
+            if (h != NULL && !h->disconnected()) {
+                h->setEnabled(enabled);
+            }
         }
     }
-
-    if (mStatus != NO_ERROR) {
-        return;
-    }
-    lStatus = init();
-    if (lStatus < 0) {
-        mStatus = lStatus;
-        goto Error;
-    }
-
-    setOffloaded(thread->type() == ThreadBase::OFFLOAD, thread->id());
-    ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
-
-    return;
-Error:
-    mEffectInterface.clear();
-    ALOGV("Constructor Error %d", mStatus);
+    return NO_ERROR;
 }
 
-AudioFlinger::EffectModule::~EffectModule()
+status_t AudioFlinger::EffectBase::setEnabled(bool enabled, bool fromHandle)
 {
-    ALOGV("Destructor %p", this);
-    if (mEffectInterface != 0) {
-        char uuidStr[64];
-        AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
-        ALOGW("EffectModule %p destructor called with unreleased interface, effect %s",
-                this, uuidStr);
-        release_l();
+    status_t status;
+    {
+        Mutex::Autolock _l(mLock);
+        status = setEnabled_l(enabled);
     }
-
+    if (fromHandle) {
+        if (enabled) {
+            if (status != NO_ERROR) {
+                mCallback->checkSuspendOnEffectEnabled(this, false, false /*threadLocked*/);
+            } else {
+                mCallback->onEffectEnable(this);
+            }
+        } else {
+            mCallback->onEffectDisable(this);
+        }
+    }
+    return status;
 }
 
-status_t AudioFlinger::EffectModule::addHandle(EffectHandle *handle)
+bool AudioFlinger::EffectBase::isEnabled() const
+{
+    switch (mState) {
+    case RESTART:
+    case STARTING:
+    case ACTIVE:
+        return true;
+    case IDLE:
+    case STOPPING:
+    case STOPPED:
+    case DESTROYED:
+    default:
+        return false;
+    }
+}
+
+void AudioFlinger::EffectBase::setSuspended(bool suspended)
+{
+    Mutex::Autolock _l(mLock);
+    mSuspended = suspended;
+}
+
+bool AudioFlinger::EffectBase::suspended() const
+{
+    Mutex::Autolock _l(mLock);
+    return mSuspended;
+}
+
+status_t AudioFlinger::EffectBase::addHandle(EffectHandle *handle)
 {
     status_t status;
 
@@ -171,7 +205,7 @@
     return status;
 }
 
-status_t AudioFlinger::EffectModule::updatePolicyState()
+status_t AudioFlinger::EffectBase::updatePolicyState()
 {
     status_t status = NO_ERROR;
     bool doRegister = false;
@@ -188,14 +222,8 @@
             doRegister = true;
             mPolicyRegistered = mHandles.size() > 0;
             if (mPolicyRegistered) {
-              sp <EffectChain> chain = mChain.promote();
-              sp <ThreadBase> thread = mThread.promote();
-
-              if (thread == nullptr || chain == nullptr) {
-                    return INVALID_OPERATION;
-                }
-                io = thread->id();
-                strategy = chain->strategy();
+                io = mCallback->io();
+                strategy = mCallback->strategy();
             }
         }
         // enable effect when registered according to enable state requested by controlling handle
@@ -233,13 +261,13 @@
 }
 
 
-ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
+ssize_t AudioFlinger::EffectBase::removeHandle(EffectHandle *handle)
 {
     Mutex::Autolock _l(mLock);
     return removeHandle_l(handle);
 }
 
-ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
+ssize_t AudioFlinger::EffectBase::removeHandle_l(EffectHandle *handle)
 {
     size_t size = mHandles.size();
     size_t i;
@@ -263,19 +291,15 @@
         }
     }
 
-    // Prevent calls to process() and other functions on effect interface from now on.
-    // The effect engine will be released by the destructor when the last strong reference on
-    // this object is released which can happen after next process is called.
     if (mHandles.size() == 0 && !mPinned) {
         mState = DESTROYED;
-        mEffectInterface->close();
     }
 
     return mHandles.size();
 }
 
 // must be called with EffectModule::mLock held
-AudioFlinger::EffectHandle *AudioFlinger::EffectModule::controlHandle_l()
+AudioFlinger::EffectHandle *AudioFlinger::EffectBase::controlHandle_l()
 {
     // the first valid handle in the list has control over the module
     for (size_t i = 0; i < mHandles.size(); i++) {
@@ -289,22 +313,271 @@
 }
 
 // unsafe method called when the effect parent thread has been destroyed
-ssize_t AudioFlinger::EffectModule::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
+ssize_t AudioFlinger::EffectBase::disconnectHandle(EffectHandle *handle, bool unpinIfLast)
 {
     ALOGV("disconnect() %p handle %p", this, handle);
+    if (mCallback->disconnectEffectHandle(handle, unpinIfLast)) {
+        return mHandles.size();
+    }
+
     Mutex::Autolock _l(mLock);
     ssize_t numHandles = removeHandle_l(handle);
     if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
-        sp<AudioFlinger> af = mAudioFlinger.promote();
-        if (af != 0) {
-            mLock.unlock();
-            af->updateOrphanEffectChains(this);
-            mLock.lock();
-        }
+        mLock.unlock();
+        mCallback->updateOrphanEffectChains(this);
+        mLock.lock();
     }
     return numHandles;
 }
 
+bool AudioFlinger::EffectBase::purgeHandles()
+{
+    bool enabled = false;
+    Mutex::Autolock _l(mLock);
+    EffectHandle *handle = controlHandle_l();
+    if (handle != NULL) {
+        enabled = handle->enabled();
+    }
+    mHandles.clear();
+    return enabled;
+}
+
+void AudioFlinger::EffectBase::checkSuspendOnEffectEnabled(bool enabled, bool threadLocked) {
+    mCallback->checkSuspendOnEffectEnabled(this, enabled, threadLocked);
+}
+
+static String8 effectFlagsToString(uint32_t flags) {
+    String8 s;
+
+    s.append("conn. mode: ");
+    switch (flags & EFFECT_FLAG_TYPE_MASK) {
+    case EFFECT_FLAG_TYPE_INSERT: s.append("insert"); break;
+    case EFFECT_FLAG_TYPE_AUXILIARY: s.append("auxiliary"); break;
+    case EFFECT_FLAG_TYPE_REPLACE: s.append("replace"); break;
+    case EFFECT_FLAG_TYPE_PRE_PROC: s.append("preproc"); break;
+    case EFFECT_FLAG_TYPE_POST_PROC: s.append("postproc"); break;
+    default: s.append("unknown/reserved"); break;
+    }
+    s.append(", ");
+
+    s.append("insert pref: ");
+    switch (flags & EFFECT_FLAG_INSERT_MASK) {
+    case EFFECT_FLAG_INSERT_ANY: s.append("any"); break;
+    case EFFECT_FLAG_INSERT_FIRST: s.append("first"); break;
+    case EFFECT_FLAG_INSERT_LAST: s.append("last"); break;
+    case EFFECT_FLAG_INSERT_EXCLUSIVE: s.append("exclusive"); break;
+    default: s.append("unknown/reserved"); break;
+    }
+    s.append(", ");
+
+    s.append("volume mgmt: ");
+    switch (flags & EFFECT_FLAG_VOLUME_MASK) {
+    case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
+    case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
+    case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
+    case EFFECT_FLAG_VOLUME_MONITOR: s.append("monitors volume"); break;
+    default: s.append("unknown/reserved"); break;
+    }
+    s.append(", ");
+
+    uint32_t devind = flags & EFFECT_FLAG_DEVICE_MASK;
+    if (devind) {
+        s.append("device indication: ");
+        switch (devind) {
+        case EFFECT_FLAG_DEVICE_IND: s.append("requires updates"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    s.append("input mode: ");
+    switch (flags & EFFECT_FLAG_INPUT_MASK) {
+    case EFFECT_FLAG_INPUT_DIRECT: s.append("direct"); break;
+    case EFFECT_FLAG_INPUT_PROVIDER: s.append("provider"); break;
+    case EFFECT_FLAG_INPUT_BOTH: s.append("direct+provider"); break;
+    default: s.append("not set"); break;
+    }
+    s.append(", ");
+
+    s.append("output mode: ");
+    switch (flags & EFFECT_FLAG_OUTPUT_MASK) {
+    case EFFECT_FLAG_OUTPUT_DIRECT: s.append("direct"); break;
+    case EFFECT_FLAG_OUTPUT_PROVIDER: s.append("provider"); break;
+    case EFFECT_FLAG_OUTPUT_BOTH: s.append("direct+provider"); break;
+    default: s.append("not set"); break;
+    }
+    s.append(", ");
+
+    uint32_t accel = flags & EFFECT_FLAG_HW_ACC_MASK;
+    if (accel) {
+        s.append("hardware acceleration: ");
+        switch (accel) {
+        case EFFECT_FLAG_HW_ACC_SIMPLE: s.append("non-tunneled"); break;
+        case EFFECT_FLAG_HW_ACC_TUNNEL: s.append("tunneled"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    uint32_t modeind = flags & EFFECT_FLAG_AUDIO_MODE_MASK;
+    if (modeind) {
+        s.append("mode indication: ");
+        switch (modeind) {
+        case EFFECT_FLAG_AUDIO_MODE_IND: s.append("required"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    uint32_t srcind = flags & EFFECT_FLAG_AUDIO_SOURCE_MASK;
+    if (srcind) {
+        s.append("source indication: ");
+        switch (srcind) {
+        case EFFECT_FLAG_AUDIO_SOURCE_IND: s.append("required"); break;
+        default: s.append("unknown/reserved"); break;
+        }
+        s.append(", ");
+    }
+
+    if (flags & EFFECT_FLAG_OFFLOAD_MASK) {
+        s.append("offloadable, ");
+    }
+
+    int len = s.length();
+    if (s.length() > 2) {
+        (void) s.lockBuffer(len);
+        s.unlockBuffer(len - 2);
+    }
+    return s;
+}
+
+void AudioFlinger::EffectBase::dump(int fd, const Vector<String16>& args __unused)
+{
+    String8 result;
+
+    result.appendFormat("\tEffect ID %d:\n", mId);
+
+    bool locked = AudioFlinger::dumpTryLock(mLock);
+    // failed to lock - AudioFlinger is probably deadlocked
+    if (!locked) {
+        result.append("\t\tCould not lock Fx mutex:\n");
+    }
+
+    result.append("\t\tSession State Registered Enabled Suspended:\n");
+    result.appendFormat("\t\t%05d   %03d   %s          %s       %s\n",
+            mSessionId, mState, mPolicyRegistered ? "y" : "n",
+            mPolicyEnabled ? "y" : "n", mSuspended ? "y" : "n");
+
+    result.append("\t\tDescriptor:\n");
+    char uuidStr[64];
+    AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+    result.appendFormat("\t\t- UUID: %s\n", uuidStr);
+    AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
+    result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
+    result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
+            mDescriptor.apiVersion,
+            mDescriptor.flags,
+            effectFlagsToString(mDescriptor.flags).string());
+    result.appendFormat("\t\t- name: %s\n",
+            mDescriptor.name);
+
+    result.appendFormat("\t\t- implementor: %s\n",
+            mDescriptor.implementor);
+
+    result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
+    result.append("\t\t\t  Pid Priority Ctrl Locked client server\n");
+    char buffer[256];
+    for (size_t i = 0; i < mHandles.size(); ++i) {
+        EffectHandle *handle = mHandles[i];
+        if (handle != NULL && !handle->disconnected()) {
+            handle->dumpToBuffer(buffer, sizeof(buffer));
+            result.append(buffer);
+        }
+    }
+    if (locked) {
+        mLock.unlock();
+    }
+
+    write(fd, result.string(), result.length());
+}
+
+// ----------------------------------------------------------------------------
+//  EffectModule implementation
+// ----------------------------------------------------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::EffectModule"
+
+AudioFlinger::EffectModule::EffectModule(const sp<AudioFlinger::EffectCallbackInterface>& callback,
+                                         effect_descriptor_t *desc,
+                                         int id,
+                                         audio_session_t sessionId,
+                                         bool pinned,
+                                         audio_port_handle_t deviceId)
+    : EffectBase(callback, desc, id, sessionId, pinned),
+      // clear mConfig to ensure consistent initial value of buffer framecount
+      // in case buffers are associated by setInBuffer() or setOutBuffer()
+      // prior to configure().
+      mConfig{{}, {}},
+      mStatus(NO_INIT),
+      mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
+      mDisableWaitCnt(0),    // set by process() and updateState()
+      mOffloaded(false)
+#ifdef FLOAT_EFFECT_CHAIN
+      , mSupportsFloat(false)
+#endif
+{
+    ALOGV("Constructor %p pinned %d", this, pinned);
+    int lStatus;
+
+    // create effect engine from effect factory
+    mStatus = callback->createEffectHal(
+            &desc->uuid, sessionId, deviceId, &mEffectInterface);
+    if (mStatus != NO_ERROR) {
+        return;
+    }
+    lStatus = init();
+    if (lStatus < 0) {
+        mStatus = lStatus;
+        goto Error;
+    }
+
+    setOffloaded(callback->isOffload(), callback->io());
+    ALOGV("Constructor success name %s, Interface %p", mDescriptor.name, mEffectInterface.get());
+
+    return;
+Error:
+    mEffectInterface.clear();
+    ALOGV("Constructor Error %d", mStatus);
+}
+
+AudioFlinger::EffectModule::~EffectModule()
+{
+    ALOGV("Destructor %p", this);
+    if (mEffectInterface != 0) {
+        char uuidStr[64];
+        AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+        ALOGW("EffectModule %p destructor called with unreleased interface, effect %s",
+                this, uuidStr);
+        release_l();
+    }
+
+}
+
+ssize_t AudioFlinger::EffectModule::removeHandle_l(EffectHandle *handle)
+{
+    ssize_t status = EffectBase::removeHandle_l(handle);
+
+    // Prevent calls to process() and other functions on effect interface from now on.
+    // The effect engine will be released by the destructor when the last strong reference on
+    // this object is released which can happen after next process is called.
+    if (status == 0 && !mPinned) {
+        mEffectInterface->close();
+    }
+
+    return status;
+}
+
 bool AudioFlinger::EffectModule::updateState() {
     Mutex::Autolock _l(mLock);
 
@@ -542,8 +815,7 @@
                 mConfig.inputCfg.buffer.raw != mConfig.outputCfg.buffer.raw) {
         // If an insert effect is idle and input buffer is different from output buffer,
         // accumulate input onto output
-        sp<EffectChain> chain = mChain.promote();
-        if (chain.get() != nullptr && chain->activeTrackCnt() != 0) {
+        if (mCallback->activeTrackCnt() != 0) {
             // similar handling with data_bypass above.
             if (mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
                 accumulateInputToOutput();
@@ -566,7 +838,6 @@
 {
     ALOGVV("configure() started");
     status_t status;
-    sp<ThreadBase> thread;
     uint32_t size;
     audio_channel_mask_t channelMask;
 
@@ -575,17 +846,11 @@
         goto exit;
     }
 
-    thread = mThread.promote();
-    if (thread == 0) {
-        status = DEAD_OBJECT;
-        goto exit;
-    }
-
     // TODO: handle configuration of effects replacing track process
     // TODO: handle configuration of input (record) SW effects above the HAL,
     // similar to output EFFECT_FLAG_TYPE_INSERT/REPLACE,
     // in which case input channel masks should be used here.
-    channelMask = thread->channelMask();
+    channelMask = mCallback->channelMask();
     mConfig.inputCfg.channels = channelMask;
     mConfig.outputCfg.channels = channelMask;
 
@@ -622,11 +887,11 @@
     mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
 
     // Don't use sample rate for thread if effect isn't offloadable.
-    if ((thread->type() == ThreadBase::OFFLOAD) && !isOffloaded()) {
+    if (mCallback->isOffloadOrDirect() && !isOffloaded()) {
         mConfig.inputCfg.samplingRate = DEFAULT_OUTPUT_SAMPLE_RATE;
         ALOGV("Overriding effect input as 48kHz");
     } else {
-        mConfig.inputCfg.samplingRate = thread->sampleRate();
+        mConfig.inputCfg.samplingRate = mCallback->sampleRate();
     }
     mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
     mConfig.inputCfg.bufferProvider.cookie = NULL;
@@ -637,7 +902,7 @@
     mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
     mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
     // Insert effect:
-    // - in session AUDIO_SESSION_OUTPUT_MIX or AUDIO_SESSION_OUTPUT_STAGE,
+    // - in global sessions (e.g AUDIO_SESSION_OUTPUT_MIX),
     // always overwrites output buffer: input buffer == output buffer
     // - in other sessions:
     //      last effect in the chain accumulates in output buffer: input buffer != output buffer
@@ -652,11 +917,13 @@
     }
     mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
     mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
-    mConfig.inputCfg.buffer.frameCount = thread->frameCount();
+    mConfig.inputCfg.buffer.frameCount = mCallback->frameCount();
     mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
 
-    ALOGV("configure() %p thread %p buffer %p framecount %zu",
-            this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
+    ALOGV("configure() %p chain %p buffer %p framecount %zu",
+            this, mCallback->chain().promote() != nullptr ? mCallback->chain().promote().get() :
+                                                            nullptr,
+              mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
 
     status_t cmdStatus;
     size = sizeof(int);
@@ -671,7 +938,7 @@
 
 #ifdef MULTICHANNEL_EFFECT_CHAIN
     if (status != NO_ERROR &&
-            thread->isOutput() &&
+            mCallback->isOutput() &&
             (mConfig.inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO
                     || mConfig.outputCfg.channels != AUDIO_CHANNEL_OUT_STEREO)) {
         // Older effects may require exact STEREO position mask.
@@ -738,11 +1005,7 @@
             size = sizeof(int);
             *(int32_t *)p->data = VISUALIZER_PARAM_LATENCY;
 
-            uint32_t latency = 0;
-            PlaybackThread *pbt = thread->mAudioFlinger->checkPlaybackThread_l(thread->mId);
-            if (pbt != NULL) {
-                latency = pbt->latency_l();
-            }
+            uint32_t latency = mCallback->latency();
 
             *((int32_t *)p->data + 1)= latency;
             mEffectInterface->command(EFFECT_CMD_SET_PARAM,
@@ -789,31 +1052,20 @@
 {
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
          (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
-        sp<ThreadBase> thread = mThread.promote();
-        if (thread != 0) {
-            sp<StreamHalInterface> stream = thread->stream();
-            if (stream != 0) {
-                status_t result = stream->addEffect(mEffectInterface);
-                ALOGE_IF(result != OK, "Error when adding effect: %d", result);
-            }
-        }
+        (void)mCallback->addEffectToHal(mEffectInterface);
     }
 }
 
 // start() must be called with PlaybackThread::mLock or EffectChain::mLock held
 status_t AudioFlinger::EffectModule::start()
 {
-    sp<EffectChain> chain;
     status_t status;
     {
         Mutex::Autolock _l(mLock);
         status = start_l();
-        if (status == NO_ERROR) {
-            chain = mChain.promote();
-        }
     }
-    if (chain != 0) {
-        chain->resetVolume_l();
+    if (status == NO_ERROR) {
+        mCallback->resetVolume();
     }
     return status;
 }
@@ -860,11 +1112,10 @@
     uint32_t size = sizeof(status_t);
 
     if (isVolumeControl() && isOffloadedOrDirect()) {
-        sp<EffectChain>chain = mChain.promote();
         // We have the EffectChain and EffectModule lock, permit a reentrant call to setVolume:
         // resetVolume_l --> setVolume_l --> EffectModule::setVolume
         mSetVolumeReentrantTid = gettid();
-        chain->resetVolume_l();
+        mCallback->resetVolume();
         mSetVolumeReentrantTid = INVALID_PID;
     }
 
@@ -877,7 +1128,7 @@
         status = cmdStatus;
     }
     if (status == NO_ERROR) {
-        status = remove_effect_from_hal_l();
+        status = removeEffectFromHal_l();
     }
     return status;
 }
@@ -886,25 +1137,18 @@
 void AudioFlinger::EffectModule::release_l()
 {
     if (mEffectInterface != 0) {
-        remove_effect_from_hal_l();
+        removeEffectFromHal_l();
         // release effect engine
         mEffectInterface->close();
         mEffectInterface.clear();
     }
 }
 
-status_t AudioFlinger::EffectModule::remove_effect_from_hal_l()
+status_t AudioFlinger::EffectModule::removeEffectFromHal_l()
 {
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
              (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
-        sp<ThreadBase> thread = mThread.promote();
-        if (thread != 0) {
-            sp<StreamHalInterface> stream = thread->stream();
-            if (stream != 0) {
-                status_t result = stream->removeEffect(mEffectInterface);
-                ALOGE_IF(result != OK, "Error when removing effect: %d", result);
-            }
-        }
+        mCallback->removeEffectFromHal(mEffectInterface);
     }
     return NO_ERROR;
 }
@@ -994,70 +1238,6 @@
     return status;
 }
 
-status_t AudioFlinger::EffectModule::setEnabled(bool enabled)
-{
-    Mutex::Autolock _l(mLock);
-    return setEnabled_l(enabled);
-}
-
-// must be called with EffectModule::mLock held
-status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled)
-{
-
-    ALOGV("setEnabled %p enabled %d", this, enabled);
-
-    if (enabled != isEnabled()) {
-        switch (mState) {
-        // going from disabled to enabled
-        case IDLE:
-            mState = STARTING;
-            break;
-        case STOPPED:
-            mState = RESTART;
-            break;
-        case STOPPING:
-            mState = ACTIVE;
-            break;
-
-        // going from enabled to disabled
-        case RESTART:
-            mState = STOPPED;
-            break;
-        case STARTING:
-            mState = IDLE;
-            break;
-        case ACTIVE:
-            mState = STOPPING;
-            break;
-        case DESTROYED:
-            return NO_ERROR; // simply ignore as we are being destroyed
-        }
-        for (size_t i = 1; i < mHandles.size(); i++) {
-            EffectHandle *h = mHandles[i];
-            if (h != NULL && !h->disconnected()) {
-                h->setEnabled(enabled);
-            }
-        }
-    }
-    return NO_ERROR;
-}
-
-bool AudioFlinger::EffectModule::isEnabled() const
-{
-    switch (mState) {
-    case RESTART:
-    case STARTING:
-    case ACTIVE:
-        return true;
-    case IDLE:
-    case STOPPING:
-    case STOPPED:
-    case DESTROYED:
-    default:
-        return false;
-    }
-}
-
 bool AudioFlinger::EffectModule::isProcessEnabled() const
 {
     if (mStatus != NO_ERROR) {
@@ -1080,7 +1260,7 @@
 
 bool AudioFlinger::EffectModule::isOffloadedOrDirect() const
 {
-    return (mThreadType == ThreadBase::OFFLOAD || mThreadType == ThreadBase::DIRECT);
+    return mCallback->isOffloadOrDirect();
 }
 
 bool AudioFlinger::EffectModule::isVolumeControlEnabled() const
@@ -1124,9 +1304,7 @@
                 || size > mInConversionBuffer->getSize())) {
             mInConversionBuffer.clear();
             ALOGV("%s: allocating mInConversionBuffer %zu", __func__, size);
-            sp<AudioFlinger> audioFlinger = mAudioFlinger.promote();
-            LOG_ALWAYS_FATAL_IF(audioFlinger == nullptr, "EM could not retrieved audioFlinger");
-            (void)audioFlinger->mEffectsFactoryHal->allocateBuffer(size, &mInConversionBuffer);
+            (void)mCallback->allocateHalBuffer(size, &mInConversionBuffer);
         }
         if (mInConversionBuffer.get() != nullptr) {
             mInConversionBuffer->setFrameCount(inFrameCount);
@@ -1170,9 +1348,7 @@
                 || size > mOutConversionBuffer->getSize())) {
             mOutConversionBuffer.clear();
             ALOGV("%s: allocating mOutConversionBuffer %zu", __func__, size);
-            sp<AudioFlinger> audioFlinger = mAudioFlinger.promote();
-            LOG_ALWAYS_FATAL_IF(audioFlinger == nullptr, "EM could not retrieved audioFlinger");
-            (void)audioFlinger->mEffectsFactoryHal->allocateBuffer(size, &mOutConversionBuffer);
+            (void)mCallback->allocateHalBuffer(size, &mOutConversionBuffer);
         }
         if (mOutConversionBuffer.get() != nullptr) {
             mOutConversionBuffer->setFrameCount(outFrameCount);
@@ -1220,14 +1396,10 @@
 
 void AudioFlinger::EffectChain::setVolumeForOutput_l(uint32_t left, uint32_t right)
 {
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread != 0 &&
-        (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT) &&
-        !isNonOffloadableEnabled_l()) {
-        PlaybackThread *t = (PlaybackThread *)thread.get();
+    if (mEffectCallback->isOffloadOrDirect() && !isNonOffloadableEnabled_l()) {
         float vol_l = (float)left / (1 << 24);
         float vol_r = (float)right / (1 << 24);
-        t->setVolumeForOutput_l(vol_l, vol_r);
+        mEffectCallback->setVolumeForOutput(vol_l, vol_r);
     }
 }
 
@@ -1307,30 +1479,6 @@
     return status;
 }
 
-void AudioFlinger::EffectModule::setSuspended(bool suspended)
-{
-    Mutex::Autolock _l(mLock);
-    mSuspended = suspended;
-}
-
-bool AudioFlinger::EffectModule::suspended() const
-{
-    Mutex::Autolock _l(mLock);
-    return mSuspended;
-}
-
-bool AudioFlinger::EffectModule::purgeHandles()
-{
-    bool enabled = false;
-    Mutex::Autolock _l(mLock);
-    EffectHandle *handle = controlHandle_l();
-    if (handle != NULL) {
-        enabled = handle->enabled();
-    }
-    mHandles.clear();
-    return enabled;
-}
-
 status_t AudioFlinger::EffectModule::setOffloaded(bool offloaded, audio_io_handle_t io)
 {
     Mutex::Autolock _l(mLock);
@@ -1370,111 +1518,6 @@
     return mOffloaded;
 }
 
-String8 effectFlagsToString(uint32_t flags) {
-    String8 s;
-
-    s.append("conn. mode: ");
-    switch (flags & EFFECT_FLAG_TYPE_MASK) {
-    case EFFECT_FLAG_TYPE_INSERT: s.append("insert"); break;
-    case EFFECT_FLAG_TYPE_AUXILIARY: s.append("auxiliary"); break;
-    case EFFECT_FLAG_TYPE_REPLACE: s.append("replace"); break;
-    case EFFECT_FLAG_TYPE_PRE_PROC: s.append("preproc"); break;
-    case EFFECT_FLAG_TYPE_POST_PROC: s.append("postproc"); break;
-    default: s.append("unknown/reserved"); break;
-    }
-    s.append(", ");
-
-    s.append("insert pref: ");
-    switch (flags & EFFECT_FLAG_INSERT_MASK) {
-    case EFFECT_FLAG_INSERT_ANY: s.append("any"); break;
-    case EFFECT_FLAG_INSERT_FIRST: s.append("first"); break;
-    case EFFECT_FLAG_INSERT_LAST: s.append("last"); break;
-    case EFFECT_FLAG_INSERT_EXCLUSIVE: s.append("exclusive"); break;
-    default: s.append("unknown/reserved"); break;
-    }
-    s.append(", ");
-
-    s.append("volume mgmt: ");
-    switch (flags & EFFECT_FLAG_VOLUME_MASK) {
-    case EFFECT_FLAG_VOLUME_NONE: s.append("none"); break;
-    case EFFECT_FLAG_VOLUME_CTRL: s.append("implements control"); break;
-    case EFFECT_FLAG_VOLUME_IND: s.append("requires indication"); break;
-    case EFFECT_FLAG_VOLUME_MONITOR: s.append("monitors volume"); break;
-    default: s.append("unknown/reserved"); break;
-    }
-    s.append(", ");
-
-    uint32_t devind = flags & EFFECT_FLAG_DEVICE_MASK;
-    if (devind) {
-        s.append("device indication: ");
-        switch (devind) {
-        case EFFECT_FLAG_DEVICE_IND: s.append("requires updates"); break;
-        default: s.append("unknown/reserved"); break;
-        }
-        s.append(", ");
-    }
-
-    s.append("input mode: ");
-    switch (flags & EFFECT_FLAG_INPUT_MASK) {
-    case EFFECT_FLAG_INPUT_DIRECT: s.append("direct"); break;
-    case EFFECT_FLAG_INPUT_PROVIDER: s.append("provider"); break;
-    case EFFECT_FLAG_INPUT_BOTH: s.append("direct+provider"); break;
-    default: s.append("not set"); break;
-    }
-    s.append(", ");
-
-    s.append("output mode: ");
-    switch (flags & EFFECT_FLAG_OUTPUT_MASK) {
-    case EFFECT_FLAG_OUTPUT_DIRECT: s.append("direct"); break;
-    case EFFECT_FLAG_OUTPUT_PROVIDER: s.append("provider"); break;
-    case EFFECT_FLAG_OUTPUT_BOTH: s.append("direct+provider"); break;
-    default: s.append("not set"); break;
-    }
-    s.append(", ");
-
-    uint32_t accel = flags & EFFECT_FLAG_HW_ACC_MASK;
-    if (accel) {
-        s.append("hardware acceleration: ");
-        switch (accel) {
-        case EFFECT_FLAG_HW_ACC_SIMPLE: s.append("non-tunneled"); break;
-        case EFFECT_FLAG_HW_ACC_TUNNEL: s.append("tunneled"); break;
-        default: s.append("unknown/reserved"); break;
-        }
-        s.append(", ");
-    }
-
-    uint32_t modeind = flags & EFFECT_FLAG_AUDIO_MODE_MASK;
-    if (modeind) {
-        s.append("mode indication: ");
-        switch (modeind) {
-        case EFFECT_FLAG_AUDIO_MODE_IND: s.append("required"); break;
-        default: s.append("unknown/reserved"); break;
-        }
-        s.append(", ");
-    }
-
-    uint32_t srcind = flags & EFFECT_FLAG_AUDIO_SOURCE_MASK;
-    if (srcind) {
-        s.append("source indication: ");
-        switch (srcind) {
-        case EFFECT_FLAG_AUDIO_SOURCE_IND: s.append("required"); break;
-        default: s.append("unknown/reserved"); break;
-        }
-        s.append(", ");
-    }
-
-    if (flags & EFFECT_FLAG_OFFLOAD_MASK) {
-        s.append("offloadable, ");
-    }
-
-    int len = s.length();
-    if (s.length() > 2) {
-        (void) s.lockBuffer(len);
-        s.unlockBuffer(len - 2);
-    }
-    return s;
-}
-
 static std::string dumpInOutBuffer(bool isInput, const sp<EffectBufferHalInterface> &buffer) {
     std::stringstream ss;
 
@@ -1490,38 +1533,16 @@
     return ss.str();
 }
 
-void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args __unused)
+void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
 {
+    EffectBase::dump(fd, args);
+
     String8 result;
-
-    result.appendFormat("\tEffect ID %d:\n", mId);
-
     bool locked = AudioFlinger::dumpTryLock(mLock);
-    // failed to lock - AudioFlinger is probably deadlocked
-    if (!locked) {
-        result.append("\t\tCould not lock Fx mutex:\n");
-    }
 
-    result.append("\t\tSession Status State Registered Enabled Suspended Engine:\n");
-    result.appendFormat("\t\t%05d   %03d    %03d   %s          %s       %s         %p\n",
-            mSessionId, mStatus, mState, mPolicyRegistered ? "y" : "n", mPolicyEnabled ? "y" : "n",
-            mSuspended ? "y" : "n", mEffectInterface.get());
-
-    result.append("\t\tDescriptor:\n");
-    char uuidStr[64];
-    AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
-    result.appendFormat("\t\t- UUID: %s\n", uuidStr);
-    AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
-    result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
-    result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
-            mDescriptor.apiVersion,
-            mDescriptor.flags,
-            effectFlagsToString(mDescriptor.flags).string());
-    result.appendFormat("\t\t- name: %s\n",
-            mDescriptor.name);
-
-    result.appendFormat("\t\t- implementor: %s\n",
-            mDescriptor.implementor);
+    result.append("\t\tStatus Engine:\n");
+    result.appendFormat("\t\t%03d    %p\n",
+            mStatus, mEffectInterface.get());
 
     result.appendFormat("\t\t- data: %s\n", mSupportsFloat ? "float" : "int16");
 
@@ -1555,17 +1576,6 @@
             dumpInOutBuffer(false /* isInput */, mOutConversionBuffer).c_str());
 #endif
 
-    result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
-    result.append("\t\t\t  Pid Priority Ctrl Locked client server\n");
-    char buffer[256];
-    for (size_t i = 0; i < mHandles.size(); ++i) {
-        EffectHandle *handle = mHandles[i];
-        if (handle != NULL && !handle->disconnected()) {
-            handle->dumpToBuffer(buffer, sizeof(buffer));
-            result.append(buffer);
-        }
-    }
-
     write(fd, result.string(), result.length());
 
     if (mEffectInterface != 0) {
@@ -1585,7 +1595,7 @@
 #undef LOG_TAG
 #define LOG_TAG "AudioFlinger::EffectHandle"
 
-AudioFlinger::EffectHandle::EffectHandle(const sp<EffectModule>& effect,
+AudioFlinger::EffectHandle::EffectHandle(const sp<EffectBase>& effect,
                                         const sp<AudioFlinger::Client>& client,
                                         const sp<IEffectClient>& effectClient,
                                         int32_t priority)
@@ -1593,7 +1603,7 @@
     mEffect(effect), mEffectClient(effectClient), mClient(client), mCblk(NULL),
     mPriority(priority), mHasControl(false), mEnabled(false), mDisconnected(false)
 {
-    ALOGV("constructor %p", this);
+    ALOGV("constructor %p client %p", this, client.get());
 
     if (client == 0) {
         return;
@@ -1626,7 +1636,7 @@
 {
     AutoMutex _l(mLock);
     ALOGV("enable %p", this);
-    sp<EffectModule> effect = mEffect.promote();
+    sp<EffectBase> effect = mEffect.promote();
     if (effect == 0 || mDisconnected) {
         return DEAD_OBJECT;
     }
@@ -1646,38 +1656,16 @@
         return status;
     }
 
-    sp<ThreadBase> thread = effect->thread().promote();
-    if (thread != 0) {
-        thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId());
-    }
+    effect->checkSuspendOnEffectEnabled(true, false /*threadLocked*/);
 
     // checkSuspendOnEffectEnabled() can suspend this same effect when enabled
     if (effect->suspended()) {
         return NO_ERROR;
     }
 
-    status = effect->setEnabled(true);
+    status = effect->setEnabled(true, true /*fromHandle*/);
     if (status != NO_ERROR) {
-        if (thread != 0) {
-            thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
-        }
         mEnabled = false;
-    } else {
-        if (thread != 0) {
-            if (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::MMAP) {
-                Mutex::Autolock _l(thread->mLock);
-                thread->broadcast_l();
-            }
-            if (!effect->isOffloadable()) {
-                if (thread->type() == ThreadBase::OFFLOAD) {
-                    PlaybackThread *t = (PlaybackThread *)thread.get();
-                    t->invalidateTracks(AUDIO_STREAM_MUSIC);
-                }
-                if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
-                    thread->mAudioFlinger->onNonOffloadableGlobalEffectEnable();
-                }
-            }
-        }
     }
     return status;
 }
@@ -1686,7 +1674,7 @@
 {
     ALOGV("disable %p", this);
     AutoMutex _l(mLock);
-    sp<EffectModule> effect = mEffect.promote();
+    sp<EffectBase> effect = mEffect.promote();
     if (effect == 0 || mDisconnected) {
         return DEAD_OBJECT;
     }
@@ -1705,17 +1693,7 @@
         return NO_ERROR;
     }
 
-    status_t status = effect->setEnabled(false);
-
-    sp<ThreadBase> thread = effect->thread().promote();
-    if (thread != 0) {
-        thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
-        if (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::MMAP) {
-            Mutex::Autolock _l(thread->mLock);
-            thread->broadcast_l();
-        }
-    }
-
+    status_t status = effect->setEnabled(false, true /*fromHandle*/);
     return status;
 }
 
@@ -1737,12 +1715,9 @@
     }
     mDisconnected = true;
     {
-        sp<EffectModule> effect = mEffect.promote();
+        sp<EffectBase> effect = mEffect.promote();
         if (effect != 0) {
-            sp<ThreadBase> thread = effect->thread().promote();
-            if (thread != 0) {
-                thread->disconnectEffectHandle(this, unpinIfLast);
-            } else if (effect->disconnectHandle(this, unpinIfLast) > 0) {
+            if (effect->disconnectHandle(this, unpinIfLast) > 0) {
                 ALOGW("%s Effect handle %p disconnected after thread destruction",
                     __func__, this);
             }
@@ -1808,7 +1783,7 @@
     }
 
     AutoMutex _l(mLock);
-    sp<EffectModule> effect = mEffect.promote();
+    sp<EffectBase> effect = mEffect.promote();
     if (effect == 0 || mDisconnected) {
         return DEAD_OBJECT;
     }
@@ -1816,12 +1791,13 @@
     if (!mHasControl && cmdCode != EFFECT_CMD_GET_PARAM) {
         return INVALID_OPERATION;
     }
-    if (mClient == 0) {
-        return INVALID_OPERATION;
-    }
 
     // handle commands that are not forwarded transparently to effect engine
     if (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) {
+        if (mClient == 0) {
+            return INVALID_OPERATION;
+        }
+
         if (*replySize < sizeof(int)) {
             android_errorWriteLog(0x534e4554, "32095713");
             return BAD_VALUE;
@@ -1856,12 +1832,13 @@
             }
 
             // copy to local memory in case of client corruption b/32220769
-            param = (effect_param_t *)realloc(param, size);
-            if (param == NULL) {
+            auto *newParam = (effect_param_t *)realloc(param, size);
+            if (newParam == NULL) {
                 ALOGW("command(): out of memory");
                 status = NO_MEMORY;
                 break;
             }
+            param = newParam;
             memcpy(param, p, size);
 
             int reply = 0;
@@ -1962,12 +1939,13 @@
 
 AudioFlinger::EffectChain::EffectChain(ThreadBase *thread,
                                         audio_session_t sessionId)
-    : mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
+    : mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
       mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
-      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
+      mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX),
+      mEffectCallback(new EffectCallback(this, thread, thread->mAudioFlinger.get()))
 {
     mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
-    if (thread == NULL) {
+    if (thread == nullptr) {
         return;
     }
     mMaxTailBuffers = ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
@@ -2033,43 +2011,30 @@
 void AudioFlinger::EffectChain::clearInputBuffer()
 {
     Mutex::Autolock _l(mLock);
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread == 0) {
-        ALOGW("clearInputBuffer(): cannot promote mixer thread");
-        return;
-    }
-    clearInputBuffer_l(thread);
+    clearInputBuffer_l();
 }
 
 // Must be called with EffectChain::mLock locked
-void AudioFlinger::EffectChain::clearInputBuffer_l(const sp<ThreadBase>& thread)
+void AudioFlinger::EffectChain::clearInputBuffer_l()
 {
     if (mInBuffer == NULL) {
         return;
     }
     const size_t frameSize =
-            audio_bytes_per_sample(EFFECT_BUFFER_FORMAT) * thread->channelCount();
+            audio_bytes_per_sample(EFFECT_BUFFER_FORMAT) * mEffectCallback->channelCount();
 
-    memset(mInBuffer->audioBuffer()->raw, 0, thread->frameCount() * frameSize);
+    memset(mInBuffer->audioBuffer()->raw, 0, mEffectCallback->frameCount() * frameSize);
     mInBuffer->commit();
 }
 
 // Must be called with EffectChain::mLock locked
 void AudioFlinger::EffectChain::process_l()
 {
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread == 0) {
-        ALOGW("process_l(): cannot promote mixer thread");
-        return;
-    }
-    bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
-            (mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
     // never process effects when:
     // - on an OFFLOAD thread
     // - no more tracks are on the session and the effect tail has been rendered
-    bool doProcess = (thread->type() != ThreadBase::OFFLOAD)
-                  && (thread->type() != ThreadBase::MMAP);
-    if (!isGlobalSession) {
+    bool doProcess = !mEffectCallback->isOffloadOrMmap();
+    if (!audio_is_global_session(mSessionId)) {
         bool tracksOnSession = (trackCnt() != 0);
 
         if (!tracksOnSession && mTailBufferCount == 0) {
@@ -2080,7 +2045,7 @@
             // if no track is active and the effect tail has not been rendered,
             // the input buffer must be cleared here as the mixer process will not do it
             if (tracksOnSession || mTailBufferCount > 0) {
-                clearInputBuffer_l(thread);
+                clearInputBuffer_l();
                 if (mTailBufferCount > 0) {
                     mTailBufferCount--;
                 }
@@ -2116,14 +2081,13 @@
 
 // createEffect_l() must be called with ThreadBase::mLock held
 status_t AudioFlinger::EffectChain::createEffect_l(sp<EffectModule>& effect,
-                                                   ThreadBase *thread,
                                                    effect_descriptor_t *desc,
                                                    int id,
                                                    audio_session_t sessionId,
                                                    bool pinned)
 {
     Mutex::Autolock _l(mLock);
-    effect = new EffectModule(thread, this, desc, id, sessionId, pinned);
+    effect = new EffectModule(mEffectCallback, desc, id, sessionId, pinned, AUDIO_PORT_HANDLE_NONE);
     status_t lStatus = effect->status();
     if (lStatus == NO_ERROR) {
         lStatus = addEffect_ll(effect);
@@ -2146,12 +2110,7 @@
     effect_descriptor_t desc = effect->desc();
     uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK;
 
-    effect->setChain(this);
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread == 0) {
-        return NO_INIT;
-    }
-    effect->setThread(thread);
+    effect->setCallback(mEffectCallback);
 
     if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
         // Auxiliary effects are inserted at the beginning of mEffects vector as
@@ -2162,13 +2121,13 @@
         // 32 bit format. This is to avoid saturation in AudoMixer
         // accumulation stage. Saturation is done in EffectModule::process() before
         // calling the process in effect engine
-        size_t numSamples = thread->frameCount();
+        size_t numSamples = mEffectCallback->frameCount();
         sp<EffectBufferHalInterface> halBuffer;
 #ifdef FLOAT_EFFECT_CHAIN
-        status_t result = thread->mAudioFlinger->mEffectsFactoryHal->allocateBuffer(
+        status_t result = mEffectCallback->allocateHalBuffer(
                 numSamples * sizeof(float), &halBuffer);
 #else
-        status_t result = thread->mAudioFlinger->mEffectsFactoryHal->allocateBuffer(
+        status_t result = mEffectCallback->allocateHalBuffer(
                 numSamples * sizeof(int32_t), &halBuffer);
 #endif
         if (result != OK) return result;
@@ -2486,7 +2445,7 @@
             if (effect != 0) {
                 desc->mEffect = effect;
                 effect->setSuspended(true);
-                effect->setEnabled(false);
+                effect->setEnabled(false, false /*fromHandle*/);
             }
         }
     } else {
@@ -2644,7 +2603,7 @@
         // if effect is requested to suspended but was not yet enabled, suspend it now.
         if (desc->mEffect == 0) {
             desc->mEffect = effect;
-            effect->setEnabled(false);
+            effect->setEnabled(false, false /*fromHandle*/);
             effect->setSuspended(true);
         }
     } else {
@@ -2679,10 +2638,7 @@
 void AudioFlinger::EffectChain::setThread(const sp<ThreadBase>& thread)
 {
     Mutex::Autolock _l(mLock);
-    mThread = thread;
-    for (size_t i = 0; i < mEffects.size(); i++) {
-        mEffects[i]->setThread(thread);
-    }
+    mEffectCallback->setThread(thread.get());
 }
 
 void AudioFlinger::EffectChain::checkOutputFlagCompatibility(audio_output_flags_t *flags) const
@@ -2742,4 +2698,549 @@
     return true;
 }
 
+// EffectCallbackInterface implementation
+status_t AudioFlinger::EffectChain::EffectCallback::createEffectHal(
+        const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
+        sp<EffectHalInterface> *effect) {
+    status_t status = NO_INIT;
+    sp<AudioFlinger> af = mAudioFlinger.promote();
+    if (af == nullptr) {
+        return status;
+    }
+    sp<EffectsFactoryHalInterface> effectsFactory = af->getEffectsFactory();
+    if (effectsFactory != 0) {
+        status = effectsFactory->createEffect(pEffectUuid, sessionId, io(), deviceId, effect);
+    }
+    return status;
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::updateOrphanEffectChains(
+        const sp<AudioFlinger::EffectBase>& effect) {
+    sp<AudioFlinger> af = mAudioFlinger.promote();
+    if (af == nullptr) {
+        return false;
+    }
+    // in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
+    return af->updateOrphanEffectChains(effect->asEffectModule());
+}
+
+status_t AudioFlinger::EffectChain::EffectCallback::allocateHalBuffer(
+        size_t size, sp<EffectBufferHalInterface>* buffer) {
+    sp<AudioFlinger> af = mAudioFlinger.promote();
+    LOG_ALWAYS_FATAL_IF(af == nullptr, "allocateHalBuffer() could not retrieved audio flinger");
+    return af->mEffectsFactoryHal->allocateBuffer(size, buffer);
+}
+
+status_t AudioFlinger::EffectChain::EffectCallback::addEffectToHal(
+        sp<EffectHalInterface> effect) {
+    status_t result = NO_INIT;
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return result;
+    }
+    sp <StreamHalInterface> st = t->stream();
+    if (st == nullptr) {
+        return result;
+    }
+    result = st->addEffect(effect);
+    ALOGE_IF(result != OK, "Error when adding effect: %d", result);
+    return result;
+}
+
+status_t AudioFlinger::EffectChain::EffectCallback::removeEffectFromHal(
+        sp<EffectHalInterface> effect) {
+    status_t result = NO_INIT;
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return result;
+    }
+    sp <StreamHalInterface> st = t->stream();
+    if (st == nullptr) {
+        return result;
+    }
+    result = st->removeEffect(effect);
+    ALOGE_IF(result != OK, "Error when removing effect: %d", result);
+    return result;
+}
+
+audio_io_handle_t AudioFlinger::EffectChain::EffectCallback::io() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return AUDIO_IO_HANDLE_NONE;
+    }
+    return t->id();
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOutput() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return true;
+    }
+    return t->isOutput();
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOffload() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return false;
+    }
+    return t->type() == ThreadBase::OFFLOAD;
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOffloadOrDirect() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return false;
+    }
+    return t->type() == ThreadBase::OFFLOAD || t->type() == ThreadBase::DIRECT;
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::isOffloadOrMmap() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return false;
+    }
+    return t->type() == ThreadBase::OFFLOAD || t->type() == ThreadBase::MMAP;
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::sampleRate() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return 0;
+    }
+    return t->sampleRate();
+}
+
+audio_channel_mask_t AudioFlinger::EffectChain::EffectCallback::channelMask() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return AUDIO_CHANNEL_NONE;
+    }
+    return t->channelMask();
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::channelCount() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return 0;
+    }
+    return t->channelCount();
+}
+
+size_t AudioFlinger::EffectChain::EffectCallback::frameCount() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return 0;
+    }
+    return t->frameCount();
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::latency() const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return 0;
+    }
+    return t->latency_l();
+}
+
+void AudioFlinger::EffectChain::EffectCallback::setVolumeForOutput(float left, float right) const {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return;
+    }
+    t->setVolumeForOutput_l(left, right);
+}
+
+void AudioFlinger::EffectChain::EffectCallback::checkSuspendOnEffectEnabled(
+        const sp<EffectBase>& effect, bool enabled, bool threadLocked) {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return;
+    }
+    t->checkSuspendOnEffectEnabled(enabled, effect->sessionId(), threadLocked);
+
+    sp<EffectChain> c = mChain.promote();
+    if (c == nullptr) {
+        return;
+    }
+    // in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
+    c->checkSuspendOnEffectEnabled(effect->asEffectModule(), enabled);
+}
+
+void AudioFlinger::EffectChain::EffectCallback::onEffectEnable(const sp<EffectBase>& effect) {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return;
+    }
+    // in EffectChain context, an EffectBase is always from an EffectModule so static cast is safe
+    t->onEffectEnable(effect->asEffectModule());
+}
+
+void AudioFlinger::EffectChain::EffectCallback::onEffectDisable(const sp<EffectBase>& effect) {
+    checkSuspendOnEffectEnabled(effect, false, false /*threadLocked*/);
+
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return;
+    }
+    t->onEffectDisable();
+}
+
+bool AudioFlinger::EffectChain::EffectCallback::disconnectEffectHandle(EffectHandle *handle,
+                                                      bool unpinIfLast) {
+    sp<ThreadBase> t = mThread.promote();
+    if (t == nullptr) {
+        return false;
+    }
+    t->disconnectEffectHandle(handle, unpinIfLast);
+    return true;
+}
+
+void AudioFlinger::EffectChain::EffectCallback::resetVolume() {
+    sp<EffectChain> c = mChain.promote();
+    if (c == nullptr) {
+        return;
+    }
+    c->resetVolume_l();
+
+}
+
+uint32_t AudioFlinger::EffectChain::EffectCallback::strategy() const {
+    sp<EffectChain> c = mChain.promote();
+    if (c == nullptr) {
+        return PRODUCT_STRATEGY_NONE;
+    }
+    return c->strategy();
+}
+
+int32_t AudioFlinger::EffectChain::EffectCallback::activeTrackCnt() const {
+    sp<EffectChain> c = mChain.promote();
+    if (c == nullptr) {
+        return 0;
+    }
+    return c->activeTrackCnt();
+}
+
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::DeviceEffectProxy"
+
+status_t AudioFlinger::DeviceEffectProxy::setEnabled(bool enabled, bool fromHandle)
+{
+    status_t status = EffectBase::setEnabled(enabled, fromHandle);
+    Mutex::Autolock _l(mProxyLock);
+    if (status == NO_ERROR) {
+        for (auto& handle : mEffectHandles) {
+            if (enabled) {
+                status = handle.second->enable();
+            } else {
+                status = handle.second->disable();
+            }
+        }
+    }
+    ALOGV("%s enable %d status %d", __func__, enabled, status);
+    return status;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::init(
+        const std::map <audio_patch_handle_t, PatchPanel::Patch>& patches) {
+//For all audio patches
+//If src or sink device match
+//If the effect is HW accelerated
+//	if no corresponding effect module
+//		Create EffectModule: mHalEffect
+//Create and attach EffectHandle
+//If the effect is not HW accelerated and the patch sink or src is a mixer port
+//	Create Effect on patch input or output thread on session -1
+//Add EffectHandle to EffectHandle map of Effect Proxy:
+    ALOGV("%s device type %d address %s", __func__,  mDevice.mType, mDevice.getAddress());
+    status_t status = NO_ERROR;
+    for (auto &patch : patches) {
+        status = onCreatePatch(patch.first, patch.second);
+        ALOGV("%s onCreatePatch status %d", __func__, status);
+        if (status == BAD_VALUE) {
+            return status;
+        }
+    }
+    return status;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::onCreatePatch(
+        audio_patch_handle_t patchHandle, const AudioFlinger::PatchPanel::Patch& patch) {
+    status_t status = NAME_NOT_FOUND;
+    sp<EffectHandle> handle;
+    // only consider source[0] as this is the only "true" source of a patch
+    status = checkPort(patch, &patch.mAudioPatch.sources[0], &handle);
+    ALOGV("%s source checkPort status %d", __func__, status);
+    for (uint32_t i = 0; i < patch.mAudioPatch.num_sinks && status == NAME_NOT_FOUND; i++) {
+        status = checkPort(patch, &patch.mAudioPatch.sinks[i], &handle);
+        ALOGV("%s sink %d checkPort status %d", __func__, i, status);
+    }
+    if (status == NO_ERROR || status == ALREADY_EXISTS) {
+        Mutex::Autolock _l(mProxyLock);
+        mEffectHandles.emplace(patchHandle, handle);
+    }
+    ALOGW_IF(status == BAD_VALUE,
+            "%s cannot attach effect %s on patch %d", __func__, mDescriptor.name, patchHandle);
+
+    return status;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::checkPort(const PatchPanel::Patch& patch,
+        const struct audio_port_config *port, sp <EffectHandle> *handle) {
+
+    ALOGV("%s type %d device type %d address %s device ID %d patch.isSoftware() %d",
+            __func__, port->type, port->ext.device.type,
+            port->ext.device.address, port->id, patch.isSoftware());
+    if (port->type != AUDIO_PORT_TYPE_DEVICE || port->ext.device.type != mDevice.mType
+        || port->ext.device.address != mDevice.mAddress) {
+        return NAME_NOT_FOUND;
+    }
+    status_t status = NAME_NOT_FOUND;
+
+    if (mDescriptor.flags & EFFECT_FLAG_HW_ACC_TUNNEL) {
+        Mutex::Autolock _l(mProxyLock);
+        mDevicePort = *port;
+        mHalEffect = new EffectModule(mMyCallback,
+                                      const_cast<effect_descriptor_t *>(&mDescriptor),
+                                      mMyCallback->newEffectId(), AUDIO_SESSION_DEVICE,
+                                      false /* pinned */, port->id);
+        if (audio_is_input_device(mDevice.mType)) {
+            mHalEffect->setInputDevice(mDevice);
+        } else {
+            mHalEffect->setDevices({mDevice});
+        }
+        *handle = new EffectHandle(mHalEffect, nullptr, nullptr, 0 /*priority*/);
+        status = (*handle)->initCheck();
+        if (status == OK) {
+            status = mHalEffect->addHandle((*handle).get());
+        } else {
+            mHalEffect.clear();
+            mDevicePort.id = AUDIO_PORT_HANDLE_NONE;
+        }
+    } else if (patch.isSoftware() || patch.thread().promote() != nullptr) {
+        sp <ThreadBase> thread;
+        if (audio_port_config_has_input_direction(port)) {
+            if (patch.isSoftware()) {
+                thread = patch.mRecord.thread();
+            } else {
+                thread = patch.thread().promote();
+            }
+        } else {
+            if (patch.isSoftware()) {
+                thread = patch.mPlayback.thread();
+            } else {
+                thread = patch.thread().promote();
+            }
+        }
+        int enabled;
+        *handle = thread->createEffect_l(nullptr, nullptr, 0, AUDIO_SESSION_DEVICE,
+                                         const_cast<effect_descriptor_t *>(&mDescriptor),
+                                         &enabled, &status, false);
+        ALOGV("%s thread->createEffect_l status %d", __func__, status);
+    } else {
+        status = BAD_VALUE;
+    }
+    if (status == NO_ERROR || status == ALREADY_EXISTS) {
+        if (isEnabled()) {
+            (*handle)->enable();
+        } else {
+            (*handle)->disable();
+        }
+    }
+    return status;
+}
+
+void AudioFlinger::DeviceEffectProxy::onReleasePatch(audio_patch_handle_t patchHandle) {
+    Mutex::Autolock _l(mProxyLock);
+    mEffectHandles.erase(patchHandle);
+}
+
+
+size_t AudioFlinger::DeviceEffectProxy::removeEffect(const sp<EffectModule>& effect)
+{
+    Mutex::Autolock _l(mProxyLock);
+    if (effect == mHalEffect) {
+        mHalEffect.clear();
+        mDevicePort.id = AUDIO_PORT_HANDLE_NONE;
+    }
+    return mHalEffect == nullptr ? 0 : 1;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::addEffectToHal(
+    sp<EffectHalInterface> effect) {
+    if (mHalEffect == nullptr) {
+        return NO_INIT;
+    }
+    return mManagerCallback->addEffectToHal(
+            mDevicePort.id, mDevicePort.ext.device.hw_module, effect);
+}
+
+status_t AudioFlinger::DeviceEffectProxy::removeEffectFromHal(
+    sp<EffectHalInterface> effect) {
+    if (mHalEffect == nullptr) {
+        return NO_INIT;
+    }
+    return mManagerCallback->removeEffectFromHal(
+            mDevicePort.id, mDevicePort.ext.device.hw_module, effect);
+}
+
+bool AudioFlinger::DeviceEffectProxy::isOutput() const {
+    if (mDevicePort.id != AUDIO_PORT_HANDLE_NONE) {
+        return mDevicePort.role == AUDIO_PORT_ROLE_SINK;
+    }
+    return true;
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::sampleRate() const {
+    if (mDevicePort.id != AUDIO_PORT_HANDLE_NONE &&
+            (mDevicePort.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) != 0) {
+        return mDevicePort.sample_rate;
+    }
+    return DEFAULT_OUTPUT_SAMPLE_RATE;
+}
+
+audio_channel_mask_t AudioFlinger::DeviceEffectProxy::channelMask() const {
+    if (mDevicePort.id != AUDIO_PORT_HANDLE_NONE &&
+            (mDevicePort.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) != 0) {
+        return mDevicePort.channel_mask;
+    }
+    return AUDIO_CHANNEL_OUT_STEREO;
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::channelCount() const {
+    if (isOutput()) {
+        return audio_channel_count_from_out_mask(channelMask());
+    }
+    return audio_channel_count_from_in_mask(channelMask());
+}
+
+void AudioFlinger::DeviceEffectProxy::dump(int fd, int spaces) {
+    const Vector<String16> args;
+    EffectBase::dump(fd, args);
+
+    const bool locked = dumpTryLock(mProxyLock);
+    if (!locked) {
+        String8 result("DeviceEffectProxy may be deadlocked\n");
+        write(fd, result.string(), result.size());
+    }
+
+    String8 outStr;
+    if (mHalEffect != nullptr) {
+        outStr.appendFormat("%*sHAL Effect Id: %d\n", spaces, "", mHalEffect->id());
+    } else {
+        outStr.appendFormat("%*sNO HAL Effect\n", spaces, "");
+    }
+    write(fd, outStr.string(), outStr.size());
+    outStr.clear();
+
+    outStr.appendFormat("%*sSub Effects:\n", spaces, "");
+    write(fd, outStr.string(), outStr.size());
+    outStr.clear();
+
+    for (const auto& iter : mEffectHandles) {
+        outStr.appendFormat("%*sEffect for patch handle %d:\n", spaces + 2, "", iter.first);
+        write(fd, outStr.string(), outStr.size());
+        outStr.clear();
+        sp<EffectBase> effect = iter.second->effect().promote();
+        if (effect != nullptr) {
+            effect->dump(fd, args);
+        }
+    }
+
+    if (locked) {
+        mLock.unlock();
+    }
+}
+
+#undef LOG_TAG
+#define LOG_TAG "AudioFlinger::DeviceEffectProxy::ProxyCallback"
+
+int AudioFlinger::DeviceEffectProxy::ProxyCallback::newEffectId() {
+    return mManagerCallback->newEffectId();
+}
+
+
+bool AudioFlinger::DeviceEffectProxy::ProxyCallback::disconnectEffectHandle(
+        EffectHandle *handle, bool unpinIfLast) {
+    sp<EffectBase> effectBase = handle->effect().promote();
+    if (effectBase == nullptr) {
+        return false;
+    }
+
+    sp<EffectModule> effect = effectBase->asEffectModule();
+    if (effect == nullptr) {
+        return false;
+    }
+
+    // restore suspended effects if the disconnected handle was enabled and the last one.
+    bool remove = (effect->removeHandle(handle) == 0) && (!effect->isPinned() || unpinIfLast);
+    if (remove) {
+        sp<DeviceEffectProxy> proxy = mProxy.promote();
+        if (proxy != nullptr) {
+            proxy->removeEffect(effect);
+        }
+        if (handle->enabled()) {
+            effectBase->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
+        }
+    }
+    return true;
+}
+
+status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::createEffectHal(
+        const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
+        sp<EffectHalInterface> *effect) {
+    return mManagerCallback->createEffectHal(pEffectUuid, sessionId, deviceId, effect);
+}
+
+status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::addEffectToHal(
+        sp<EffectHalInterface> effect) {
+    sp<DeviceEffectProxy> proxy = mProxy.promote();
+    if (proxy == nullptr) {
+        return NO_INIT;
+    }
+    return proxy->addEffectToHal(effect);
+}
+
+status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::removeEffectFromHal(
+        sp<EffectHalInterface> effect) {
+    sp<DeviceEffectProxy> proxy = mProxy.promote();
+    if (proxy == nullptr) {
+        return NO_INIT;
+    }
+    return proxy->addEffectToHal(effect);
+}
+
+bool AudioFlinger::DeviceEffectProxy::ProxyCallback::isOutput() const {
+    sp<DeviceEffectProxy> proxy = mProxy.promote();
+    if (proxy == nullptr) {
+        return true;
+    }
+    return proxy->isOutput();
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::ProxyCallback::sampleRate() const {
+    sp<DeviceEffectProxy> proxy = mProxy.promote();
+    if (proxy == nullptr) {
+        return DEFAULT_OUTPUT_SAMPLE_RATE;
+    }
+    return proxy->sampleRate();
+}
+
+audio_channel_mask_t AudioFlinger::DeviceEffectProxy::ProxyCallback::channelMask() const {
+    sp<DeviceEffectProxy> proxy = mProxy.promote();
+    if (proxy == nullptr) {
+        return AUDIO_CHANNEL_OUT_STEREO;
+    }
+    return proxy->channelMask();
+}
+
+uint32_t AudioFlinger::DeviceEffectProxy::ProxyCallback::channelCount() const {
+    sp<DeviceEffectProxy> proxy = mProxy.promote();
+    if (proxy == nullptr) {
+        return 2;
+    }
+    return proxy->channelCount();
+}
+
 } // namespace android
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index dbf63c8..40bb226 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -21,34 +21,78 @@
 
 //--- Audio Effect Management
 
-// EffectModule and EffectChain classes both have their own mutex to protect
+// Interface implemented by the EffectModule parent or owner (e.g an EffectChain) to abstract
+// interactions between the EffectModule and the reset of the audio framework.
+class EffectCallbackInterface : public RefBase {
+public:
+            ~EffectCallbackInterface() override = default;
+
+    // Trivial methods usually implemented with help from ThreadBase
+    virtual audio_io_handle_t io() const = 0;
+    virtual bool isOutput() const = 0;
+    virtual bool isOffload() const = 0;
+    virtual bool isOffloadOrDirect() const = 0;
+    virtual bool isOffloadOrMmap() const = 0;
+    virtual uint32_t sampleRate() const = 0;
+    virtual audio_channel_mask_t channelMask() const = 0;
+    virtual uint32_t channelCount() const = 0;
+    virtual size_t frameCount() const = 0;
+
+    // Non trivial methods usually implemented with help from ThreadBase:
+    //   pay attention to mutex locking order
+    virtual uint32_t latency() const { return 0; }
+    virtual status_t addEffectToHal(sp<EffectHalInterface> effect) = 0;
+    virtual status_t removeEffectFromHal(sp<EffectHalInterface> effect) = 0;
+    virtual void setVolumeForOutput(float left, float right) const = 0;
+    virtual bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) = 0;
+    virtual void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect,
+                                             bool enabled,
+                                             bool threadLocked) = 0;
+    virtual void onEffectEnable(const sp<EffectBase>& effect) = 0;
+    virtual void onEffectDisable(const sp<EffectBase>& effect) = 0;
+
+    // Methods usually implemented with help from AudioFlinger: pay attention to mutex locking order
+    virtual status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+                    int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) = 0;
+    virtual status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) = 0;
+    virtual bool updateOrphanEffectChains(const sp<EffectBase>& effect) = 0;
+
+    // Methods usually implemented with help from EffectChain: pay attention to mutex locking order
+    virtual uint32_t strategy() const = 0;
+    virtual int32_t activeTrackCnt() const = 0;
+    virtual void resetVolume() = 0;
+
+    virtual wp<EffectChain> chain() const = 0;
+};
+
+// EffectBase(EffectModule) and EffectChain classes both have their own mutex to protect
 // state changes or resource modifications. Always respect the following order
 // if multiple mutexes must be acquired to avoid cross deadlock:
-// AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
-// AudioHandle -> ThreadBase -> EffectChain -> EffectModule
+// AudioFlinger -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
+// AudioHandle -> ThreadBase -> EffectChain -> EffectBase(EffectModule)
+
+// NOTE: When implementing the EffectCallbackInterface, in an EffectChain or other, it is important
+// to pay attention to this locking order as some callback methods can be called from a state where
+// EffectModule and/or EffectChain mutexes are held.
+
 // In addition, methods that lock the AudioPolicyService mutex (getOutputForEffect(),
 // startOutput(), getInputForAttr(), releaseInput()...) should never be called with AudioFlinger or
 // Threadbase mutex locked to avoid cross deadlock with other clients calling AudioPolicyService
 // methods that in turn call AudioFlinger thus locking the same mutexes in the reverse order.
 
-// The EffectModule class is a wrapper object controlling the effect engine implementation
-// in the effect library. It prevents concurrent calls to process() and command() functions
-// from different client threads. It keeps a list of EffectHandle objects corresponding
-// to all client applications using this effect and notifies applications of effect state,
-// control or parameter changes. It manages the activation state machine to send appropriate
-// reset, enable, disable commands to effect engine and provide volume
-// ramping when effects are activated/deactivated.
-// When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
-// the attached track(s) to accumulate their auxiliary channel.
-class EffectModule : public RefBase {
+
+// The EffectBase class contains common properties, state and behavior for and EffectModule or
+// other derived classes managing an audio effect instance within the effect framework.
+// It also contains the class mutex (see comment on locking order above).
+class EffectBase : public RefBase {
 public:
-    EffectModule(ThreadBase *thread,
-                    const wp<AudioFlinger::EffectChain>& chain,
-                    effect_descriptor_t *desc,
-                    int id,
-                    audio_session_t sessionId,
-                    bool pinned);
-    virtual ~EffectModule();
+    EffectBase(const sp<EffectCallbackInterface>& callback,
+               effect_descriptor_t *desc,
+               int id,
+               audio_session_t sessionId,
+               bool pinned);
+
+    ~EffectBase() override = default;
 
     enum effect_state {
         IDLE,
@@ -60,72 +104,14 @@
         DESTROYED
     };
 
-    int         id() const { return mId; }
-    void process();
-    bool updateState();
-    status_t command(uint32_t cmdCode,
-                     uint32_t cmdSize,
-                     void *pCmdData,
-                     uint32_t *replySize,
-                     void *pReplyData);
-
-    void reset_l();
-    status_t configure();
-    status_t init();
+    int id() const { return mId; }
     effect_state state() const {
         return mState;
     }
-    uint32_t status() {
-        return mStatus;
-    }
     audio_session_t sessionId() const {
         return mSessionId;
     }
-    status_t    setEnabled(bool enabled);
-    status_t    setEnabled_l(bool enabled);
-    bool isEnabled() const;
-    bool isProcessEnabled() const;
-    bool isOffloadedOrDirect() const;
-    bool isVolumeControlEnabled() const;
-
-    void        setInBuffer(const sp<EffectBufferHalInterface>& buffer);
-    int16_t     *inBuffer() const {
-        return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
-    }
-    void        setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
-    int16_t     *outBuffer() const {
-        return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
-    }
-    void        setChain(const wp<EffectChain>& chain) { mChain = chain; }
-    void        setThread(const wp<ThreadBase>& thread)
-                    { mThread = thread; mThreadType = thread.promote()->type(); }
-    const wp<ThreadBase>& thread() { return mThread; }
-
-    status_t addHandle(EffectHandle *handle);
-    ssize_t  disconnectHandle(EffectHandle *handle, bool unpinIfLast);
-    ssize_t removeHandle(EffectHandle *handle);
-    ssize_t removeHandle_l(EffectHandle *handle);
-
     const effect_descriptor_t& desc() const { return mDescriptor; }
-    wp<EffectChain>&     chain() { return mChain; }
-
-    status_t         setDevices(const AudioDeviceTypeAddrVector &devices);
-    status_t         setInputDevice(const AudioDeviceTypeAddr &device);
-    status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
-    status_t         setMode(audio_mode_t mode);
-    status_t         setAudioSource(audio_source_t source);
-    status_t         start();
-    status_t         stop();
-    void             setSuspended(bool suspended);
-    bool             suspended() const;
-
-    EffectHandle*    controlHandle_l();
-
-    bool             isPinned() const { return mPinned; }
-    void             unPin() { mPinned = false; }
-    bool             purgeHandles();
-    void             lock() { mLock.lock(); }
-    void             unlock() { mLock.unlock(); }
     bool             isOffloadable() const
                         { return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
     bool             isImplementationSoftware() const
@@ -138,18 +124,143 @@
     bool             isVolumeMonitor() const
                         { return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
                             == EFFECT_FLAG_VOLUME_MONITOR; }
-    status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
-    bool             isOffloaded() const;
-    void             addEffectToHal_l();
-    void             release_l();
+
+    virtual status_t setEnabled(bool enabled, bool fromHandle);
+    status_t    setEnabled_l(bool enabled);
+    bool isEnabled() const;
+
+    void             setSuspended(bool suspended);
+    bool             suspended() const;
+
+    virtual status_t command(uint32_t cmdCode __unused,
+                 uint32_t cmdSize __unused,
+                 void *pCmdData __unused,
+                 uint32_t *replySize __unused,
+                 void *pReplyData __unused) { return NO_ERROR; };
+
+    void setCallback(const sp<EffectCallbackInterface>& callback) { mCallback = callback; }
+    sp<EffectCallbackInterface>&     callback() { return mCallback; }
+
+    status_t addHandle(EffectHandle *handle);
+    ssize_t disconnectHandle(EffectHandle *handle, bool unpinIfLast);
+    ssize_t removeHandle(EffectHandle *handle);
+    virtual ssize_t removeHandle_l(EffectHandle *handle);
+    EffectHandle* controlHandle_l();
+    bool purgeHandles();
+
+    void             checkSuspendOnEffectEnabled(bool enabled, bool threadLocked);
+
+    bool             isPinned() const { return mPinned; }
+    void             unPin() { mPinned = false; }
+
+    void             lock() { mLock.lock(); }
+    void             unlock() { mLock.unlock(); }
 
     status_t         updatePolicyState();
 
+    virtual          sp<EffectModule> asEffectModule() { return nullptr; }
+    virtual          sp<DeviceEffectProxy> asDeviceEffectProxy() { return nullptr; }
+
     void             dump(int fd, const Vector<String16>& args);
 
 private:
     friend class AudioFlinger;      // for mHandles
-    bool                mPinned;
+    bool             mPinned = false;
+
+    DISALLOW_COPY_AND_ASSIGN(EffectBase);
+
+mutable Mutex                 mLock;      // mutex for process, commands and handles list protection
+    sp<EffectCallbackInterface> mCallback; // parent effect chain
+    const int                 mId;        // this instance unique ID
+    const audio_session_t     mSessionId; // audio session ID
+    const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
+    effect_state              mState = IDLE; // current activation state
+    // effect is suspended: temporarily disabled by framework
+    bool                      mSuspended = false;
+
+    Vector<EffectHandle *>    mHandles;   // list of client handles
+                // First handle in mHandles has highest priority and controls the effect module
+
+    // Audio policy effect state management
+    // Mutex protecting transactions with audio policy manager as mLock cannot
+    // be held to avoid cross deadlocks with audio policy mutex
+    Mutex                     mPolicyLock;
+    // Effect is registered in APM or not
+    bool                      mPolicyRegistered = false;
+    // Effect enabled state communicated to APM. Enabled state corresponds to
+    // state requested by the EffectHandle with control
+    bool                      mPolicyEnabled = false;
+};
+
+// The EffectModule class is a wrapper object controlling the effect engine implementation
+// in the effect library. It prevents concurrent calls to process() and command() functions
+// from different client threads. It keeps a list of EffectHandle objects corresponding
+// to all client applications using this effect and notifies applications of effect state,
+// control or parameter changes. It manages the activation state machine to send appropriate
+// reset, enable, disable commands to effect engine and provide volume
+// ramping when effects are activated/deactivated.
+// When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
+// the attached track(s) to accumulate their auxiliary channel.
+class EffectModule : public EffectBase {
+public:
+    EffectModule(const sp<EffectCallbackInterface>& callabck,
+                    effect_descriptor_t *desc,
+                    int id,
+                    audio_session_t sessionId,
+                    bool pinned,
+                    audio_port_handle_t deviceId);
+    virtual ~EffectModule();
+
+    void process();
+    bool updateState();
+    status_t command(uint32_t cmdCode,
+                     uint32_t cmdSize,
+                     void *pCmdData,
+                     uint32_t *replySize,
+                     void *pReplyData) override;
+
+    void reset_l();
+    status_t configure();
+    status_t init();
+
+    uint32_t status() {
+        return mStatus;
+    }
+
+    bool isProcessEnabled() const;
+    bool isOffloadedOrDirect() const;
+    bool isVolumeControlEnabled() const;
+
+    void        setInBuffer(const sp<EffectBufferHalInterface>& buffer);
+    int16_t     *inBuffer() const {
+        return mInBuffer != 0 ? reinterpret_cast<int16_t*>(mInBuffer->ptr()) : NULL;
+    }
+    void        setOutBuffer(const sp<EffectBufferHalInterface>& buffer);
+    int16_t     *outBuffer() const {
+        return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
+    }
+
+    ssize_t removeHandle_l(EffectHandle *handle) override;
+
+    status_t         setDevices(const AudioDeviceTypeAddrVector &devices);
+    status_t         setInputDevice(const AudioDeviceTypeAddr &device);
+    status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
+    status_t         setMode(audio_mode_t mode);
+    status_t         setAudioSource(audio_source_t source);
+    status_t         start();
+    status_t         stop();
+
+    status_t         setOffloaded(bool offloaded, audio_io_handle_t io);
+    bool             isOffloaded() const;
+    void             addEffectToHal_l();
+    void             release_l();
+
+    sp<EffectModule> asEffectModule() override { return this; }
+
+    void             dump(int fd, const Vector<String16>& args);
+
+private:
+    friend class AudioFlinger;      // for mHandles
 
     // Maximum time allocated to effect engines to complete the turn off sequence
     static const uint32_t MAX_DISABLE_TIME_MS = 10000;
@@ -158,30 +269,19 @@
 
     status_t start_l();
     status_t stop_l();
-    status_t remove_effect_from_hal_l();
+    status_t removeEffectFromHal_l();
     status_t sendSetAudioDevicesCommand(const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode);
 
-mutable Mutex               mLock;      // mutex for process, commands and handles list protection
-    wp<ThreadBase>      mThread;    // parent thread
-    ThreadBase::type_t  mThreadType; // parent thread type
-    wp<EffectChain>     mChain;     // parent effect chain
-    const int           mId;        // this instance unique ID
-    const audio_session_t mSessionId; // audio session ID
-    const effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
     effect_config_t     mConfig;    // input and output audio configuration
     sp<EffectHalInterface> mEffectInterface; // Effect module HAL
     sp<EffectBufferHalInterface> mInBuffer;  // Buffers for interacting with HAL
     sp<EffectBufferHalInterface> mOutBuffer;
     status_t            mStatus;    // initialization status
-    effect_state        mState;     // current activation state
-    Vector<EffectHandle *> mHandles;    // list of client handles
                 // First handle in mHandles has highest priority and controls the effect module
     uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after
                                     // sending disable command.
     uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
-    bool     mSuspended;            // effect is suspended: temporarily disabled by framework
     bool     mOffloaded;            // effect is currently offloaded to the audio DSP
-    wp<AudioFlinger>    mAudioFlinger;
 
 #ifdef FLOAT_EFFECT_CHAIN
     bool    mSupportsFloat;         // effect supports float processing
@@ -208,16 +308,6 @@
     static constexpr pid_t INVALID_PID = (pid_t)-1;
     // this tid is allowed to call setVolume() without acquiring the mutex.
     pid_t mSetVolumeReentrantTid = INVALID_PID;
-
-    // Audio policy effect state management
-    // Mutex protecting transactions with audio policy manager as mLock cannot
-    // be held to avoid cross deadlocks with audio policy mutex
-    Mutex   mPolicyLock;
-    // Effect is registered in APM or not
-    bool    mPolicyRegistered = false;
-    // Effect enabled state communicated to APM. Enabled state corresponds to
-    // state requested by the EffectHandle with control
-    bool    mPolicyEnabled = false;
 };
 
 // The EffectHandle class implements the IEffect interface. It provides resources
@@ -229,7 +319,7 @@
 class EffectHandle: public android::BnEffect {
 public:
 
-    EffectHandle(const sp<EffectModule>& effect,
+    EffectHandle(const sp<EffectBase>& effect,
             const sp<AudioFlinger::Client>& client,
             const sp<IEffectClient>& effectClient,
             int32_t priority);
@@ -267,9 +357,9 @@
     bool enabled() const { return mEnabled; }
 
     // Getters
-    wp<EffectModule> effect() const { return mEffect; }
+    wp<EffectBase> effect() const { return mEffect; }
     int id() const {
-        sp<EffectModule> effect = mEffect.promote();
+        sp<EffectBase> effect = mEffect.promote();
         if (effect == 0) {
             return 0;
         }
@@ -286,7 +376,7 @@
     DISALLOW_COPY_AND_ASSIGN(EffectHandle);
 
     Mutex mLock;                        // protects IEffect method calls
-    wp<EffectModule> mEffect;           // pointer to controlled EffectModule
+    wp<EffectBase> mEffect;           // pointer to controlled EffectModule
     sp<IEffectClient> mEffectClient;    // callback interface for client notifications
     /*const*/ sp<Client> mClient;       // client for shared memory allocation, see disconnect()
     sp<IMemory>         mCblkMemory;    // shared memory for control block
@@ -333,7 +423,6 @@
     }
 
     status_t createEffect_l(sp<EffectModule>& effect,
-                            ThreadBase *thread,
                             effect_descriptor_t *desc,
                             int id,
                             audio_session_t sessionId,
@@ -389,9 +478,8 @@
                               bool suspend);
     // suspend all eligible effects
     void setEffectSuspendedAll_l(bool suspend);
-    // check if effects should be suspend or restored when a given effect is enable or disabled
-    void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
-                                          bool enabled);
+    // check if effects should be suspended or restored when a given effect is enable or disabled
+    void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, bool enabled);
 
     void clearInputBuffer();
 
@@ -416,9 +504,60 @@
     // isCompatibleWithThread_l() must be called with thread->mLock held
     bool isCompatibleWithThread_l(const sp<ThreadBase>& thread) const;
 
+    sp<EffectCallbackInterface> effectCallback() const { return mEffectCallback; }
+    wp<ThreadBase> thread() const { return mEffectCallback->thread(); }
+
     void dump(int fd, const Vector<String16>& args);
 
 private:
+
+    class EffectCallback :  public EffectCallbackInterface {
+    public:
+        EffectCallback(EffectChain *chain, ThreadBase *thread, AudioFlinger *audioFlinger)
+            : mChain(chain), mThread(thread), mAudioFlinger(audioFlinger) {}
+
+        status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+               int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) override;
+        status_t allocateHalBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) override;
+        bool updateOrphanEffectChains(const sp<EffectBase>& effect) override;
+
+        audio_io_handle_t io() const override;
+        bool isOutput() const override;
+        bool isOffload() const override;
+        bool isOffloadOrDirect() const override;
+        bool isOffloadOrMmap() const override;
+
+        uint32_t sampleRate() const override;
+        audio_channel_mask_t channelMask() const override;
+        uint32_t channelCount() const override;
+        size_t frameCount() const override;
+        uint32_t latency() const override;
+
+        status_t addEffectToHal(sp<EffectHalInterface> effect) override;
+        status_t removeEffectFromHal(sp<EffectHalInterface> effect) override;
+        bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
+        void setVolumeForOutput(float left, float right) const override;
+
+        // check if effects should be suspended/restored when a given effect is enable/disabled
+        void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect,
+                              bool enabled, bool threadLocked) override;
+        void resetVolume() override;
+        uint32_t strategy() const override;
+        int32_t activeTrackCnt() const override;
+        void onEffectEnable(const sp<EffectBase>& effect) override;
+        void onEffectDisable(const sp<EffectBase>& effect) override;
+
+        wp<EffectChain> chain() const override { return mChain; }
+
+        wp<ThreadBase> thread() { return mThread; }
+        void setThread(ThreadBase *thread) { mThread = thread; };
+
+    private:
+        wp<EffectChain> mChain;
+        wp<ThreadBase> mThread;
+        wp<AudioFlinger> mAudioFlinger;
+    };
+
     friend class AudioFlinger;  // for mThread, mEffects
     DISALLOW_COPY_AND_ASSIGN(EffectChain);
 
@@ -444,13 +583,12 @@
 
     static bool isEffectEligibleForBtNrecSuspend(const effect_uuid_t *type);
 
-    void clearInputBuffer_l(const sp<ThreadBase>& thread);
+    void clearInputBuffer_l();
 
     void setThread(const sp<ThreadBase>& thread);
 
     void setVolumeForOutput_l(uint32_t left, uint32_t right);
 
-             wp<ThreadBase> mThread;     // parent mixer thread
     mutable  Mutex mLock;        // mutex protecting effect list
              Vector< sp<EffectModule> > mEffects; // list of effect modules
              audio_session_t mSessionId; // audio session ID
@@ -474,4 +612,99 @@
              // timeLow fields among effect type UUIDs.
              // Updated by setEffectSuspended_l() and setEffectSuspendedAll_l() only.
              KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
+
+             const sp<EffectCallback> mEffectCallback;
+};
+
+class DeviceEffectProxy : public EffectBase {
+public:
+        DeviceEffectProxy (const AudioDeviceTypeAddr& device,
+                const sp<DeviceEffectManagerCallback>& callback,
+                effect_descriptor_t *desc, int id)
+            : EffectBase(callback, desc, id, AUDIO_SESSION_DEVICE, false),
+                mDevice(device), mManagerCallback(callback),
+                mMyCallback(new ProxyCallback(this, callback)) {}
+
+    status_t setEnabled(bool enabled, bool fromHandle) override;
+    sp<DeviceEffectProxy> asDeviceEffectProxy() override { return this; }
+
+    status_t init(const std::map<audio_patch_handle_t, PatchPanel::Patch>& patches);
+    status_t onCreatePatch(audio_patch_handle_t patchHandle, const PatchPanel::Patch& patch);
+    void onReleasePatch(audio_patch_handle_t patchHandle);
+
+    size_t removeEffect(const sp<EffectModule>& effect);
+
+    status_t addEffectToHal(sp<EffectHalInterface> effect);
+    status_t removeEffectFromHal(sp<EffectHalInterface> effect);
+
+    const AudioDeviceTypeAddr& device() { return mDevice; };
+    bool isOutput() const;
+    uint32_t sampleRate() const;
+    audio_channel_mask_t channelMask() const;
+    uint32_t channelCount() const;
+
+    void dump(int fd, int spaces);
+
+private:
+
+    class ProxyCallback :  public EffectCallbackInterface {
+    public:
+                ProxyCallback(DeviceEffectProxy *proxy,
+                        const sp<DeviceEffectManagerCallback>& callback)
+                    : mProxy(proxy), mManagerCallback(callback) {}
+
+        status_t createEffectHal(const effect_uuid_t *pEffectUuid,
+               int32_t sessionId, int32_t deviceId, sp<EffectHalInterface> *effect) override;
+        status_t allocateHalBuffer(size_t size __unused,
+                sp<EffectBufferHalInterface>* buffer __unused) override { return NO_ERROR; }
+        bool updateOrphanEffectChains(const sp<EffectBase>& effect __unused) override {
+                    return false;
+        }
+
+        audio_io_handle_t io() const override { return AUDIO_IO_HANDLE_NONE; }
+        bool isOutput() const override;
+        bool isOffload() const override { return false; }
+        bool isOffloadOrDirect() const override { return false; }
+        bool isOffloadOrMmap() const override { return false; }
+
+        uint32_t sampleRate() const override;
+        audio_channel_mask_t channelMask() const override;
+        uint32_t channelCount() const override;
+        size_t frameCount() const override  { return 0; }
+        uint32_t latency() const override  { return 0; }
+
+        status_t addEffectToHal(sp<EffectHalInterface> effect) override;
+        status_t removeEffectFromHal(sp<EffectHalInterface> effect) override;
+
+        bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
+        void setVolumeForOutput(float left __unused, float right __unused) const override {}
+
+        void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect __unused,
+                              bool enabled __unused, bool threadLocked __unused) override {}
+        void resetVolume() override {}
+        uint32_t strategy() const override  { return 0; }
+        int32_t activeTrackCnt() const override { return 0; }
+        void onEffectEnable(const sp<EffectBase>& effect __unused) override {}
+        void onEffectDisable(const sp<EffectBase>& effect __unused) override {}
+
+        wp<EffectChain> chain() const override { return nullptr; }
+
+        int newEffectId();
+
+    private:
+        const wp<DeviceEffectProxy> mProxy;
+        const sp<DeviceEffectManagerCallback> mManagerCallback;
+    };
+
+    status_t checkPort(const PatchPanel::Patch& patch, const struct audio_port_config *port,
+            sp<EffectHandle> *handle);
+
+    const AudioDeviceTypeAddr mDevice;
+    const sp<DeviceEffectManagerCallback> mManagerCallback;
+    const sp<ProxyCallback> mMyCallback;
+
+    Mutex mProxyLock;
+    std::map<audio_patch_handle_t, sp<EffectHandle>> mEffectHandles; // protected by mProxyLock
+    sp<EffectModule> mHalEffect; // protected by mProxyLock
+    struct audio_port_config mDevicePort = { .id = AUDIO_PORT_HANDLE_NONE };
 };
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index ee5bd75..786c279 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -169,8 +169,7 @@
                     hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
                 }
             }
-            mPatches.erase(iter);
-            removeSoftwarePatchFromInsertedModules(*handle);
+            erasePatch(*handle);
         }
     }
 
@@ -325,10 +324,14 @@
                         }
                     }
                     status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+                    if (status == NO_ERROR) {
+                        newPatch.setThread(thread);
+                    }
+
                     // remove stale audio patch with same input as sink if any
                     for (auto& iter : mPatches) {
                         if (iter.second.mAudioPatch.sinks[0].ext.mix.handle == thread->id()) {
-                            mPatches.erase(iter.first);
+                            erasePatch(iter.first);
                             break;
                         }
                     }
@@ -387,11 +390,14 @@
             }
 
             status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
+            if (status == NO_ERROR) {
+                newPatch.setThread(thread);
+            }
 
             // remove stale audio patch with same output as source if any
             for (auto& iter : mPatches) {
                 if (iter.second.mAudioPatch.sources[0].ext.mix.handle == thread->id()) {
-                    mPatches.erase(iter.first);
+                    erasePatch(iter.first);
                     break;
                 }
             }
@@ -405,11 +411,11 @@
     if (status == NO_ERROR) {
         *handle = (audio_patch_handle_t) mAudioFlinger.nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH);
         newPatch.mHalHandle = halHandle;
+        mAudioFlinger.mDeviceEffectManager.createAudioPatch(*handle, newPatch);
         mPatches.insert(std::make_pair(*handle, std::move(newPatch)));
         if (insertedModule != AUDIO_MODULE_HANDLE_NONE) {
             addSoftwarePatchToInsertedModules(insertedModule, *handle);
         }
-        ALOGV("%s() added new patch handle %d halHandle %d", __func__, *handle, halHandle);
     } else {
         newPatch.clearConnections(this);
     }
@@ -490,10 +496,12 @@
     }
 
     sp<RecordThread::PatchRecord> tempRecordTrack;
+    const bool usePassthruPatchRecord =
+            (inputFlags & AUDIO_INPUT_FLAG_DIRECT) && (outputFlags & AUDIO_OUTPUT_FLAG_DIRECT);
     const size_t playbackFrameCount = mPlayback.thread()->frameCount();
     const size_t recordFrameCount = mRecord.thread()->frameCount();
     size_t frameCount = 0;
-    if ((inputFlags & AUDIO_INPUT_FLAG_DIRECT) && (outputFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+    if (usePassthruPatchRecord) {
         // PassthruPatchRecord producesBufferOnDemand, so use
         // maximum of playback and record thread framecounts
         frameCount = std::max(playbackFrameCount, recordFrameCount);
@@ -550,8 +558,14 @@
     }
 
     // tie playback and record tracks together
-    mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack);
-    mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack);
+    // In the case of PassthruPatchRecord no I/O activity happens on RecordThread,
+    // everything is driven from PlaybackThread. Thus AudioBufferProvider methods
+    // of PassthruPatchRecord can only be called if the corresponding PatchTrack
+    // is alive. There is no need to hold a reference, and there is no need
+    // to clear it. In fact, since playback stopping is asynchronous, there is
+    // no proper time when clearing could be done.
+    mRecord.setTrackAndPeer(tempRecordTrack, tempPatchTrack, !usePassthruPatchRecord);
+    mPlayback.setTrackAndPeer(tempPatchTrack, tempRecordTrack, true /*holdReference*/);
 
     // start capture and playback
     mRecord.track()->start(AudioSystem::SYNC_EVENT_NONE, AUDIO_SESSION_NONE);
@@ -633,8 +647,21 @@
 String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle) const
 {
     // TODO: Consider table dump form for patches, just like tracks.
-    String8 result = String8::format("Patch %d: thread %p => thread %p",
-            myHandle, mRecord.const_thread().get(), mPlayback.const_thread().get());
+    String8 result = String8::format("Patch %d: %s (thread %p => thread %p)",
+            myHandle, isSoftware() ? "Software bridge between" : "No software bridge",
+            mRecord.const_thread().get(), mPlayback.const_thread().get());
+
+    bool hasSinkDevice =
+            mAudioPatch.num_sinks > 0 && mAudioPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE;
+    bool hasSourceDevice =
+            mAudioPatch.num_sources > 0 && mAudioPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE;
+    result.appendFormat(" thread %p %s (%d) first device type %08x", mThread.unsafe_get(),
+            hasSinkDevice ? "num sinks" :
+                (hasSourceDevice ? "num sources" : "no devices"),
+            hasSinkDevice ? mAudioPatch.num_sinks :
+                (hasSourceDevice ? mAudioPatch.num_sources : 0),
+            hasSinkDevice ? mAudioPatch.sinks[0].ext.device.type :
+                (hasSourceDevice ? mAudioPatch.sources[0].ext.device.type : 0));
 
     // add latency if it exists
     double latencyMs;
@@ -710,11 +737,16 @@
             status = BAD_VALUE;
     }
 
-    mPatches.erase(iter);
-    removeSoftwarePatchFromInsertedModules(handle);
+    erasePatch(handle);
     return status;
 }
 
+void AudioFlinger::PatchPanel::erasePatch(audio_patch_handle_t handle) {
+    mPatches.erase(handle);
+    removeSoftwarePatchFromInsertedModules(handle);
+    mAudioFlinger.mDeviceEffectManager.releaseAudioPatch(handle);
+}
+
 /* List connected audio ports and they attributes */
 status_t AudioFlinger::PatchPanel::listAudioPatches(unsigned int *num_patches __unused,
                                   struct audio_patch *patches __unused)
@@ -798,16 +830,13 @@
     String8 patchPanelDump;
     const char *indent = "  ";
 
-    // Only dump software patches.
     bool headerPrinted = false;
     for (const auto& iter : mPatches) {
-        if (iter.second.isSoftware()) {
-            if (!headerPrinted) {
-                patchPanelDump += "\nSoftware patches:\n";
-                headerPrinted = true;
-            }
-            patchPanelDump.appendFormat("%s%s\n", indent, iter.second.dump(iter.first).string());
+        if (!headerPrinted) {
+            patchPanelDump += "\nPatches:\n";
+            headerPrinted = true;
         }
+        patchPanelDump.appendFormat("%s%s\n", indent, iter.second.dump(iter.first).string());
     }
 
     headerPrinted = false;
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 181e27c..89d4eb1 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -76,13 +76,18 @@
 
     void dump(int fd) const;
 
-private:
     template<typename ThreadType, typename TrackType>
-    class Endpoint {
+    class Endpoint final {
     public:
         Endpoint() = default;
         Endpoint(const Endpoint&) = delete;
-        Endpoint& operator=(const Endpoint&) = delete;
+        Endpoint& operator=(const Endpoint& other) noexcept {
+            mThread = other.mThread;
+            mCloseThread = other.mCloseThread;
+            mHandle = other.mHandle;
+            mTrack = other.mTrack;
+            return *this;
+        }
         Endpoint(Endpoint&& other) noexcept { swap(other); }
         Endpoint& operator=(Endpoint&& other) noexcept {
             swap(other);
@@ -98,8 +103,8 @@
             return trackOrNull->initCheck();
         }
         audio_patch_handle_t handle() const { return mHandle; }
-        sp<ThreadType> thread() { return mThread; }
-        sp<TrackType> track() { return mTrack; }
+        sp<ThreadType> thread() const { return mThread; }
+        sp<TrackType> track() const { return mTrack; }
         sp<const ThreadType> const_thread() const { return mThread; }
         sp<const TrackType> const_track() const { return mTrack; }
 
@@ -123,18 +128,20 @@
             mCloseThread = closeThread;
         }
         template <typename T>
-        void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer) {
+        void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer, bool holdReference) {
             mTrack = track;
             mThread->addPatchTrack(mTrack);
-            mTrack->setPeerProxy(peer, true /* holdReference */);
+            mTrack->setPeerProxy(peer, holdReference);
+            mClearPeerProxy = holdReference;
         }
-        void clearTrackPeer() { if (mTrack) mTrack->clearPeerProxy(); }
+        void clearTrackPeer() { if (mClearPeerProxy && mTrack) mTrack->clearPeerProxy(); }
         void stopTrack() { if (mTrack) mTrack->stop(); }
 
         void swap(Endpoint &other) noexcept {
             using std::swap;
             swap(mThread, other.mThread);
             swap(mCloseThread, other.mCloseThread);
+            swap(mClearPeerProxy, other.mClearPeerProxy);
             swap(mHandle, other.mHandle);
             swap(mTrack, other.mTrack);
         }
@@ -146,18 +153,41 @@
     private:
         sp<ThreadType> mThread;
         bool mCloseThread = true;
+        bool mClearPeerProxy = true;
         audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
         sp<TrackType> mTrack;
     };
 
-    class Patch {
+    class Patch final {
     public:
         explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
+        Patch() = default;
         ~Patch();
-        Patch(const Patch&) = delete;
-        Patch(Patch&&) = default;
-        Patch& operator=(const Patch&) = delete;
-        Patch& operator=(Patch&&) = default;
+        Patch(const Patch& other) noexcept {
+            mAudioPatch = other.mAudioPatch;
+            mHalHandle = other.mHalHandle;
+            mPlayback = other.mPlayback;
+            mRecord = other.mRecord;
+            mThread = other.mThread;
+        }
+        Patch(Patch&& other) noexcept { swap(other); }
+        Patch& operator=(Patch&& other) noexcept {
+            swap(other);
+            return *this;
+        }
+
+        void swap(Patch &other) noexcept {
+            using std::swap;
+            swap(mAudioPatch, other.mAudioPatch);
+            swap(mHalHandle, other.mHalHandle);
+            swap(mPlayback, other.mPlayback);
+            swap(mRecord, other.mRecord);
+            swap(mThread, other.mThread);
+        }
+
+        friend void swap(Patch &a, Patch &b) noexcept {
+            a.swap(b);
+        }
 
         status_t createConnections(PatchPanel *panel);
         void clearConnections(PatchPanel *panel);
@@ -165,6 +195,9 @@
             return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
                     mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
 
+        void setThread(sp<ThreadBase> thread) { mThread = thread; }
+        wp<ThreadBase> thread() const { return mThread; }
+
         // returns the latency of the patch (from record to playback).
         status_t getLatencyMs(double *latencyMs) const;
 
@@ -182,13 +215,20 @@
         Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
         // connects source device to record thread input
         Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
+
+        wp<ThreadBase> mThread;
     };
 
+    // Call with AudioFlinger mLock held
+    std::map<audio_patch_handle_t, Patch>& patches_l() { return mPatches; }
+
+private:
     AudioHwDevice* findAudioHwDeviceByModule(audio_module_handle_t module);
     sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
     void addSoftwarePatchToInsertedModules(
             audio_module_handle_t module, audio_patch_handle_t handle);
     void removeSoftwarePatchFromInsertedModules(audio_patch_handle_t handle);
+    void erasePatch(audio_patch_handle_t handle);
 
     AudioFlinger &mAudioFlinger;
     std::map<audio_patch_handle_t, Patch> mPatches;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b5592e3..598caeb 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1146,32 +1146,26 @@
     }
 }
 
-void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
-                                                            bool enabled,
-                                                            audio_session_t sessionId)
-{
-    Mutex::Autolock _l(mLock);
-    checkSuspendOnEffectEnabled_l(effect, enabled, sessionId);
-}
+void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(bool enabled,
+                                                           audio_session_t sessionId,
+                                                           bool threadLocked) {
+    if (!threadLocked) {
+        mLock.lock();
+    }
 
-void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,
-                                                            bool enabled,
-                                                            audio_session_t sessionId)
-{
     if (mType != RECORD) {
         // suspend all effects in AUDIO_SESSION_OUTPUT_MIX when enabling any effect on
         // another session. This gives the priority to well behaved effect control panels
         // and applications not using global effects.
         // Enabling post processing in AUDIO_SESSION_OUTPUT_STAGE session does not affect
         // global effects
-        if ((sessionId != AUDIO_SESSION_OUTPUT_MIX) && (sessionId != AUDIO_SESSION_OUTPUT_STAGE)) {
+        if (!audio_is_global_session(sessionId)) {
             setEffectSuspended_l(NULL, enabled, AUDIO_SESSION_OUTPUT_MIX);
         }
     }
 
-    sp<EffectChain> chain = getEffectChain_l(sessionId);
-    if (chain != 0) {
-        chain->checkSuspendOnEffectEnabled(effect, enabled);
+    if (!threadLocked) {
+        mLock.unlock();
     }
 }
 
@@ -1179,8 +1173,9 @@
 status_t AudioFlinger::RecordThread::checkEffectCompatibility_l(
         const effect_descriptor_t *desc, audio_session_t sessionId)
 {
-    // No global effect sessions on record threads
-    if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
+    // No global output effect sessions on record threads
+    if (sessionId == AUDIO_SESSION_OUTPUT_MIX
+            || sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
         ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s",
                 desc->name, mThreadName);
         return BAD_VALUE;
@@ -1254,6 +1249,13 @@
                             " on output stage session", desc->name);
                     return BAD_VALUE;
                 }
+            } else if (sessionId == AUDIO_SESSION_DEVICE) {
+                // only post processing on output stage session
+                if ((desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_POST_PROC) {
+                    ALOGW("checkEffectCompatibility_l(): non post processing effect %s not allowed"
+                            " on device session", desc->name);
+                    return BAD_VALUE;
+                }
             } else {
                 // no restriction on effects applied on non fast tracks
                 if ((hasAudioSession_l(sessionId) & ThreadBase::FAST_SESSION) == 0) {
@@ -1295,7 +1297,7 @@
             return BAD_VALUE;
         }
 #endif
-        if ((sessionId == AUDIO_SESSION_OUTPUT_STAGE) || (sessionId == AUDIO_SESSION_OUTPUT_MIX)) {
+        if (audio_is_global_session(sessionId)) {
             ALOGW("checkEffectCompatibility_l(): global effect %s on DUPLICATING"
                     " thread %s", desc->name, mThreadName);
             return BAD_VALUE;
@@ -1371,7 +1373,7 @@
         if (effect == 0) {
             effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
             // create a new effect module if none present in the chain
-            lStatus = chain->createEffect_l(effect, this, desc, effectId, sessionId, pinned);
+            lStatus = chain->createEffect_l(effect, desc, effectId, sessionId, pinned);
             if (lStatus != NO_ERROR) {
                 goto Exit;
             }
@@ -1417,9 +1419,12 @@
     sp<EffectModule> effect;
     {
         Mutex::Autolock _l(mLock);
-
-        effect = handle->effect().promote();
-        if (effect == 0) {
+        sp<EffectBase> effectBase = handle->effect().promote();
+        if (effectBase == nullptr) {
+            return;
+        }
+        effect = effectBase->asEffectModule();
+        if (effect == nullptr) {
             return;
         }
         // restore suspended effects if the disconnected handle was enabled and the last one.
@@ -1431,11 +1436,34 @@
     if (remove) {
         mAudioFlinger->updateOrphanEffectChains(effect);
         if (handle->enabled()) {
-            checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
+            effect->checkSuspendOnEffectEnabled(false, false /*threadLocked*/);
         }
     }
 }
 
+void AudioFlinger::ThreadBase::onEffectEnable(const sp<EffectModule>& effect) {
+    if (mType == OFFLOAD || mType == MMAP) {
+        Mutex::Autolock _l(mLock);
+        broadcast_l();
+    }
+    if (!effect->isOffloadable()) {
+        if (mType == ThreadBase::OFFLOAD) {
+            PlaybackThread *t = (PlaybackThread *)this;
+            t->invalidateTracks(AUDIO_STREAM_MUSIC);
+        }
+        if (effect->sessionId() == AUDIO_SESSION_OUTPUT_MIX) {
+            mAudioFlinger->onNonOffloadableGlobalEffectEnable();
+        }
+    }
+}
+
+void AudioFlinger::ThreadBase::onEffectDisable() {
+    if (mType == OFFLOAD || mType == MMAP) {
+        Mutex::Autolock _l(mLock);
+        broadcast_l();
+    }
+}
+
 sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect(audio_session_t sessionId,
         int effectId)
 {
@@ -1511,7 +1539,7 @@
         detachAuxEffect_l(effect->id());
     }
 
-    sp<EffectChain> chain = effect->chain().promote();
+    sp<EffectChain> chain = effect->callback()->chain().promote();
     if (chain != 0) {
         // remove effect chain if removing last effect
         if (chain->removeEffect_l(effect, release) == 0) {
@@ -2051,6 +2079,7 @@
         { // scope for mLock
             Mutex::Autolock _l(mLock);
             for (audio_session_t session : {
+                    AUDIO_SESSION_DEVICE,
                     AUDIO_SESSION_OUTPUT_STAGE,
                     AUDIO_SESSION_OUTPUT_MIX,
                     sessionId,
@@ -3103,7 +3132,7 @@
     halOutBuffer = halInBuffer;
     effect_buffer_t *buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData());
     ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
-    if (session > AUDIO_SESSION_OUTPUT_MIX) {
+    if (!audio_is_global_session(session)) {
         // Only one effect chain can be present in direct output thread and it uses
         // the sink buffer as input
         if (mType != DIRECT) {
@@ -3143,8 +3172,11 @@
     chain->setThread(this);
     chain->setInBuffer(halInBuffer);
     chain->setOutBuffer(halOutBuffer);
-    // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted at end of effect
-    // chains list in order to be processed last as it contains output stage effects.
+    // Effect chain for session AUDIO_SESSION_DEVICE is inserted at end of effect
+    // chains list in order to be processed last as it contains output device effects.
+    // Effect chain for session AUDIO_SESSION_OUTPUT_STAGE is inserted just before to apply post
+    // processing effects specific to an output stream before effects applied to all streams
+    // routed to a given device.
     // Effect chain for session AUDIO_SESSION_OUTPUT_MIX is inserted before
     // session AUDIO_SESSION_OUTPUT_STAGE to be processed
     // after track specific effects and before output stage.
@@ -3154,7 +3186,8 @@
     // chains list to be processed before output mix effects. Relative order between other
     // sessions is not important.
     static_assert(AUDIO_SESSION_OUTPUT_MIX == 0 &&
-            AUDIO_SESSION_OUTPUT_STAGE < AUDIO_SESSION_OUTPUT_MIX,
+            AUDIO_SESSION_OUTPUT_STAGE < AUDIO_SESSION_OUTPUT_MIX &&
+            AUDIO_SESSION_DEVICE < AUDIO_SESSION_OUTPUT_STAGE,
             "audio_session_t constants misdefined");
     size_t size = mEffectChains.size();
     size_t i = 0;
@@ -9093,8 +9126,8 @@
         const effect_descriptor_t *desc, audio_session_t sessionId)
 {
     // No global effect sessions on mmap threads
-    if (sessionId == AUDIO_SESSION_OUTPUT_MIX || sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
-        ALOGW("checkEffectCompatibility_l(): global effect %s on record thread %s",
+    if (audio_is_global_session(sessionId)) {
+        ALOGW("checkEffectCompatibility_l(): global effect %s on MMAP thread %s",
                 desc->name, mThreadName);
         return BAD_VALUE;
     }
@@ -9116,7 +9149,6 @@
     }
 
     return NO_ERROR;
-
 }
 
 void AudioFlinger::MmapThread::checkInvalidTracks_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8de7632..4c53e28 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -271,6 +271,8 @@
                 // Called by AudioFlinger::frameCount(audio_io_handle_t output) and effects,
                 // and returns the [normal mix] buffer's frame count.
     virtual     size_t      frameCount() const = 0;
+    virtual     uint32_t    latency_l() const { return 0; }
+    virtual     void        setVolumeForOutput_l(float left __unused, float right __unused) const {}
 
                 // Return's the HAL's frame count i.e. fast mixer buffer size.
                 size_t      frameCountHAL() const { return mFrameCount; }
@@ -424,14 +426,9 @@
 
                 // check if some effects must be suspended/restored when an effect is enabled
                 // or disabled
-                void checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
-                                                 bool enabled,
-                                                 audio_session_t sessionId =
-                                                        AUDIO_SESSION_OUTPUT_MIX);
-                void checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,
-                                                   bool enabled,
-                                                   audio_session_t sessionId =
-                                                        AUDIO_SESSION_OUTPUT_MIX);
+                void checkSuspendOnEffectEnabled(bool enabled,
+                                                 audio_session_t sessionId,
+                                                 bool threadLocked);
 
                 virtual status_t    setSyncEvent(const sp<SyncEvent>& event) = 0;
                 virtual bool        isValidSyncEvent(const sp<SyncEvent>& event) const = 0;
@@ -465,6 +462,9 @@
 
     mutable     Mutex                   mLock;
 
+                void onEffectEnable(const sp<EffectModule>& effect);
+                void onEffectDisable();
+
 protected:
 
                 // entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -814,7 +814,7 @@
                 // return estimated latency in milliseconds, as reported by HAL
                 uint32_t    latency() const;
                 // same, but lock must already be held
-                uint32_t    latency_l() const;
+                uint32_t    latency_l() const override;
 
                 // VolumeInterface
     virtual     void        setMasterVolume(float value);
@@ -824,7 +824,7 @@
     virtual     void        setStreamMute(audio_stream_type_t stream, bool muted);
     virtual     float       streamVolume(audio_stream_type_t stream) const;
 
-                void        setVolumeForOutput_l(float left, float right) const;
+                void        setVolumeForOutput_l(float left, float right) const override;
 
                 sp<Track>   createTrack_l(
                                 const sp<AudioFlinger::Client>& client,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
index 0843fea..a5de655 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
@@ -31,12 +31,24 @@
 public:
     AudioPatch(const struct audio_patch *patch, uid_t uid);
 
+    audio_patch_handle_t getHandle() const { return mHandle; }
+
+    audio_patch_handle_t getAfHandle() const { return mAfPatchHandle; }
+
+    void setAfHandle(audio_patch_handle_t afHandle) { mAfPatchHandle = afHandle; }
+
+    uid_t getUid() const { return mUid; }
+
+    void setUid(uid_t uid) { mUid = uid; }
+
     void dump(String8 *dst, int spaces, int index) const;
 
-    audio_patch_handle_t mHandle;
     struct audio_patch mPatch;
+
+private:
+    const audio_patch_handle_t mHandle;
     uid_t mUid;
-    audio_patch_handle_t mAfPatchHandle;
+    audio_patch_handle_t mAfPatchHandle = AUDIO_PATCH_HANDLE_NONE;
 };
 
 class AudioPatchCollection : public DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> >
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 0d05a63..0c5d1d0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -183,13 +183,17 @@
 {
 public:
     SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
-                           const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
+                           const struct audio_port_config &config,
+                           const sp<DeviceDescriptor>& srcDevice,
                            audio_stream_type_t stream, product_strategy_t strategy,
                            VolumeSource volumeSource);
+
     ~SourceClientDescriptor() override = default;
 
-    sp<AudioPatch> patchDesc() const { return mPatchDesc; }
-    sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; };
+    audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }
+    void setPatchHandle(audio_patch_handle_t patchHandle) { mPatchHandle = patchHandle; }
+
+    sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; }
     wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
     void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
     wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
@@ -199,7 +203,7 @@
     void dump(String8 *dst, int spaces, int index) const override;
 
  private:
-    const sp<AudioPatch> mPatchDesc;
+    audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
     const sp<DeviceDescriptor> mSrcDevice;
     wp<SwAudioOutputDescriptor> mSwOutput;
     wp<HwAudioOutputDescriptor> mHwOutput;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index bf0cc94..d79110a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -26,10 +26,9 @@
 namespace android {
 
 AudioPatch::AudioPatch(const struct audio_patch *patch, uid_t uid) :
-    mHandle(HandleGenerator<audio_patch_handle_t>::getNextHandle()),
     mPatch(*patch),
-    mUid(uid),
-    mAfPatchHandle(AUDIO_PATCH_HANDLE_NONE)
+    mHandle(HandleGenerator<audio_patch_handle_t>::getNextHandle()),
+    mUid(uid)
 {
 }
 
@@ -68,7 +67,7 @@
     add(handle, patch);
     ALOGV("addAudioPatch() handle %d af handle %d num_sources %d num_sinks %d source handle %d"
             "sink handle %d",
-          handle, patch->mAfPatchHandle, patch->mPatch.num_sources, patch->mPatch.num_sinks,
+          handle, patch->getAfHandle(), patch->mPatch.num_sources, patch->mPatch.num_sinks,
           patch->mPatch.sources[0].id, patch->mPatch.sinks[0].id);
     return NO_ERROR;
 }
@@ -81,7 +80,7 @@
         ALOGW("removeAudioPatch() patch %d not in", handle);
         return ALREADY_EXISTS;
     }
-    ALOGV("removeAudioPatch() handle %d af handle %d", handle, valueAt(index)->mAfPatchHandle);
+    ALOGV("removeAudioPatch() handle %d af handle %d", handle, valueAt(index)->getAfHandle());
     removeItemsAt(index);
     return NO_ERROR;
 }
@@ -123,7 +122,7 @@
         }
         if (patchesWritten < patchesMax) {
             patches[patchesWritten] = patch->mPatch;
-            patches[patchesWritten++].id = patch->mHandle;
+            patches[patchesWritten++].id = patch->getHandle();
         }
         (*num_patches)++;
         ALOGV("listAudioPatches() patch %zu num_sources %d num_sinks %d",
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 1dc7020..95822b9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -82,14 +82,13 @@
 }
 
 SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
-         audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
+         audio_attributes_t attributes, const struct audio_port_config &config,
          const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
          product_strategy_t strategy, VolumeSource volumeSource) :
     TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
-        AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE,
+        {config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
         stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
-        {} /* Sources do not support secondary outputs*/),
-        mPatchDesc(patchDesc), mSrcDevice(srcDevice)
+        {} /* Sources do not support secondary outputs*/), mSrcDevice(srcDevice)
 {
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 4de8d3b..f0bb28e 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -199,6 +199,7 @@
     struct Attributes
     {
         static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
+        static constexpr const char *engineLibrarySuffix = "engine_library";
     };
 
     static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
@@ -687,6 +688,10 @@
                     convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
                 config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
             }
+            std::string engineLibrarySuffix = getXmlAttribute(cur, Attributes::engineLibrarySuffix);
+            if (!engineLibrarySuffix.empty()) {
+                config->setEngineLibraryNameSuffix(engineLibrarySuffix);
+            }
             return NO_ERROR;
         }
     }
diff --git a/services/audiopolicy/config/Android.bp b/services/audiopolicy/config/Android.bp
index 4b5e788..f4610bb 100644
--- a/services/audiopolicy/config/Android.bp
+++ b/services/audiopolicy/config/Android.bp
@@ -92,6 +92,10 @@
     srcs: ["audio_policy_configuration_generic.xml"],
 }
 filegroup {
+    name: "audio_policy_configuration_generic_configurable",
+    srcs: ["audio_policy_configuration_generic_configurable.xml"],
+}
+filegroup {
     name: "usb_audio_policy_configuration",
     srcs: ["usb_audio_policy_configuration.xml"],
 }
diff --git a/services/audiopolicy/config/audio_policy_configuration_generic_configurable.xml b/services/audiopolicy/config/audio_policy_configuration_generic_configurable.xml
new file mode 100644
index 0000000..fbe4f7f
--- /dev/null
+++ b/services/audiopolicy/config/audio_policy_configuration_generic_configurable.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->
+
+    <!-- Global configuration Decalaration -->
+    <globalConfiguration speaker_drc_enabled="false" engine_library="configurable"/>
+
+    <modules>
+        <!-- Primary Audio HAL -->
+        <xi:include href="primary_audio_policy_configuration.xml"/>
+
+        <!-- Remote Submix Audio HAL -->
+        <xi:include href="r_submix_audio_policy_configuration.xml"/>
+
+    </modules>
+    <!-- End of Modules section -->
+
+    <!-- Volume section:
+        IMPORTANT NOTE: Volume tables have been moved to engine configuration.
+                        Keep it here for legacy.
+                        Engine will fallback on these files if none are provided by engine.
+     -->
+
+    <xi:include href="audio_policy_volumes.xml"/>
+    <xi:include href="default_volume_tables.xml"/>
+
+    <!-- End of Volume section -->
+
+    <!-- Surround Sound configuration -->
+
+    <xi:include href="surround_sound_configuration_5_0.xml"/>
+
+    <!-- End of Surround Sound configuration -->
+
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/config/audio_policy_volumes.xml b/services/audiopolicy/config/audio_policy_volumes.xml
index ec64a7c..ddd031a 100644
--- a/services/audiopolicy/config/audio_policy_volumes.xml
+++ b/services/audiopolicy/config/audio_policy_volumes.xml
@@ -181,6 +181,16 @@
                                                 ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
     <volume stream="AUDIO_STREAM_ACCESSIBILITY" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
                                                 ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_HEADSET"
+                                                ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                                                ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_EARPIECE"
+                                                ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
+                                                ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+    <volume stream="AUDIO_STREAM_ASSISTANT" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
+                                                ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
     <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_HEADSET"
                                             ref="FULL_SCALE_VOLUME_CURVE"/>
     <volume stream="AUDIO_STREAM_REROUTING" deviceCategory="DEVICE_CATEGORY_SPEAKER"
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 01efc7a..525e965 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -106,48 +106,33 @@
 
 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig()
 {
-    auto loadProductStrategies =
-            [](auto& strategyConfigs, auto& productStrategies, auto& volumeGroups) {
-        for (auto& strategyConfig : strategyConfigs) {
-            sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
-            for (const auto &group : strategyConfig.attributesGroups) {
-                const auto &iter = std::find_if(begin(volumeGroups), end(volumeGroups),
-                                         [&group](const auto &volumeGroup) {
-                        return group.volumeGroup == volumeGroup.second->getName(); });
-                ALOG_ASSERT(iter != end(volumeGroups), "Invalid Volume Group Name %s",
-                            group.volumeGroup.c_str());
-                if (group.stream != AUDIO_STREAM_DEFAULT) {
-                    iter->second->addSupportedStream(group.stream);
-                }
-                for (const auto &attr : group.attributesVect) {
-                    strategy->addAttributes({group.stream, iter->second->getId(), attr});
-                    iter->second->addSupportedAttributes(attr);
-                }
-            }
-            product_strategy_t strategyId = strategy->getId();
-            productStrategies[strategyId] = strategy;
-        }
-    };
-    auto loadVolumeGroups = [](auto &volumeConfigs, auto &volumeGroups) {
-        for (auto &volumeConfig : volumeConfigs) {
-            sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
-                                                          volumeConfig.indexMax);
-            volumeGroups[volumeGroup->getId()] = volumeGroup;
+    auto loadVolumeConfig = [](auto &volumeGroups, auto &volumeConfig) {
+        sp<VolumeGroup> volumeGroup = new VolumeGroup(volumeConfig.name, volumeConfig.indexMin,
+                                                      volumeConfig.indexMax);
+        volumeGroups[volumeGroup->getId()] = volumeGroup;
 
-            for (auto &configCurve : volumeConfig.volumeCurves) {
-                device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
-                if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
-                    ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
-                    continue;
-                }
-                sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
-                for (auto &point : configCurve.curvePoints) {
-                    curve->add({point.index, point.attenuationInMb});
-                }
-                volumeGroup->add(curve);
+        for (auto &configCurve : volumeConfig.volumeCurves) {
+            device_category deviceCat = DEVICE_CATEGORY_SPEAKER;
+            if (!DeviceCategoryConverter::fromString(configCurve.deviceCategory, deviceCat)) {
+                ALOGE("%s: Invalid %s", __FUNCTION__, configCurve.deviceCategory.c_str());
+                continue;
             }
+            sp<VolumeCurve> curve = new VolumeCurve(deviceCat);
+            for (auto &point : configCurve.curvePoints) {
+                curve->add({point.index, point.attenuationInMb});
+            }
+            volumeGroup->add(curve);
+        }
+        return volumeGroup;
+    };
+    auto addSupportedStreamAttributes = [](auto &group, auto &volumeGroup, auto &strategy) {
+        volumeGroup->addSupportedStream(group.stream);
+        for (const auto &attr : group.attributesVect) {
+            strategy->addAttributes({group.stream, volumeGroup->getId(), attr});
+            volumeGroup->addSupportedAttributes(attr);
         }
     };
+
     auto result = engineConfig::parse();
     if (result.parsedConfig == nullptr) {
         ALOGW("%s: No configuration found, using default matching phone experience.", __FUNCTION__);
@@ -156,10 +141,47 @@
         result = {std::make_unique<engineConfig::Config>(config),
                   static_cast<size_t>(ret == NO_ERROR ? 0 : 1)};
     }
+    // Append for internal use only strategies/volume groups (e.g. rerouting/patch)
+    result.parsedConfig->productStrategies.insert(
+                std::end(result.parsedConfig->productStrategies),
+                std::begin(gOrderedSystemStrategies), std::end(gOrderedSystemStrategies));
+
+    result.parsedConfig->volumeGroups.insert(
+                std::end(result.parsedConfig->volumeGroups),
+                std::begin(gSystemVolumeGroups), std::end(gSystemVolumeGroups));
+
     ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
-    loadVolumeGroups(result.parsedConfig->volumeGroups, mVolumeGroups);
-    loadProductStrategies(result.parsedConfig->productStrategies, mProductStrategies,
-                          mVolumeGroups);
+
+    engineConfig::VolumeGroup defaultVolumeConfig;
+    for (auto &volumeConfig : result.parsedConfig->volumeGroups) {
+        // save default volume config for streams not defined in configuration
+        if (volumeConfig.name.compare("AUDIO_STREAM_MUSIC") == 0) {
+            defaultVolumeConfig = volumeConfig;
+        }
+        loadVolumeConfig(mVolumeGroups, volumeConfig);
+    }
+    for (auto& strategyConfig : result.parsedConfig->productStrategies) {
+        sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
+        for (const auto &group : strategyConfig.attributesGroups) {
+            const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
+                                         [&group](const auto &volumeGroup) {
+                    return group.volumeGroup == volumeGroup.second->getName(); });
+            if (group.stream != AUDIO_STREAM_DEFAULT) {
+                if (iter == end(mVolumeGroups)) {
+                    ALOGW("%s: No configuration of %s found, using default volume configuration"
+                            , __FUNCTION__, group.volumeGroup.c_str());
+                    defaultVolumeConfig.name = group.volumeGroup;
+                    sp<VolumeGroup> volumeGroup =
+                            loadVolumeConfig(mVolumeGroups, defaultVolumeConfig);
+                    addSupportedStreamAttributes(group, volumeGroup, strategy);
+                } else {
+                    addSupportedStreamAttributes(group, iter->second, strategy);
+                }
+            }
+        }
+        product_strategy_t strategyId = strategy->getId();
+        mProductStrategies[strategyId] = strategy;
+    }
     mProductStrategies.initialize();
     return result;
 }
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index fede0d9..a3071d7 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -81,6 +81,10 @@
     },
     {"STRATEGY_MEDIA",
      {
+         {"assistant", AUDIO_STREAM_ASSISTANT, "AUDIO_STREAM_ASSISTANT",
+          {{AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
+            AUDIO_SOURCE_DEFAULT, 0, ""}}
+         },
          {"music", AUDIO_STREAM_MUSIC, "AUDIO_STREAM_MUSIC",
           {
               {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, 0, ""},
@@ -114,15 +118,22 @@
             AUDIO_FLAG_BEACON, ""}}
          }
      },
-    },
-    {"STRATEGY_REROUTING",
+    }
+};
+
+/**
+ * For Internal use of respectively audio policy and audioflinger
+ * For compatibility reason why apm volume config file, volume group name is the stream type.
+ */
+const engineConfig::ProductStrategies gOrderedSystemStrategies = {
+    {"rerouting",
      {
          {"", AUDIO_STREAM_REROUTING, "AUDIO_STREAM_REROUTING",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
          }
      },
     },
-    {"STRATEGY_PATCH",
+    {"patch",
      {
          {"", AUDIO_STREAM_PATCH, "AUDIO_STREAM_PATCH",
           {{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT, 0, ""}}
@@ -130,6 +141,28 @@
      },
     }
 };
+const engineConfig::VolumeGroups gSystemVolumeGroups = {
+    {"AUDIO_STREAM_REROUTING", 0, 1,
+     {
+         {"DEVICE_CATEGORY_SPEAKER", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_HEADSET", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_EARPIECE", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_EXT_MEDIA", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_HEARING_AID", {{0,0}, {100, 0}}},
+
+     }
+    },
+    {"AUDIO_STREAM_PATCH", 0, 1,
+     {
+         {"DEVICE_CATEGORY_SPEAKER", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_HEADSET", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_EARPIECE", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_EXT_MEDIA", {{0,0}, {100, 0}}},
+         {"DEVICE_CATEGORY_HEARING_AID", {{0,0}, {100, 0}}},
+
+     }
+    }
+};
 
 const engineConfig::Config gDefaultEngineConfig = {
     1.0,
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
index 885b5fa..ff840f9 100644
--- a/services/audiopolicy/engine/config/Android.bp
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -1,4 +1,4 @@
-cc_library_static {
+cc_library {
     name: "libaudiopolicyengine_config",
     export_include_dirs: ["include"],
     include_dirs: [
@@ -14,17 +14,14 @@
     ],
     shared_libs: [
         "libmedia_helper",
-        "libandroidicu",
         "libxml2",
         "libutils",
         "liblog",
         "libcutils",
     ],
-    static_libs: [
-        "libaudiopolicycomponents",
-    ],
     header_libs: [
         "libaudio_system_headers",
-        "libaudiopolicycommon",
+        "libmedia_headers",
+        "libaudioclient_headers",
     ],
 }
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index d47fbd2..7f8cdd9 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -18,7 +18,6 @@
 //#define LOG_NDEBUG 0
 
 #include "EngineConfig.h"
-#include <policy.h>
 #include <cutils/properties.h>
 #include <media/TypeConverter.h>
 #include <media/convert.h>
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
index 0ee83a2..f598cf2 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
@@ -84,7 +84,7 @@
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="voice_command">
-        <AttributesGroup volumeGroup="speech">
+        <AttributesGroup volumeGroup="speech" streamType="AUDIO_STREAM_ASSISTANT">
             <Attributes>
                 <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
                 <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
@@ -147,10 +147,6 @@
     <ProductStrategy name="notification">
         <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="ring">
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="system">
@@ -167,19 +163,5 @@
         </AttributesGroup>
     </ProductStrategy>
 
-    <!-- Routing Strategy rerouting may be removed as following media??? -->
-    <ProductStrategy name="rerouting">
-        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
-
-    <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
-    <ProductStrategy name="patch">
-        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
-
 </ProductStrategies>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
index 6e72dc5..97a25a8 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -189,25 +189,5 @@
         </volume>
     </volumeGroup>
 
-    <volumeGroup>
-        <name>rerouting</name>
-        <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
-            <point>0,0</point>
-            <point>100,0</point>
-        </volume>
-    </volumeGroup>
-
-    <volumeGroup>
-        <name>patch</name>
-        <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
-            <point>0,0</point>
-            <point>100,0</point>
-        </volume>
-    </volumeGroup>
-
 </volumeGroups>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
index adcbd83..f598cf2 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
@@ -84,7 +84,7 @@
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="voice_command">
-        <AttributesGroup volumeGroup="speech">
+        <AttributesGroup volumeGroup="speech" streamType="AUDIO_STREAM_ASSISTANT">
             <Attributes>
                 <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
                 <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
@@ -147,10 +147,6 @@
     <ProductStrategy name="notification">
         <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="ring">
             <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/> </Attributes>
-            <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
         </AttributesGroup>
     </ProductStrategy>
     <ProductStrategy name="system">
@@ -167,18 +163,5 @@
         </AttributesGroup>
     </ProductStrategy>
 
-    <!-- Routing Strategy rerouting may be removed as following media??? -->
-    <ProductStrategy name="rerouting">
-        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
-
-    <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
-    <ProductStrategy name="patch">
-        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
 </ProductStrategies>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
index 6e72dc5..97a25a8 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
@@ -189,25 +189,5 @@
         </volume>
     </volumeGroup>
 
-    <volumeGroup>
-        <name>rerouting</name>
-        <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
-            <point>0,0</point>
-            <point>100,0</point>
-        </volume>
-    </volumeGroup>
-
-    <volumeGroup>
-        <name>patch</name>
-        <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
-            <point>0,0</point>
-            <point>100,0</point>
-        </volume>
-    </volumeGroup>
-
 </volumeGroups>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in
index fe17369..e134c42 100644
--- a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in
+++ b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types.xml.in
@@ -22,7 +22,12 @@
             <value literal="0" numerical="1"/>
         </values>
     </criterion_type>
-    <criterion_type name="InputDevicesAddressesType" type="inclusive"/>
+    <criterion_type name="InputDevicesAddressesType" type="inclusive">
+        <values>
+            <!-- legacy remote submix -->
+            <value literal="0" numerical="1"/>
+        </values>
+    </criterion_type>
     <criterion_type name="AndroidModeType" type="exclusive"/>
     <criterion_type name="BooleanType" type="exclusive">
         <values>
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
index 9398743..a7388da 100644
--- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_product_strategies.xml
@@ -72,6 +72,12 @@
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
             <Attributes></Attributes>
         </AttributesGroup>
+        <AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
+            <Attributes>
+                <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+                <Usage value="AUDIO_USAGE_ASSISTANT"/>
+            </Attributes>
+        </AttributesGroup>
         <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
         </AttributesGroup>
@@ -91,20 +97,5 @@
         </AttributesGroup>
     </ProductStrategy>
 
-    <!-- Routing Strategy rerouting may be removed as following media??? -->
-    <ProductStrategy name="STRATEGY_REROUTING">
-        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
-
-    <!-- Default product strategy has empty attributes -->
-    <ProductStrategy name="STRATEGY_PATCH">
-        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
-
-
 </ProductStrategies>
 
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
index 707a184..8aa71ca 100644
--- a/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/audio_policy_engine_stream_volumes.xml
@@ -205,27 +205,16 @@
         <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
         <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
     </volumeGroup>
-
     <volumeGroup>
-        <name>rerouting</name>
+        <name>assistant</name>
         <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID"  ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
     </volumeGroup>
 
-    <volumeGroup>
-        <name>patch</name>
-        <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
-    </volumeGroup>
 </volumeGroups>
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
index a0b874a..90ebffd 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
@@ -31,9 +31,13 @@
 prebuilt_etc {
     name: "PolicySubsystem-CommonTypes.xml",
     vendor: true,
-    src: ":PolicySubsystem-CommonTypes",
+    src: ":buildcommontypesstructure_gen",
     sub_dir: "parameter-framework/Structure/Policy",
 }
+genrule {
+    name: "buildcommontypesstructure_gen",
+    defaults: ["buildcommontypesstructurerule"],
+}
 
 filegroup {
     name: "product_strategies_structure_template",
@@ -48,8 +52,8 @@
     srcs: ["examples/common/Structure/PolicySubsystem-no-strategy.xml"],
 }
 filegroup {
-    name: "PolicySubsystem-CommonTypes",
-    srcs: ["examples/common/Structure/PolicySubsystem-CommonTypes.xml"],
+    name: "common_types_structure_template",
+    srcs: ["examples/common/Structure/PolicySubsystem-CommonTypes.xml.in"],
 }
 filegroup {
     name: "PolicyClass",
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
index 5078268..82b1b6d 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
@@ -85,7 +85,7 @@
     srcs: [
         ":PolicyClass",
         ":PolicySubsystem",
-        ":PolicySubsystem-CommonTypes",
+        ":buildcommontypesstructure_gen",
         ":buildstrategiesstructure_gen",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
index 57ad592..ddae356 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Settings/device_for_product_strategies.pfw
@@ -14,7 +14,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -59,7 +59,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -106,7 +106,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -152,7 +152,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -205,7 +205,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -251,7 +251,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -304,7 +304,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -357,7 +357,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -411,7 +411,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -464,7 +464,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -517,7 +517,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -570,7 +570,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -623,7 +623,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -676,7 +676,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -729,7 +729,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
index 0917440..e4605b2 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
@@ -86,7 +86,7 @@
     srcs: [
         ":PolicyClass",
         ":PolicySubsystem",
-        ":PolicySubsystem-CommonTypes",
+        ":buildcommontypesstructure_gen",
         ":buildstrategiesstructure_gen",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
index ca3464f..cc778df 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Settings/device_for_product_strategies.pfw
@@ -14,7 +14,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -59,7 +59,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -106,7 +106,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -153,7 +153,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -198,7 +198,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -245,7 +245,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -291,7 +291,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -337,7 +337,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -384,7 +384,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -430,7 +430,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -476,7 +476,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -522,7 +522,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -568,7 +568,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -614,7 +614,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -659,7 +659,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
index 11e220b..61b54cf 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
@@ -94,7 +94,7 @@
     srcs: [
         ":PolicyClass",
         ":PolicySubsystem",
-        ":PolicySubsystem-CommonTypes",
+        ":buildcommontypesstructure_gen",
         ":buildstrategiesstructure_gen",
     ],
 }
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw
index 53e93de..d16a904 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_accessibility.pfw
@@ -45,7 +45,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -73,7 +73,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -101,7 +101,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -129,7 +129,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -157,7 +157,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -186,7 +186,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -215,7 +215,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -244,7 +244,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -281,7 +281,7 @@
 					wired_headset = 0
 					wired_headphone = 1
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -317,7 +317,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 1
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -354,7 +354,7 @@
 					wired_headset = 1
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -394,7 +394,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 1
@@ -425,7 +425,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 1
 					usb_device = 0
@@ -455,7 +455,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 1
 					usb_accessory = 0
 					usb_device = 0
@@ -485,7 +485,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -517,7 +517,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 1
+					anlg_dock_headset = 1
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -546,7 +546,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -568,7 +568,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -588,7 +588,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw
index b8426c6..414445d 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_dtmf.pfw
@@ -34,7 +34,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -62,7 +62,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -90,7 +90,7 @@
 					bluetooth_a2dp_headphones = 1
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -118,7 +118,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 1
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -147,7 +147,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -176,7 +176,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -205,7 +205,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -242,7 +242,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -281,7 +281,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -318,7 +318,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -358,7 +358,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 1
@@ -389,7 +389,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 1
 					usb_device = 0
@@ -419,7 +419,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 1
 					usb_accessory = 0
 					usb_device = 0
@@ -449,7 +449,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 1
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -481,7 +481,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 1
+					anlg_dock_headset = 1
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -510,7 +510,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -548,7 +548,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -568,7 +568,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw
index 2daa9ac..36b8f3c 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_enforced_audible.pfw
@@ -77,7 +77,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -100,7 +100,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -123,7 +123,7 @@
 					bluetooth_a2dp_headphones = 1
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -146,7 +146,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 1
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -169,7 +169,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -192,7 +192,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -215,7 +215,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -238,7 +238,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 1
 					usb_device = 0
@@ -261,7 +261,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 1
@@ -284,7 +284,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 1
 					usb_accessory = 0
 					usb_device = 0
@@ -307,7 +307,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 1
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -331,7 +331,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 1
+					anlg_dock_headset = 1
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -351,7 +351,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw
index d6d355c..6210a57 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_media.pfw
@@ -26,7 +26,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -46,7 +46,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -66,7 +66,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -86,7 +86,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -109,7 +109,7 @@
 					speaker = 1
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -127,7 +127,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -145,7 +145,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -163,7 +163,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 1
@@ -181,7 +181,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 1
 					wired_headset = 0
@@ -199,7 +199,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 1
 					usb_accessory = 0
 					wired_headset = 0
@@ -217,7 +217,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 1
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -235,7 +235,7 @@
 					speaker = 0
 					hdmi = 1
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -254,7 +254,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 1
+					anlg_dock_headset = 1
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -277,7 +277,7 @@
 					speaker = 1
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
@@ -293,7 +293,7 @@
 					speaker = 0
 					hdmi = 0
 					dgtl_dock_headset = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					usb_device = 0
 					usb_accessory = 0
 					wired_headset = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
index d2cc090..feeeec6 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_patch.pfw
@@ -14,7 +14,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw
index 5693d4e..da2fc9b 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_phone.pfw
@@ -32,7 +32,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -55,7 +55,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -78,7 +78,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -108,7 +108,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -138,7 +138,7 @@
 					bluetooth_a2dp_headphones = 1
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -168,7 +168,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 1
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -195,7 +195,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -222,7 +222,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -245,7 +245,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -283,7 +283,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 1
@@ -311,7 +311,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 1
@@ -339,7 +339,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 1
 					usb_accessory = 0
 					usb_device = 0
@@ -367,7 +367,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 1
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -395,7 +395,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 1
+					anlg_dock_headset = 1
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -422,7 +422,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -449,7 +449,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -472,7 +472,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
index 10f8814..3275cdf 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_rerouting.pfw
@@ -14,7 +14,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw
index c4edeeb..a60445b 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification.pfw
@@ -69,7 +69,7 @@
 					bluetooth_a2dp = 1
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -95,7 +95,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 1
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -121,7 +121,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 1
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -148,7 +148,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -175,7 +175,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -202,7 +202,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -238,7 +238,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -276,7 +276,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -312,7 +312,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -349,7 +349,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 1
@@ -378,7 +378,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 1
 					usb_device = 0
@@ -407,7 +407,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 1
 					usb_accessory = 0
 					usb_device = 0
@@ -437,7 +437,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 1
+					anlg_dock_headset = 1
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -464,7 +464,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -482,7 +482,7 @@
 					bluetooth_a2dp = 0
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw
index 0a3dd5f..6b11e23 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_sonification_respectful.pfw
@@ -92,7 +92,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -119,7 +119,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -146,7 +146,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -173,7 +173,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -200,7 +200,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -227,7 +227,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -264,7 +264,7 @@
 					wired_headset = 0
 					wired_headphone = 1
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -305,7 +305,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 1
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -342,7 +342,7 @@
 					wired_headset = 1
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -380,7 +380,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 1
@@ -410,7 +410,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 1
 					usb_device = 0
@@ -440,7 +440,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 1
 					usb_accessory = 0
 					usb_device = 0
@@ -470,7 +470,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -501,7 +501,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 1
+					anlg_dock_headset = 1
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
@@ -528,7 +528,7 @@
 					wired_headset = 0
 					wired_headphone = 0
 					line = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw
index 3fc7670..418f3cc 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Settings/device_for_product_strategy_transmitted_through_speaker.pfw
@@ -19,7 +19,7 @@
 					bluetooth_a2dp_headphones = 0
 					bluetooth_a2dp_speaker = 0
 					hdmi = 0
-					angl_dock_headset = 0
+					anlg_dock_headset = 0
 					dgtl_dock_headset = 0
 					usb_accessory = 0
 					usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
index 0710441..baffa81 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/PolicyConfigurableDomains.xml
@@ -145,7 +145,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/speaker"/>
       <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/hdmi"/>
       <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device"/>
       <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/wired_headset"/>
@@ -167,8 +167,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -208,8 +208,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -249,8 +249,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -290,8 +290,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -331,8 +331,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -372,8 +372,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -413,8 +413,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -454,8 +454,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -495,8 +495,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -536,8 +536,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">1</BitParameter>
@@ -577,8 +577,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -618,8 +618,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -659,8 +659,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -700,8 +700,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -741,8 +741,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/media/selected_output_devices/mask/usb_device">
           <BitParameter Name="usb_device">0</BitParameter>
@@ -1039,7 +1039,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
       <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
       <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/usb_device"/>
@@ -1079,8 +1079,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1132,8 +1132,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1185,8 +1185,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1238,8 +1238,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1291,8 +1291,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1344,8 +1344,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1397,8 +1397,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1450,8 +1450,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1503,8 +1503,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1556,8 +1556,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1609,8 +1609,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1662,8 +1662,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -1715,8 +1715,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1768,8 +1768,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1821,8 +1821,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1874,8 +1874,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -1927,8 +1927,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/phone/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2228,7 +2228,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/usb_device"/>
@@ -2264,8 +2264,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2311,8 +2311,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2358,8 +2358,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2405,8 +2405,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2452,8 +2452,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2499,8 +2499,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2546,8 +2546,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2593,8 +2593,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2640,8 +2640,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2687,8 +2687,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2734,8 +2734,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2781,8 +2781,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -2828,8 +2828,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2875,8 +2875,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -2922,8 +2922,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/bluetooth_a2dp_speaker">
           <BitParameter Name="bluetooth_a2dp_speaker">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3246,7 +3246,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/wired_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/wired_headphone"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/usb_device"/>
@@ -3284,8 +3284,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3331,8 +3331,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3378,8 +3378,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3425,8 +3425,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3472,8 +3472,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3519,8 +3519,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3566,8 +3566,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3613,8 +3613,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3660,8 +3660,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3707,8 +3707,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3754,8 +3754,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3801,8 +3801,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -3848,8 +3848,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3895,8 +3895,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -3942,8 +3942,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/sonification_respectful/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4207,7 +4207,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
       <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
       <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/usb_device"/>
@@ -4247,8 +4247,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4300,8 +4300,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4353,8 +4353,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4406,8 +4406,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4459,8 +4459,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4512,8 +4512,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4565,8 +4565,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4618,8 +4618,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4671,8 +4671,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4724,8 +4724,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4777,8 +4777,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4830,8 +4830,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4883,8 +4883,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -4936,8 +4936,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -4989,8 +4989,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5042,8 +5042,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5095,8 +5095,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5148,8 +5148,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/dtmf/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5448,7 +5448,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
       <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
       <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/usb_device"/>
@@ -5490,8 +5490,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5543,8 +5543,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5596,8 +5596,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5649,8 +5649,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5702,8 +5702,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5755,8 +5755,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5808,8 +5808,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5861,8 +5861,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5914,8 +5914,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -5967,8 +5967,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -6020,8 +6020,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6073,8 +6073,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6126,8 +6126,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/enforced_audible/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6170,7 +6170,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/bluetooth_a2dp_headphones"/>
       <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/bluetooth_a2dp_speaker"/>
       <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/hdmi"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/usb_device"/>
@@ -6230,8 +6230,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/hdmi">
           <BitParameter Name="hdmi">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/transmitted_through_speaker/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6539,7 +6539,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/wired_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/wired_headphone"/>
       <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/usb_device"/>
@@ -6583,8 +6583,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6636,8 +6636,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6689,8 +6689,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6742,8 +6742,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6795,8 +6795,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6848,8 +6848,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6901,8 +6901,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -6954,8 +6954,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7007,8 +7007,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7060,8 +7060,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7113,8 +7113,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7166,8 +7166,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7219,8 +7219,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7272,8 +7272,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -7325,8 +7325,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7378,8 +7378,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7431,8 +7431,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7484,8 +7484,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7537,8 +7537,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/accessibility/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7710,7 +7710,7 @@
       <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/wired_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/wired_headphone"/>
       <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line"/>
-      <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset"/>
+      <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset"/>
       <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/usb_accessory"/>
       <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/usb_device"/>
@@ -7742,8 +7742,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7783,8 +7783,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7824,8 +7824,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7865,8 +7865,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7906,8 +7906,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7947,8 +7947,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -7988,8 +7988,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">1</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8029,8 +8029,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8070,8 +8070,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8111,8 +8111,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8152,8 +8152,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">1</BitParameter>
@@ -8193,8 +8193,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8234,8 +8234,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">1</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">1</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8275,8 +8275,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
@@ -8316,8 +8316,8 @@
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/line">
           <BitParameter Name="line">0</BitParameter>
         </ConfigurableElement>
-        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/angl_dock_headset">
-          <BitParameter Name="angl_dock_headset">0</BitParameter>
+        <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/anlg_dock_headset">
+          <BitParameter Name="anlg_dock_headset">0</BitParameter>
         </ConfigurableElement>
         <ConfigurableElement Path="/Policy/policy/strategies/rerouting/selected_output_devices/mask/dgtl_dock_headset">
           <BitParameter Name="dgtl_dock_headset">0</BitParameter>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw
index 7db4537..cf1857e 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/volumes.pfw
@@ -11,6 +11,7 @@
 			/Policy/policy/streams/enforced_audible/applicable_volume_profile/volume_profile = enforced_audible
 			/Policy/policy/streams/tts/applicable_volume_profile/volume_profile = tts
 			/Policy/policy/streams/accessibility/applicable_volume_profile/volume_profile = accessibility
+			/Policy/policy/streams/assistant/applicable_volume_profile/volume_profile = assistant
 			/Policy/policy/streams/rerouting/applicable_volume_profile/volume_profile = rerouting
 			/Policy/policy/streams/patch/applicable_volume_profile/volume_profile = patch
 
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
index ffd494e..9abcb70 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
@@ -55,7 +55,7 @@
     srcs: [
         ":PolicyClass",
         ":PolicySubsystem",
-        ":PolicySubsystem-CommonTypes",
+        ":buildcommontypesstructure_gen",
     ],
 }
 filegroup {
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
index 6fca048..27172a4 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
@@ -54,7 +54,7 @@
     srcs: [
         ":PolicyClass",
         ":PolicySubsystem",
-        ":PolicySubsystem-CommonTypes",
+        ":buildcommontypesstructure_gen",
     ],
 }
 filegroup {
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
index f923610..e259c00 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/device_for_strategies.pfw
@@ -13,7 +13,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -41,7 +41,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -69,7 +69,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -97,7 +97,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -125,7 +125,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -153,7 +153,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -181,7 +181,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -209,7 +209,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
@@ -237,7 +237,7 @@
 				bluetooth_a2dp_headphones = 0
 				bluetooth_a2dp_speaker = 0
 				hdmi = 0
-				angl_dock_headset = 0
+				anlg_dock_headset = 0
 				dgtl_dock_headset = 0
 				usb_accessory = 0
 				usb_device = 0
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
deleted file mode 100644
index d17c021..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml
+++ /dev/null
@@ -1,186 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-              xmlns:xi="http://www.w3.org/2001/XInclude"
-              xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
-    <!-- Output devices definition as a bitfield for the supported devices per output
-    profile. It must match with the output device enum parameter.
-    -->
-     <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
-
-     <!--#################### GLOBAL COMPONENTS END ####################-->
-
-    <ComponentType Name="OutputDevicesMask" Description="32th bit is not allowed as dedicated
-                                                     for input devices detection">
-        <BitParameterBlock Name="mask" Size="32">
-            <BitParameter Name="earpiece" Size="1" Pos="0"/>
-            <BitParameter Name="speaker" Size="1" Pos="1"/>
-            <BitParameter Name="wired_headset" Size="1" Pos="2"/>
-            <BitParameter Name="wired_headphone" Size="1" Pos="3"/>
-            <BitParameter Name="bluetooth_sco" Size="1" Pos="4"/>
-            <BitParameter Name="bluetooth_sco_headset" Size="1" Pos="5"/>
-            <BitParameter Name="bluetooth_sco_carkit" Size="1" Pos="6"/>
-            <BitParameter Name="bluetooth_a2dp" Size="1" Pos="7"/>
-            <BitParameter Name="bluetooth_a2dp_headphones" Size="1" Pos="8"/>
-            <BitParameter Name="bluetooth_a2dp_speaker" Size="1" Pos="9"/>
-            <BitParameter Name="hdmi" Size="1" Pos="10"/>
-            <BitParameter Name="angl_dock_headset" Size="1" Pos="11"/>
-            <BitParameter Name="dgtl_dock_headset" Size="1" Pos="12"/>
-            <BitParameter Name="usb_accessory" Size="1" Pos="13"/>
-            <BitParameter Name="usb_device" Size="1" Pos="14"/>
-            <BitParameter Name="remote_submix" Size="1" Pos="15"/>
-            <BitParameter Name="telephony_tx" Size="1" Pos="16"/>
-            <BitParameter Name="line" Size="1" Pos="17"/>
-            <BitParameter Name="hdmi_arc" Size="1" Pos="18"/>
-            <BitParameter Name="spdif" Size="1" Pos="19"/>
-            <BitParameter Name="fm" Size="1" Pos="20"/>
-            <BitParameter Name="aux_line" Size="1" Pos="21"/>
-            <BitParameter Name="speaker_safe" Size="1" Pos="22"/>
-            <BitParameter Name="ip" Size="1" Pos="23"/>
-            <BitParameter Name="bus" Size="1" Pos="24"/>
-            <BitParameter Name="proxy" Size="1" Pos="25"/>
-            <BitParameter Name="usb_headset" Size="1" Pos="26"/>
-            <BitParameter Name="hearing_aid" Size="1" Pos="27"/>
-            <BitParameter Name="echo_canceller" Size="1" Pos="28"/>
-            <BitParameter Name="stub" Size="1" Pos="30"/>
-        </BitParameterBlock>
-    </ComponentType>
-
-    <!-- Input devices definition as a bitfield for the supported devices per Input
-    profile. It must match with the Input device enum parameter.
-    -->
-    <ComponentType Name="InputDevicesMask">
-        <BitParameterBlock Name="mask" Size="32">
-            <BitParameter Name="communication" Size="1" Pos="0"/>
-            <BitParameter Name="ambient" Size="1" Pos="1"/>
-            <BitParameter Name="builtin_mic" Size="1" Pos="2"/>
-            <BitParameter Name="bluetooth_sco_headset" Size="1" Pos="3"/>
-            <BitParameter Name="wired_headset" Size="1" Pos="4"/>
-            <BitParameter Name="hdmi" Size="1" Pos="5"/>
-            <BitParameter Name="telephony_rx" Size="1" Pos="6"/>
-            <BitParameter Name="back_mic" Size="1" Pos="7"/>
-            <BitParameter Name="remote_submix" Size="1" Pos="8"/>
-            <BitParameter Name="anlg_dock_headset" Size="1" Pos="9"/>
-            <BitParameter Name="dgtl_dock_headset" Size="1" Pos="10"/>
-            <BitParameter Name="usb_accessory" Size="1" Pos="11"/>
-            <BitParameter Name="usb_device" Size="1" Pos="12"/>
-            <BitParameter Name="fm_tuner" Size="1" Pos="13"/>
-            <BitParameter Name="tv_tuner" Size="1" Pos="14"/>
-            <BitParameter Name="line" Size="1" Pos="15"/>
-            <BitParameter Name="spdif" Size="1" Pos="16"/>
-            <BitParameter Name="bluetooth_a2dp" Size="1" Pos="17"/>
-            <BitParameter Name="loopback" Size="1" Pos="18"/>
-            <BitParameter Name="ip" Size="1" Pos="19"/>
-            <BitParameter Name="bus" Size="1" Pos="20"/>
-            <BitParameter Name="proxy" Size="1" Pos="21"/>
-            <BitParameter Name="usb_headset" Size="1" Pos="22"/>
-            <BitParameter Name="bluetooth_ble" Size="1" Pos="23"/>
-            <BitParameter Name="hdmi_arc" Size="1" Pos="24"/>
-            <BitParameter Name="echo_reference" Size="1" Pos="25"/>
-            <BitParameter Name="stub" Size="1" Pos="30"/>
-        </BitParameterBlock>
-    </ComponentType>
-
-    <ComponentType Name="OutputFlags"
-                   Description="the audio output flags serve two purposes:
-                    - when an AudioTrack is created they indicate a wish to be connected to an
-                      output stream with attributes corresponding to the specified flags.
-                    - when present in an output profile descriptor listed for a particular audio
-                      hardware module, they indicate that an output stream can be opened that
-                      supports the attributes indicated by the flags.
-                    The audio policy manager will try to match the flags in the request
-                    (when getOuput() is called) to an available output stream.">
-        <BitParameterBlock Name="mask" Size="32">
-            <BitParameter Name="direct" Size="1" Pos="0"/>
-            <BitParameter Name="primary" Size="1" Pos="1"/>
-            <BitParameter Name="fast" Size="1" Pos="2"/>
-            <BitParameter Name="deep_buffer" Size="1" Pos="3"/>
-            <BitParameter Name="compress_offload" Size="1" Pos="4"/>
-            <BitParameter Name="non_blocking" Size="1" Pos="5"/>
-            <BitParameter Name="hw_av_sync" Size="1" Pos="6"/>
-            <BitParameter Name="tts" Size="1" Pos="7"/>
-            <BitParameter Name="raw" Size="1" Pos="8"/>
-            <BitParameter Name="sync" Size="1" Pos="9"/>
-            <BitParameter Name="iec958_nonaudio" Size="1" Pos="10"/>
-        </BitParameterBlock>
-    </ComponentType>
-
-    <ComponentType Name="InputFlags"
-                   Description="The audio input flags are analogous to audio output flags.
-                                Currently they are used only when an AudioRecord is created,
-                                to indicate a preference to be connected to an input stream with
-                                attributes corresponding to the specified flags.">
-        <BitParameterBlock Name="mask" Size="32">
-            <BitParameter Name="fast" Size="1" Pos="0"/>
-            <BitParameter Name="hw_hotword" Size="1" Pos="2"/>
-            <BitParameter Name="raw" Size="1" Pos="3"/>
-            <BitParameter Name="sync" Size="1" Pos="4"/>
-        </BitParameterBlock>
-    </ComponentType>
-
-    <ComponentType Name="InputSourcesMask" Description="The audio input source is also known
-                                                        as the use case.">
-        <BitParameterBlock Name="mask" Size="32">
-            <BitParameter Name="default" Size="1" Pos="0"/>
-            <BitParameter Name="mic" Size="1" Pos="1"/>
-            <BitParameter Name="voice_uplink" Size="1" Pos="2"/>
-            <BitParameter Name="voice_downlink" Size="1" Pos="3"/>
-            <BitParameter Name="voice_call" Size="1" Pos="4"/>
-            <BitParameter Name="camcorder" Size="1" Pos="5"/>
-            <BitParameter Name="voice_recognition" Size="1" Pos="6"/>
-            <BitParameter Name="voice_communication" Size="1" Pos="7"/>
-            <BitParameter Name="remote_submix" Size="1" Pos="8"/>
-            <BitParameter Name="unprocessed" Size="1" Pos="9"/>
-            <BitParameter Name="voice_performance" Size="1" Pos="10"/>
-            <BitParameter Name="echo_reference" Size="1" Pos="11"/>
-            <BitParameter Name="fm_tuner" Size="1" Pos="12"/>
-            <BitParameter Name="hotword" Size="1" Pos="13"/>
-        </BitParameterBlock>
-    </ComponentType>
-
-    <!--#################### STREAM COMMON TYPES BEGIN ####################-->
-
-    <ComponentType Name="VolumeProfileType">
-        <EnumParameter Name="volume_profile" Size="32">
-            <ValuePair Literal="voice_call" Numerical="0"/>
-            <ValuePair Literal="system" Numerical="1"/>
-            <ValuePair Literal="ring" Numerical="2"/>
-            <ValuePair Literal="music" Numerical="3"/>
-            <ValuePair Literal="alarm" Numerical="4"/>
-            <ValuePair Literal="notification" Numerical="5"/>
-            <ValuePair Literal="bluetooth_sco" Numerical="6"/>
-            <ValuePair Literal="enforced_audible" Numerical="7"/>
-            <ValuePair Literal="dtmf" Numerical="8"/>
-            <ValuePair Literal="tts" Numerical="9"/>
-            <ValuePair Literal="accessibility" Numerical="10"/>
-            <ValuePair Literal="rerouting" Numerical="11"/>
-            <ValuePair Literal="patch" Numerical="12"/>
-        </EnumParameter>
-    </ComponentType>
-
-    <ComponentType Name="Stream"  Mapping="Stream">
-        <Component Name="applicable_volume_profile" Type="VolumeProfileType"
-                   Description="Volume profile followed by a given stream type."/>
-    </ComponentType>
-
-    <!--#################### STREAM COMMON TYPES END ####################-->
-
-    <!--#################### INPUT SOURCE COMMON TYPES BEGIN ####################-->
-
-    <ComponentType Name="InputSource">
-        <Component Name="applicable_input_device" Type="InputDevicesMask"
-                   Mapping="InputSource" Description="Selected Input device"/>
-    </ComponentType>
-
-    <!--#################### INPUT SOURCE COMMON TYPES END ####################-->
-
-    <!--#################### PRODUCT STRATEGY COMMON TYPES BEGIN ####################-->
-
-    <ComponentType Name="ProductStrategy" Mapping="ProductStrategy">
-        <Component Name="selected_output_devices" Type="OutputDevicesMask"/>
-        <StringParameter Name="device_address" MaxLength="256"
-                         Description="if any, device address associated"/>
-    </ComponentType>
-
-    <!--#################### PRODUCT STRATEGY COMMON TYPES END ####################-->
-
-</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in
new file mode 100644
index 0000000..2e9f37e
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-CommonTypes.xml.in
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xmlns:xi="http://www.w3.org/2001/XInclude"
+              xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+    <!-- Output devices definition as a bitfield for the supported devices per output
+    profile. It must match with the output device enum parameter.
+    -->
+     <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
+
+     <!--#################### GLOBAL COMPONENTS END ####################-->
+
+    <!-- Automatically filled from audio-base.h file -->
+    <ComponentType Name="OutputDevicesMask" Description="32th bit is not allowed as dedicated for input devices detection">
+        <BitParameterBlock Name="mask" Size="32">
+        </BitParameterBlock>
+    </ComponentType>
+
+    <!-- Input devices definition as a bitfield for the supported devices per Input
+    profile. It must match with the Input device enum parameter.
+    -->
+    <!-- Automatically filled from audio-base.h file -->
+    <ComponentType Name="InputDevicesMask">
+        <BitParameterBlock Name="mask" Size="32">
+        </BitParameterBlock>
+    </ComponentType>
+
+    <!--#################### STREAM COMMON TYPES BEGIN ####################-->
+    <!-- Automatically filled from audio-base.h file. VolumeProfileType is associated to stream type -->
+    <ComponentType Name="VolumeProfileType">
+        <EnumParameter Name="volume_profile" Size="32">
+        </EnumParameter>
+    </ComponentType>
+
+    <ComponentType Name="Stream"  Mapping="Stream">
+        <Component Name="applicable_volume_profile" Type="VolumeProfileType"
+                   Description="Volume profile followed by a given stream type."/>
+    </ComponentType>
+
+    <!--#################### STREAM COMMON TYPES END ####################-->
+
+    <!--#################### INPUT SOURCE COMMON TYPES BEGIN ####################-->
+
+    <ComponentType Name="InputSource">
+        <Component Name="applicable_input_device" Type="InputDevicesMask"
+                   Mapping="InputSource" Description="Selected Input device"/>
+    </ComponentType>
+
+    <!--#################### INPUT SOURCE COMMON TYPES END ####################-->
+
+    <!--#################### PRODUCT STRATEGY COMMON TYPES BEGIN ####################-->
+
+    <ComponentType Name="ProductStrategy" Mapping="ProductStrategy">
+        <Component Name="selected_output_devices" Type="OutputDevicesMask"/>
+        <StringParameter Name="device_address" MaxLength="256"
+                         Description="if any, device address associated"/>
+    </ComponentType>
+
+    <!--#################### PRODUCT STRATEGY COMMON TYPES END ####################-->
+
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
index a4e7537..ed349c8 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem-no-strategy.xml
@@ -28,6 +28,8 @@
                              Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
             <Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
                              Description="For accessibility talk back prompts"/>
+            <Component Name="assistant" Type="Stream" Mapping="Name:AUDIO_STREAM_ASSISTANT"
+                             Description="used by a virtual assistant like Google Assistant, Bixby, etc."/>
             <Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
                              Description="For dynamic policy output mixes"/>
             <Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
index 585ce87..7bbb57a 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
@@ -44,6 +44,8 @@
                              Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
             <Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
                              Description="For accessibility talk back prompts"/>
+            <Component Name="assistant" Type="Stream" Mapping="Name:AUDIO_STREAM_ASSISTANT"
+                             Description="used by a virtual assistant like Google Assistant, Bixby, etc."/>
             <Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
                              Description="For dynamic policy output mixes"/>
             <Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 752ba92..6d42fcf 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -80,8 +80,9 @@
 
 status_t Engine::initCheck()
 {
-    if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start() != NO_ERROR) {
-        ALOGE("%s: could not start Policy PFW", __FUNCTION__);
+    std::string error;
+    if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
+        ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
         return NO_INIT;
     }
     return EngineBase::initCheck();
@@ -128,7 +129,7 @@
     Element<Key> *element = getFromCollection<Key>(key);
     if (element == NULL) {
         ALOGE("%s: Element not found within collection", __FUNCTION__);
-        return BAD_VALUE;
+        return false;
     }
     return element->template set<Property>(property) == NO_ERROR;
 }
@@ -162,21 +163,21 @@
     return mPolicyParameterMgr->getForceUse(usage);
 }
 
-status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> device,
                                           audio_policy_dev_state_t state)
 {
-    mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
-
-    if (audio_is_output_device(devDesc->type())) {
+    mPolicyParameterMgr->setDeviceConnectionState(
+                device->type(), device->address().c_str(), state);
+    if (audio_is_output_device(device->type())) {
         // FIXME: Use DeviceTypeSet when the interface is ready
         return mPolicyParameterMgr->setAvailableOutputDevices(
                     deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
-    } else if (audio_is_input_device(devDesc->type())) {
+    } else if (audio_is_input_device(device->type())) {
         // FIXME: Use DeviceTypeSet when the interface is ready
         return mPolicyParameterMgr->setAvailableInputDevices(
                     deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
     }
-    return EngineBase::setDeviceConnectionState(devDesc, state);
+    return EngineBase::setDeviceConnectionState(device, state);
 }
 
 status_t Engine::loadAudioPolicyEngineConfig()
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.cpp b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
index d252d3f..aa06ae3 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.cpp
@@ -30,7 +30,7 @@
         return BAD_VALUE;
     }
     mIdentifier = identifier;
-    ALOGD("%s: InputSource %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
+    ALOGV("%s: InputSource %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
     return NO_ERROR;
 }
 
@@ -46,15 +46,18 @@
 template <>
 status_t Element<audio_source_t>::set(audio_devices_t devices)
 {
-    if (devices != AUDIO_DEVICE_NONE) {
-        devices |= AUDIO_DEVICE_BIT_IN;
+    if (devices == AUDIO_DEVICE_NONE) {
+        // Reset
+        mApplicableDevices = devices;
+        return NO_ERROR;
     }
+    devices |= AUDIO_DEVICE_BIT_IN;
     if (!audio_is_input_device(devices)) {
         ALOGE("%s: trying to set an invalid device 0x%X for input source %s",
               __FUNCTION__, devices, getName().c_str());
         return BAD_VALUE;
     }
-    ALOGD("%s: 0x%X for input source %s", __FUNCTION__, devices, getName().c_str());
+    ALOGV("%s: 0x%X for input source %s", __FUNCTION__, devices, getName().c_str());
     mApplicableDevices = devices;
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/engineconfigurable/src/InputSource.h b/services/audiopolicy/engineconfigurable/src/InputSource.h
index e1865cc..d64a60a 100644
--- a/services/audiopolicy/engineconfigurable/src/InputSource.h
+++ b/services/audiopolicy/engineconfigurable/src/InputSource.h
@@ -73,10 +73,11 @@
     Element(const Element &object);
     Element &operator=(const Element &object);
 
-    std::string mName; /**< Unique literal Identifier of a policy base element*/
-    audio_source_t mIdentifier; /**< Unique numerical Identifier of a policy base element*/
-
-    audio_devices_t mApplicableDevices; /**< Applicable input device for this input source. */
+    const std::string mName; /**< Unique literal Identifier of a policy base element*/
+    /** Unique numerical Identifier of a policy base element */
+    audio_source_t mIdentifier = AUDIO_SOURCE_DEFAULT;
+    /** Applicable input device for this input source. */
+    audio_devices_t mApplicableDevices = AUDIO_DEVICE_NONE;
 };
 
 typedef Element<audio_source_t> InputSource;
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.cpp b/services/audiopolicy/engineconfigurable/src/Stream.cpp
index 297eb02..e64ba4b 100644
--- a/services/audiopolicy/engineconfigurable/src/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp
@@ -30,7 +30,7 @@
         return BAD_VALUE;
     }
     mIdentifier = identifier;
-    ALOGD("%s: Stream %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
+    ALOGV("%s: Stream %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier);
     return NO_ERROR;
 }
 
@@ -41,7 +41,7 @@
         return BAD_VALUE;
     }
     mVolumeProfile = volumeProfile;
-    ALOGD("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
+    ALOGV("%s: 0x%X for Stream %s", __FUNCTION__, mVolumeProfile, getName().c_str());
     return NO_ERROR;
 }
 
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index d9e97af..3e47324 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -133,3 +133,29 @@
     ],
     out: ["ProductStrategies.xml"],
 }
+
+//##################################################################################################
+// Tools for policy parameter-framework common type structure file generation
+//
+python_binary_host {
+    name: "buildCommonTypesStructureFile.py",
+    main: "buildCommonTypesStructureFile.py",
+    srcs: [
+        "buildCommonTypesStructureFile.py",
+    ],
+    defaults: ["tools_default"],
+}
+
+genrule_defaults {
+    name: "buildcommontypesstructurerule",
+    tools: ["buildCommonTypesStructureFile.py"],
+    cmd: "$(location buildCommonTypesStructureFile.py) " +
+         "--androidaudiobaseheader $(location :libaudio_system_audio_base) " +
+         "--commontypesstructure $(location :common_types_structure_template) " +
+         "--outputfile $(out)",
+    srcs: [
+        ":common_types_structure_template",
+        ":libaudio_system_audio_base",
+    ],
+    out: ["PolicySubsystem-CommonTypes.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
new file mode 100755
index 0000000..9a7fa8f
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
@@ -0,0 +1,184 @@
+#! /usr/bin/python3
+#
+# pylint: disable=line-too-long, missing-docstring, logging-format-interpolation, invalid-name
+
+#
+# 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.
+
+import argparse
+import re
+import sys
+import os
+import logging
+import xml.etree.ElementTree as ET
+from collections import OrderedDict
+import xml.dom.minidom as MINIDOM
+
+def parseArgs():
+    argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+        structure file generator.\n\
+        Exit with the number of (recoverable or not) error that occured.")
+    argparser.add_argument('--androidaudiobaseheader',
+                           help="Android Audio Base C header file, Mandatory.",
+                           metavar="ANDROID_AUDIO_BASE_HEADER",
+                           type=argparse.FileType('r'),
+                           required=True)
+    argparser.add_argument('--commontypesstructure',
+                           help="Structure XML base file. Mandatory.",
+                           metavar="STRUCTURE_FILE_IN",
+                           type=argparse.FileType('r'),
+                           required=True)
+    argparser.add_argument('--outputfile',
+                           help="Structure XML file. Mandatory.",
+                           metavar="STRUCTURE_FILE_OUT",
+                           type=argparse.FileType('w'),
+                           required=True)
+    argparser.add_argument('--verbose',
+                           action='store_true')
+
+    return argparser.parse_args()
+
+
+def findBitPos(decimal):
+    pos = 0
+    i = 1
+    while i != decimal:
+        i = i << 1
+        pos = pos + 1
+        if pos == 32:
+            return -1
+    return pos
+
+
+def generateXmlStructureFile(componentTypeDict, structureTypesFile, outputFile):
+
+    logging.info("Importing structureTypesFile {}".format(structureTypesFile))
+    component_types_in_tree = ET.parse(structureTypesFile)
+
+    component_types_root = component_types_in_tree.getroot()
+
+    for component_types_name, values_dict in componentTypeDict.items():
+        for component_type in component_types_root.findall('ComponentType'):
+            if component_type.get('Name') == component_types_name:
+                bitparameters_node = component_type.find("BitParameterBlock")
+                if bitparameters_node is not None:
+                    ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
+                    for key, value in ordered_values.items():
+                        value_node = ET.SubElement(bitparameters_node, "BitParameter")
+                        value_node.set('Name', key)
+                        value_node.set('Size', "1")
+                        value_node.set('Pos', str(findBitPos(value)))
+
+                enum_parameter_node = component_type.find("EnumParameter")
+                if enum_parameter_node is not None:
+                    ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
+                    for key, value in ordered_values.items():
+                        value_node = ET.SubElement(enum_parameter_node, "ValuePair")
+                        value_node.set('Literal', key)
+                        value_node.set('Numerical', str(value))
+
+    xmlstr = ET.tostring(component_types_root, encoding='utf8', method='xml')
+    reparsed = MINIDOM.parseString(xmlstr)
+    prettyXmlStr = reparsed.toprettyxml(indent="    ", newl='\n')
+    prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
+    outputFile.write(prettyXmlStr)
+
+
+def capitalizeLine(line):
+    return ' '.join((w.capitalize() for w in line.split(' ')))
+
+def parseAndroidAudioFile(androidaudiobaseheaderFile):
+    #
+    # Adaptation table between Android Enumeration prefix and Audio PFW Criterion type names
+    #
+    component_type_mapping_table = {
+        'AUDIO_STREAM' : "VolumeProfileType",
+        'AUDIO_DEVICE_OUT' : "OutputDevicesMask",
+        'AUDIO_DEVICE_IN' : "InputDevicesMask"}
+
+    all_component_types = {
+        'VolumeProfileType' : {},
+        'OutputDevicesMask' : {},
+        'InputDevicesMask' : {}
+    }
+
+    #
+    # _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
+    #
+    ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
+
+    criteria_pattern = re.compile(
+        r"\s*(?P<type>(?:"+'|'.join(component_type_mapping_table.keys()) + "))_" \
+        r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
+        r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
+
+    logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
+
+    for line_number, line in enumerate(androidaudiobaseheaderFile):
+        match = criteria_pattern.match(line)
+        if match:
+            logging.debug("The following line is VALID: {}:{}\n{}".format(
+                androidaudiobaseheaderFile.name, line_number, line))
+
+            component_type_name = component_type_mapping_table[match.groupdict()['type']]
+            component_type_literal = match.groupdict()['literal'].lower()
+
+            component_type_numerical_value = match.groupdict()['values']
+
+            # for AUDIO_DEVICE_IN: need to remove sign bit / rename default to stub
+            if component_type_name == "InputDevicesMask":
+                component_type_numerical_value = str(int(component_type_numerical_value, 0) & ~2147483648)
+                if component_type_literal == "default":
+                    component_type_literal = "stub"
+
+            if component_type_name == "OutputDevicesMask":
+                if component_type_literal == "default":
+                    component_type_literal = "stub"
+
+            # Remove duplicated numerical values
+            if int(component_type_numerical_value, 0) in all_component_types[component_type_name].values():
+                logging.info("The value {}:{} is duplicated for criterion {}, KEEPING LATEST".format(component_type_numerical_value, component_type_literal, component_type_name))
+                for key in list(all_component_types[component_type_name]):
+                    if all_component_types[component_type_name][key] == int(component_type_numerical_value, 0):
+                        del all_component_types[component_type_name][key]
+
+            all_component_types[component_type_name][component_type_literal] = int(component_type_numerical_value, 0)
+
+            logging.debug("type:{}, literal:{}, values:{}.".format(component_type_name, component_type_literal, component_type_numerical_value))
+
+    # Transform input source in inclusive criterion
+    shift = len(all_component_types['OutputDevicesMask'])
+    if shift > 32:
+        logging.critical("OutputDevicesMask incompatible with criterion representation on 32 bits")
+        logging.info("EXIT ON FAILURE")
+        exit(1)
+
+    for component_types in all_component_types:
+        values = ','.join('{}:{}'.format(value, key) for key, value in all_component_types[component_types].items())
+        logging.info("{}: <{}>".format(component_types, values))
+
+    return all_component_types
+
+
+def main():
+    logging.root.setLevel(logging.INFO)
+    args = parseArgs()
+    route_criteria = 0
+
+    all_component_types = parseAndroidAudioFile(args.androidaudiobaseheader)
+
+    generateXmlStructureFile(all_component_types, args.commontypesstructure, args.outputfile)
+
+# If this file is directly executed
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.bp b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
index 6f59487..301ecc0 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.bp
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
@@ -11,7 +11,6 @@
         "libbase_headers",
         "libaudiopolicycommon",
     ],
-    static_libs: ["libaudiopolicycomponents"],
     shared_libs: [
         "liblog",
         "libutils",
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 465a6f9..63990ac 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -92,7 +92,8 @@
 template <>
 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
 
-ParameterManagerWrapper::ParameterManagerWrapper()
+ParameterManagerWrapper::ParameterManagerWrapper(bool enableSchemaVerification,
+                                                 const std::string &schemaUri)
     : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
 {
     // Connector
@@ -104,6 +105,15 @@
 
     // Logger
     mPfwConnector->setLogger(mPfwConnectorLogger);
+
+    // Schema validation
+    std::string error;
+    bool ret = mPfwConnector->setValidateSchemasOnStart(enableSchemaVerification, error);
+    ALOGE_IF(!ret, "Failed to activate schema validation: %s", error.c_str());
+    if (enableSchemaVerification && ret && !schemaUri.empty()) {
+        ALOGE("Schema verification activated with schema URI: %s", schemaUri.c_str());
+        mPfwConnector->setSchemaUri(schemaUri);
+    }
 }
 
 status_t ParameterManagerWrapper::addCriterion(const std::string &name, bool isInclusive,
@@ -145,11 +155,10 @@
     delete mPfwConnector;
 }
 
-status_t ParameterManagerWrapper::start()
+status_t ParameterManagerWrapper::start(std::string &error)
 {
     ALOGD("%s: in", __FUNCTION__);
     /// Start PFW
-    std::string error;
     if (!mPfwConnector->start(error)) {
         ALOGE("%s: Policy PFW start error: %s", __FUNCTION__, error.c_str());
         return NO_INIT;
@@ -253,13 +262,13 @@
     return interface->getLiteralValue(valueToCheck, literalValue);
 }
 
-status_t ParameterManagerWrapper::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
-                                                           audio_policy_dev_state_t state)
+status_t ParameterManagerWrapper::setDeviceConnectionState(
+        audio_devices_t type, const std::string address, audio_policy_dev_state_t state)
 {
-    std::string criterionName = audio_is_output_device(devDesc->type()) ?
+    std::string criterionName = audio_is_output_device(type) ?
                 gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
 
-    ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->address().c_str(),
+    ALOGV("%s: device with address %s %s", __FUNCTION__, address.c_str(),
           state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
     ISelectionCriterionInterface *criterion =
             getElement<ISelectionCriterionInterface>(criterionName, mPolicyCriteria);
@@ -271,8 +280,9 @@
 
     auto criterionType = criterion->getCriterionType();
     int deviceAddressId;
-    if (not criterionType->getNumericalValue(devDesc->address().c_str(), deviceAddressId)) {
-        ALOGW("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->address().c_str());
+    if (not criterionType->getNumericalValue(address.c_str(), deviceAddressId)) {
+        ALOGW("%s: unknown device address reported (%s) for criterion %s", __FUNCTION__,
+              address.c_str(), criterionName.c_str());
         return BAD_TYPE;
     }
     int currentValueMask = criterion->getCriterionState();
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 8443008..62b129a 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,9 +16,6 @@
 
 #pragma once
 
-#include <PolicyAudioPort.h>
-#include <HwModule.h>
-#include <DeviceDescriptor.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
 #include <utils/Errors.h>
@@ -47,16 +44,18 @@
     using Criteria = std::map<std::string, ISelectionCriterionInterface *>;
 
 public:
-    ParameterManagerWrapper();
+    ParameterManagerWrapper(bool enableSchemaVerification = false,
+                            const std::string &schemaUri = {});
     ~ParameterManagerWrapper();
 
     /**
      * Starts the platform state service.
      * It starts the parameter framework policy instance.
+     * @param[out] contains human readable error if starts failed
      *
-     * @return NO_ERROR if success, error code otherwise.
+     * @return NO_ERROR if success, error code otherwise, and error is set to human readable string.
      */
-    status_t start();
+    status_t start(std::string &error);
 
     /**
      * The following API wrap policy action to criteria
@@ -117,7 +116,15 @@
      */
     status_t setAvailableOutputDevices(audio_devices_t outputDevices);
 
-    status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+    /**
+     * @brief setDeviceConnectionState propagates a state event on a given device(s)
+     * @param type bit mask of the device whose state has changed
+     * @param address of the device whose state has changed
+     * @param state new state of the given device
+     * @return NO_ERROR if new state corretly propagated to Engine Parameter-Framework, error
+     * code otherwise.
+     */
+    status_t setDeviceConnectionState(audio_devices_t type, const std::string address,
                                       audio_policy_dev_state_t state);
 
     /**
diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
index 9398743..a7388da 100644
--- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_product_strategies.xml
@@ -72,6 +72,12 @@
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
             <Attributes></Attributes>
         </AttributesGroup>
+        <AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
+            <Attributes>
+                <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+                <Usage value="AUDIO_USAGE_ASSISTANT"/>
+            </Attributes>
+        </AttributesGroup>
         <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
             <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
         </AttributesGroup>
@@ -91,20 +97,5 @@
         </AttributesGroup>
     </ProductStrategy>
 
-    <!-- Routing Strategy rerouting may be removed as following media??? -->
-    <ProductStrategy name="STRATEGY_REROUTING">
-        <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
-
-    <!-- Default product strategy has empty attributes -->
-    <ProductStrategy name="STRATEGY_PATCH">
-        <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
-            <Attributes></Attributes>
-        </AttributesGroup>
-    </ProductStrategy>
-
-
 </ProductStrategies>
 
diff --git a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
index 707a184..d5c3896 100644
--- a/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
+++ b/services/audiopolicy/enginedefault/config/example/phone/audio_policy_engine_stream_volumes.xml
@@ -207,25 +207,15 @@
     </volumeGroup>
 
     <volumeGroup>
-        <name>rerouting</name>
+        <name>assistant</name>
         <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
+        <indexMax>15</indexMax>
+        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID"  ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
     </volumeGroup>
 
-    <volumeGroup>
-        <name>patch</name>
-        <indexMin>0</indexMin>
-        <indexMax>1</indexMax>
-        <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="FULL_SCALE_VOLUME_CURVE"/>
-        <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="FULL_SCALE_VOLUME_CURVE"/>
-    </volumeGroup>
 </volumeGroups>
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 23c0a12..632c356 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -526,12 +526,12 @@
 
     // release existing RX patch if any
     if (mCallRxPatch != 0) {
-        mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
+        releaseAudioPatchInternal(mCallRxPatch->getHandle());
         mCallRxPatch.clear();
     }
     // release TX patch if any
     if (mCallTxPatch != 0) {
-        mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
+        releaseAudioPatchInternal(mCallTxPatch->getHandle());
         mCallTxPatch.clear();
     }
 
@@ -557,11 +557,9 @@
             ALOGE("updateCallRouting() no telephony Tx and/or RX device");
             return muteWaitMs;
         }
-        // do not create a patch (aka Sw Bridging) if Primary HW module has declared supporting a
-        // route between telephony RX to Sink device and Source device to telephony TX
-        const auto &primaryModule = telephonyRxModule;
-        createRxPatch = !primaryModule->supportsPatch(rxSourceDevice, rxDevices.itemAt(0));
-        createTxPatch = !primaryModule->supportsPatch(txSourceDevice, txSinkDevice);
+        // createAudioPatchInternal now supports both HW / SW bridging
+        createRxPatch = true;
+        createTxPatch = true;
     } else {
         // If the RX device is on the primary HW module, then use legacy routing method for
         // voice calls via setOutputDevice() on primary output.
@@ -585,6 +583,15 @@
         // assuming the device uses audio HAL V5.0 and above
     }
     if (createTxPatch) { // create TX path audio patch
+        // terminate active capture if on the same HW module as the call TX source device
+        // FIXME: would be better to refine to only inputs whose profile connects to the
+        // call TX device but this information is not in the audio patch and logic here must be
+        // symmetric to the one in startInput()
+        for (const auto& activeDesc : mInputs.getActiveInputs()) {
+            if (activeDesc->hasSameHwModuleAs(txSourceDevice)) {
+                closeActiveClients(activeDesc);
+            }
+        }
         mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
     }
 
@@ -598,6 +605,8 @@
     if (device == nullptr) {
         return nullptr;
     }
+
+    // @TODO: still ignoring the address, or not dealing platform with mutliple telephony devices
     if (isRx) {
         patchBuilder.addSink(device).
                 addSource(mAvailableInputDevices.getDevice(
@@ -608,45 +617,15 @@
                     AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT));
     }
 
-    // @TODO: still ignoring the address, or not dealing platform with mutliple telephonydevices
-    const sp<DeviceDescriptor> outputDevice = isRx ?
-                device : mAvailableOutputDevices.getDevice(
-                    AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT);
-    SortedVector<audio_io_handle_t> outputs =
-            getOutputsForDevices(DeviceVector(outputDevice), mOutputs);
-    const audio_io_handle_t output = selectOutput(outputs);
-    // request to reuse existing output stream if one is already opened to reach the target device
-    if (output != AUDIO_IO_HANDLE_NONE) {
-        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
-        ALOG_ASSERT(!outputDesc->isDuplicated(), "%s() %s device output %d is duplicated", __func__,
-                    outputDevice->toString().c_str(), output);
-        patchBuilder.addSource(outputDesc, { .stream = AUDIO_STREAM_PATCH });
+    audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
+    status_t status =
+            createAudioPatchInternal(patchBuilder.patch(), &patchHandle, mUidCached, delayMs);
+    ssize_t index = mAudioPatches.indexOfKey(patchHandle);
+    if (status != NO_ERROR || index < 0) {
+        ALOGW("%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
+        return nullptr;
     }
-
-    if (!isRx) {
-        // terminate active capture if on the same HW module as the call TX source device
-        // FIXME: would be better to refine to only inputs whose profile connects to the
-        // call TX device but this information is not in the audio patch and logic here must be
-        // symmetric to the one in startInput()
-        for (const auto& activeDesc : mInputs.getActiveInputs()) {
-            if (activeDesc->hasSameHwModuleAs(device)) {
-                closeActiveClients(activeDesc);
-            }
-        }
-    }
-
-    audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    status_t status = mpClientInterface->createAudioPatch(
-            patchBuilder.patch(), &afPatchHandle, delayMs);
-    ALOGW_IF(status != NO_ERROR,
-            "%s() error %d creating %s audio patch", __func__, status, isRx ? "RX" : "TX");
-    sp<AudioPatch> audioPatch;
-    if (status == NO_ERROR) {
-        audioPatch = new AudioPatch(patchBuilder.patch(), mUidCached);
-        audioPatch->mAfPatchHandle = afPatchHandle;
-        audioPatch->mUid = mUidCached;
-    }
-    return audioPatch;
+    return mAudioPatches.valueAt(index);
 }
 
 bool AudioPolicyManager::isDeviceOfModule(
@@ -729,11 +708,11 @@
             updateCallRouting(rxDevices, delayMs);
         } else if (oldState == AUDIO_MODE_IN_CALL) {
             if (mCallRxPatch != 0) {
-                mpClientInterface->releaseAudioPatch(mCallRxPatch->mAfPatchHandle, 0);
+                releaseAudioPatchInternal(mCallRxPatch->getHandle());
                 mCallRxPatch.clear();
             }
             if (mCallTxPatch != 0) {
-                mpClientInterface->releaseAudioPatch(mCallTxPatch->mAfPatchHandle, 0);
+                releaseAudioPatchInternal(mCallTxPatch->getHandle());
                 mCallTxPatch.clear();
             }
             setOutputDevices(mPrimaryOutput, rxDevices, force, 0);
@@ -1209,7 +1188,7 @@
                         devices.containsDeviceWithType(sink->ext.device.type) &&
                         (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
                                 AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
-                    releaseAudioPatch(patch->mHandle, mUidCached);
+                    releaseAudioPatch(patch->getHandle(), mUidCached);
                     break;
                 }
             }
@@ -1296,7 +1275,7 @@
                 const struct audio_port_config *source = &patch->mPatch.sources[j];
                 if (source->type == AUDIO_PORT_TYPE_DEVICE &&
                         source->ext.device.hw_module == msdModule->getHandle()) {
-                    msdPatches.addAudioPatch(patch->mHandle, patch);
+                    msdPatches.addAudioPatch(patch->getHandle(), patch);
                 }
             }
         }
@@ -1355,6 +1334,14 @@
     // For encoded streams force direct flag to prevent downstream mixing.
     sinkConfig->flags.output = static_cast<audio_output_flags_t>(
             sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_DIRECT);
+    if (audio_is_iec61937_compatible(sinkConfig->format)) {
+        // For formats compatible with IEC61937 encapsulation, assume that
+        // the record thread input from MSD is IEC61937 framed (for proportional buffer sizing).
+        // Add the AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO flag so downstream HAL can distinguish between
+        // raw and IEC61937 framed streams.
+        sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+                sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
+    }
     sourceConfig->sample_rate = bestSinkConfig.sample_rate;
     // Specify exact channel mask to prevent guessing by bit count in PatchPanel.
     sourceConfig->channel_mask = audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
@@ -1418,7 +1405,7 @@
         if (audio_patches_are_equal(&currentPatch->mPatch, patch)) {
             return NO_ERROR;
         }
-        releaseAudioPatch(currentPatch->mHandle, mUidCached);
+        releaseAudioPatch(currentPatch->getHandle(), mUidCached);
     }
     status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
             patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
@@ -2748,12 +2735,14 @@
                                 int session,
                                 int id)
 {
-    ssize_t index = mOutputs.indexOfKey(io);
-    if (index < 0) {
-        index = mInputs.indexOfKey(io);
+    if (session != AUDIO_SESSION_DEVICE) {
+        ssize_t index = mOutputs.indexOfKey(io);
         if (index < 0) {
-            ALOGW("registerEffect() unknown io %d", io);
-            return INVALID_OPERATION;
+            index = mInputs.indexOfKey(io);
+            if (index < 0) {
+                ALOGW("registerEffect() unknown io %d", io);
+                return INVALID_OPERATION;
+            }
         }
     }
     return mEffects.registerEffect(desc, io, session, id,
@@ -3381,16 +3370,16 @@
     return BAD_VALUE;
 }
 
-status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
-                                               audio_patch_handle_t *handle,
-                                               uid_t uid)
+status_t AudioPolicyManager::createAudioPatchInternal(const struct audio_patch *patch,
+                                                      audio_patch_handle_t *handle,
+                                                      uid_t uid, uint32_t delayMs,
+                                                      const sp<SourceClientDescriptor>& sourceDesc)
 {
-    ALOGV("createAudioPatch()");
-
+    ALOGV("%s", __func__);
     if (handle == NULL || patch == NULL) {
         return BAD_VALUE;
     }
-    ALOGV("createAudioPatch() num sources %d num sinks %d", patch->num_sources, patch->num_sinks);
+    ALOGV("%s num sources %d num sinks %d", __func__, patch->num_sources, patch->num_sinks);
 
     if (!audio_patch_is_valid(patch)) {
         return BAD_VALUE;
@@ -3412,22 +3401,22 @@
     sp<AudioPatch> patchDesc;
     ssize_t index = mAudioPatches.indexOfKey(*handle);
 
-    ALOGV("createAudioPatch source id %d role %d type %d", patch->sources[0].id,
-                                                           patch->sources[0].role,
-                                                           patch->sources[0].type);
+    ALOGV("%s source id %d role %d type %d", __func__, patch->sources[0].id,
+                                                       patch->sources[0].role,
+                                                       patch->sources[0].type);
 #if LOG_NDEBUG == 0
     for (size_t i = 0; i < patch->num_sinks; i++) {
-        ALOGV("createAudioPatch sink %zu: id %d role %d type %d", i, patch->sinks[i].id,
-                                                             patch->sinks[i].role,
-                                                             patch->sinks[i].type);
+        ALOGV("%s sink %zu: id %d role %d type %d", __func__ ,i, patch->sinks[i].id,
+                                                                 patch->sinks[i].role,
+                                                                 patch->sinks[i].type);
     }
 #endif
 
     if (index >= 0) {
         patchDesc = mAudioPatches.valueAt(index);
-        ALOGV("createAudioPatch() mUidCached %d patchDesc->mUid %d uid %d",
-                                                                  mUidCached, patchDesc->mUid, uid);
-        if (patchDesc->mUid != mUidCached && uid != patchDesc->mUid) {
+        ALOGV("%s mUidCached %d patchDesc->mUid %d uid %d",
+              __func__, mUidCached, patchDesc->getUid(), uid);
+        if (patchDesc->getUid() != mUidCached && uid != patchDesc->getUid()) {
             return INVALID_OPERATION;
         }
     } else {
@@ -3437,15 +3426,15 @@
     if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
         if (outputDesc == NULL) {
-            ALOGV("createAudioPatch() output not found for id %d", patch->sources[0].id);
+            ALOGV("%s output not found for id %d", __func__, patch->sources[0].id);
             return BAD_VALUE;
         }
         ALOG_ASSERT(!outputDesc->isDuplicated(),"duplicated output %d in source in ports",
                                                 outputDesc->mIoHandle);
         if (patchDesc != 0) {
             if (patchDesc->mPatch.sources[0].id != patch->sources[0].id) {
-                ALOGV("createAudioPatch() source id differs for patch current id %d new id %d",
-                                          patchDesc->mPatch.sources[0].id, patch->sources[0].id);
+                ALOGV("%s source id differs for patch current id %d new id %d",
+                      __func__, patchDesc->mPatch.sources[0].id, patch->sources[0].id);
                 return BAD_VALUE;
             }
         }
@@ -3454,13 +3443,13 @@
             // Only support mix to devices connection
             // TODO add support for mix to mix connection
             if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
-                ALOGV("createAudioPatch() source mix but sink is not a device");
+                ALOGV("%s source mix but sink is not a device", __func__);
                 return INVALID_OPERATION;
             }
             sp<DeviceDescriptor> devDesc =
                     mAvailableOutputDevices.getDeviceFromId(patch->sinks[i].id);
             if (devDesc == 0) {
-                ALOGV("createAudioPatch() out device not found for id %d", patch->sinks[i].id);
+                ALOGV("%s out device not found for id %d", __func__, patch->sinks[i].id);
                 return BAD_VALUE;
             }
 
@@ -3472,8 +3461,7 @@
                                                            patch->sources[0].channel_mask,
                                                            NULL,  // updatedChannelMask
                                                            AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
-                ALOGV("createAudioPatch() profile not supported for device %08x",
-                        devDesc->type());
+                ALOGV("%s profile not supported for device %08x", __func__, devDesc->type());
                 return INVALID_OPERATION;
             }
             devices.add(devDesc);
@@ -3483,19 +3471,19 @@
         }
 
         // TODO: reconfigure output format and channels here
-        ALOGV("createAudioPatch() setting device %s on output %d",
-              dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
+        ALOGV("%s setting device %s on output %d",
+              __func__, dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
         setOutputDevices(outputDesc, devices, true, 0, handle);
         index = mAudioPatches.indexOfKey(*handle);
         if (index >= 0) {
             if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
-                ALOGW("createAudioPatch() setOutputDevice() did not reuse the patch provided");
+                ALOGW("%s setOutputDevice() did not reuse the patch provided", __func__);
             }
             patchDesc = mAudioPatches.valueAt(index);
-            patchDesc->mUid = uid;
-            ALOGV("createAudioPatch() success");
+            patchDesc->setUid(uid);
+            ALOGV("%s success", __func__);
         } else {
-            ALOGW("createAudioPatch() setOutputDevice() failed to create a patch");
+            ALOGW("%s setOutputDevice() failed to create a patch", __func__);
             return INVALID_OPERATION;
         }
     } else if (patch->sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
@@ -3534,19 +3522,19 @@
                 return INVALID_OPERATION;
             }
             // TODO: reconfigure output format and channels here
-            ALOGV("%s() setting device %s on output %d", __func__,
+            ALOGV("%s setting device %s on output %d", __func__,
                   device->toString().c_str(), inputDesc->mIoHandle);
             setInputDevice(inputDesc->mIoHandle, device, true, handle);
             index = mAudioPatches.indexOfKey(*handle);
             if (index >= 0) {
                 if (patchDesc != 0 && patchDesc != mAudioPatches.valueAt(index)) {
-                    ALOGW("createAudioPatch() setInputDevice() did not reuse the patch provided");
+                    ALOGW("%s setInputDevice() did not reuse the patch provided", __func__);
                 }
                 patchDesc = mAudioPatches.valueAt(index);
-                patchDesc->mUid = uid;
-                ALOGV("createAudioPatch() success");
+                patchDesc->setUid(uid);
+                ALOGV("%s success", __func__);
             } else {
-                ALOGW("createAudioPatch() setInputDevice() failed to create a patch");
+                ALOGW("%s setInputDevice() failed to create a patch", __func__);
                 return INVALID_OPERATION;
             }
         } else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
@@ -3564,55 +3552,96 @@
 
             //update source and sink with our own data as the data passed in the patch may
             // be incomplete.
-            struct audio_patch newPatch = *patch;
-            srcDevice->toAudioPortConfig(&newPatch.sources[0], &patch->sources[0]);
+            PatchBuilder patchBuilder;
+            audio_port_config sourcePortConfig = {};
+            srcDevice->toAudioPortConfig(&sourcePortConfig, &patch->sources[0]);
+            patchBuilder.addSource(sourcePortConfig);
 
             for (size_t i = 0; i < patch->num_sinks; i++) {
                 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
-                    ALOGV("createAudioPatch() source device but one sink is not a device");
+                    ALOGV("%s source device but one sink is not a device", __func__);
                     return INVALID_OPERATION;
                 }
-
                 sp<DeviceDescriptor> sinkDevice =
                         mAvailableOutputDevices.getDeviceFromId(patch->sinks[i].id);
                 if (sinkDevice == 0) {
                     return BAD_VALUE;
                 }
-                sinkDevice->toAudioPortConfig(&newPatch.sinks[i], &patch->sinks[i]);
+                audio_port_config sinkPortConfig = {};
+                sinkDevice->toAudioPortConfig(&sinkPortConfig, &patch->sinks[i]);
+                patchBuilder.addSink(sinkPortConfig);
 
                 // create a software bridge in PatchPanel if:
                 // - source and sink devices are on different HW modules OR
                 // - audio HAL version is < 3.0
                 // - audio HAL version is >= 3.0 but no route has been declared between devices
+                // - called from startAudioSource (aka sourceDesc != nullptr) and source device does
+                //   not have a gain controller
                 if (!srcDevice->hasSameHwModuleAs(sinkDevice) ||
                         (srcDevice->getModuleVersionMajor() < 3) ||
-                        !srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice)) {
+                        !srcDevice->getModule()->supportsPatch(srcDevice, sinkDevice) ||
+                        (sourceDesc != nullptr &&
+                         srcDevice->getAudioPort()->getGains().size() == 0)) {
                     // support only one sink device for now to simplify output selection logic
                     if (patch->num_sinks > 1) {
                         return INVALID_OPERATION;
                     }
-                    SortedVector<audio_io_handle_t> outputs =
-                            getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
-                    // if the sink device is reachable via an opened output stream, request to go via
-                    // this output stream by adding a second source to the patch description
-                    const audio_io_handle_t output = selectOutput(outputs);
-                    if (output != AUDIO_IO_HANDLE_NONE) {
-                        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
-                        if (outputDesc->isDuplicated()) {
+                    audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+                    if (sourceDesc != nullptr) {
+                        // take care of dynamic routing for SwOutput selection,
+                        audio_attributes_t attributes = sourceDesc->attributes();
+                        audio_stream_type_t stream = sourceDesc->stream();
+                        audio_attributes_t resultAttr;
+                        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+                        config.sample_rate = sourceDesc->config().sample_rate;
+                        config.channel_mask = sourceDesc->config().channel_mask;
+                        config.format = sourceDesc->config().format;
+                        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+                        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+                        bool isRequestedDeviceForExclusiveUse = false;
+                        std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
+                        getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
+                                            &stream, sourceDesc->uid(), &config, &flags,
+                                            &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
+                                            &secondaryOutputs);
+                        if (output == AUDIO_IO_HANDLE_NONE) {
+                            ALOGV("%s no output for device %s",
+                                  __FUNCTION__, sinkDevice->toString().c_str());
                             return INVALID_OPERATION;
                         }
-                        outputDesc->toAudioPortConfig(&newPatch.sources[1], &patch->sources[0]);
-                        newPatch.sources[1].ext.mix.usecase.stream = AUDIO_STREAM_PATCH;
-                        newPatch.num_sources = 2;
+                    } else {
+                        SortedVector<audio_io_handle_t> outputs =
+                                getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
+                        // if the sink device is reachable via an opened output stream, request to
+                        // go via this output stream by adding a second source to the patch
+                        // description
+                        output = selectOutput(outputs);
+                    }
+                    if (output != AUDIO_IO_HANDLE_NONE) {
+                        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
+                        if (outputDesc->isDuplicated()) {
+                            ALOGV("%s output for device %s is duplicated",
+                                  __FUNCTION__, sinkDevice->toString().c_str());
+                            return INVALID_OPERATION;
+                        }
+                        audio_port_config srcMixPortConfig = {};
+                        outputDesc->toAudioPortConfig(&srcMixPortConfig, &patch->sources[0]);
+                        if (sourceDesc != nullptr) {
+                            sourceDesc->setSwOutput(outputDesc);
+                        }
+                        // for volume control, we may need a valid stream
+                        srcMixPortConfig.ext.mix.usecase.stream = sourceDesc != nullptr ?
+                                    sourceDesc->stream() : AUDIO_STREAM_PATCH;
+                        patchBuilder.addSource(srcMixPortConfig);
                     }
                 }
             }
             // TODO: check from routing capabilities in config file and other conflicting patches
 
-            status_t status = installPatch(__func__, index, handle, &newPatch, 0, uid, &patchDesc);
+            status_t status = installPatch(
+                        __func__, index, handle, patchBuilder.patch(), delayMs, uid, &patchDesc);
             if (status != NO_ERROR) {
-                ALOGW("createAudioPatch() patch panel could not connect device patch, error %d",
-                status);
+                ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
                 return INVALID_OPERATION;
             }
         } else {
@@ -3635,18 +3664,29 @@
         return BAD_VALUE;
     }
     sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-    ALOGV("releaseAudioPatch() mUidCached %d patchDesc->mUid %d uid %d",
-          mUidCached, patchDesc->mUid, uid);
-    if (patchDesc->mUid != mUidCached && uid != patchDesc->mUid) {
+    ALOGV("%s() mUidCached %d patchDesc->mUid %d uid %d",
+          __func__, mUidCached, patchDesc->getUid(), uid);
+    if (patchDesc->getUid() != mUidCached && uid != patchDesc->getUid()) {
         return INVALID_OPERATION;
     }
+    return releaseAudioPatchInternal(handle);
+}
 
+status_t AudioPolicyManager::releaseAudioPatchInternal(audio_patch_handle_t handle,
+                                                       uint32_t delayMs)
+{
+    ALOGV("%s patch %d", __func__, handle);
+    if (mAudioPatches.indexOfKey(handle) < 0) {
+        ALOGE("%s: no patch found with handle=%d", __func__, handle);
+        return BAD_VALUE;
+    }
+    sp<AudioPatch> patchDesc = mAudioPatches.valueFor(handle);
     struct audio_patch *patch = &patchDesc->mPatch;
-    patchDesc->mUid = mUidCached;
+    patchDesc->setUid(mUidCached);
     if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputFromId(patch->sources[0].id);
         if (outputDesc == NULL) {
-            ALOGV("releaseAudioPatch() output not found for id %d", patch->sources[0].id);
+            ALOGV("%s output not found for id %d", __func__, patch->sources[0].id);
             return BAD_VALUE;
         }
 
@@ -3659,7 +3699,7 @@
         if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
             sp<AudioInputDescriptor> inputDesc = mInputs.getInputFromId(patch->sinks[0].id);
             if (inputDesc == NULL) {
-                ALOGV("releaseAudioPatch() input not found for id %d", patch->sinks[0].id);
+                ALOGV("%s input not found for id %d", __func__, patch->sinks[0].id);
                 return BAD_VALUE;
             }
             setInputDevice(inputDesc->mIoHandle,
@@ -3667,10 +3707,11 @@
                            true,
                            NULL);
         } else if (patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) {
-            status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
-            ALOGV("releaseAudioPatch() patch panel returned %d patchHandle %d",
-                                                              status, patchDesc->mAfPatchHandle);
-            removeAudioPatch(patchDesc->mHandle);
+            status_t status =
+                    mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), delayMs);
+            ALOGV("%s patch panel returned %d patchHandle %d",
+                  __func__, status, patchDesc->getAfHandle());
+            removeAudioPatch(patchDesc->getHandle());
             nextAudioPortGeneration();
             mpClientInterface->onAudioPatchListUpdate();
         } else {
@@ -3768,7 +3809,7 @@
 {
     for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--)  {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
-        if (patchDesc->mUid == uid) {
+        if (patchDesc->getUid() == uid) {
             releaseAudioPatch(mAudioPatches.keyAt(i), uid);
         }
     }
@@ -3904,11 +3945,8 @@
 
     *portId = PolicyAudioPort::getNextUniqueId();
 
-    struct audio_patch dummyPatch = {};
-    sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
-
     sp<SourceClientDescriptor> sourceDesc =
-        new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDevice,
+        new SourceClientDescriptor(*portId, uid, *attributes, *source, srcDevice,
                                    mEngine->getStreamTypeForAttributes(*attributes),
                                    mEngine->getProductStrategyForAttributes(*attributes),
                                    toVolumeSource(*attributes));
@@ -3928,7 +3966,6 @@
     disconnectAudioSource(sourceDesc);
 
     audio_attributes_t attributes = sourceDesc->attributes();
-    audio_stream_type_t stream = sourceDesc->stream();
     sp<DeviceDescriptor> srcDevice = sourceDesc->srcDevice();
 
     DeviceVector sinkDevices =
@@ -3937,92 +3974,55 @@
     sp<DeviceDescriptor> sinkDevice = sinkDevices.itemAt(0);
     ALOG_ASSERT(mAvailableOutputDevices.contains(sinkDevice), "%s: Device %s not available",
                 __FUNCTION__, sinkDevice->toString().c_str());
-
-    audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-
-    if (srcDevice->hasSameHwModuleAs(sinkDevice) &&
-            srcDevice->getModuleVersionMajor() >= 3 &&
-            sinkDevice->getModule()->supportsPatch(srcDevice, sinkDevice) &&
-            srcDevice->getAudioPort()->getGains().size() > 0) {
-        ALOGV("%s Device to Device route supported by >=3.0 HAL", __FUNCTION__);
-        // TODO: may explicitly specify whether we should use HW or SW patch
-        //   create patch between src device and output device
-        //   create Hwoutput and add to mHwOutputs
-    } else {
-        audio_attributes_t resultAttr;
-        audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
-        config.sample_rate = sourceDesc->config().sample_rate;
-        config.channel_mask = sourceDesc->config().channel_mask;
-        config.format = sourceDesc->config().format;
-        audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
-        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
-        bool isRequestedDeviceForExclusiveUse = false;
-        std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
-        getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE,
-                &attributes, &stream, sourceDesc->uid(), &config, &flags,
-                &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
-                &secondaryOutputs);
-        if (output == AUDIO_IO_HANDLE_NONE) {
-            ALOGV("%s no output for device %s",
-                  __FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
-            return INVALID_OPERATION;
-        }
-        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
-        if (outputDesc->isDuplicated()) {
-            ALOGV("%s output for device %s is duplicated",
-                  __FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
-            return INVALID_OPERATION;
-        }
-        status_t status = outputDesc->start();
+    PatchBuilder patchBuilder;
+    patchBuilder.addSink(sinkDevice).addSource(srcDevice);
+    audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
+    status_t status =
+            createAudioPatchInternal(patchBuilder.patch(), &handle, mUidCached, 0, sourceDesc);
+    if (status != NO_ERROR || mAudioPatches.indexOfKey(handle) < 0) {
+        ALOGW("%s patch panel could not connect device patch, error %d", __func__, status);
+        return INVALID_OPERATION;
+    }
+    sourceDesc->setPatchHandle(handle);
+    // SW Bridge? (@todo: HW bridge, keep track of HwOutput for device selection "reconsideration")
+    sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
+    if (swOutput != 0) {
+        status = swOutput->start();
         if (status != NO_ERROR) {
-            return status;
+            goto FailureSourceAdded;
         }
-
-        // create a special patch with no sink and two sources:
-        // - the second source indicates to PatchPanel through which output mix this patch should
-        // be connected as well as the stream type for volume control
-        // - the sink is defined by whatever output device is currently selected for the output
-        // though which this patch is routed.
-        PatchBuilder patchBuilder;
-        patchBuilder.addSource(srcDevice).addSource(outputDesc, { .stream = stream });
-        status = mpClientInterface->createAudioPatch(patchBuilder.patch(),
-                                                              &afPatchHandle,
-                                                              0);
-        ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
-                                                              status, afPatchHandle);
-        sourceDesc->patchDesc()->mPatch = *patchBuilder.patch();
-        if (status != NO_ERROR) {
-            ALOGW("%s patch panel could not connect device patch, error %d",
-                  __FUNCTION__, status);
-            return INVALID_OPERATION;
-        }
-
-        if (outputDesc->getClient(sourceDesc->portId()) != nullptr) {
+        if (swOutput->getClient(sourceDesc->portId()) != nullptr) {
             ALOGW("%s source portId has already been attached to outputDesc", __func__);
-            return INVALID_OPERATION;
+            goto FailureReleasePatch;
         }
-        outputDesc->addClient(sourceDesc);
-
+        swOutput->addClient(sourceDesc);
         uint32_t delayMs = 0;
-        status = startSource(outputDesc, sourceDesc, &delayMs);
-
+        status = startSource(swOutput, sourceDesc, &delayMs);
         if (status != NO_ERROR) {
-            mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
-            outputDesc->removeClient(sourceDesc->portId());
-            outputDesc->stop();
-            return status;
+            ALOGW("%s failed to start source, error %d", __FUNCTION__, status);
+            goto FailureSourceActive;
         }
-        sourceDesc->setSwOutput(outputDesc);
         if (delayMs != 0) {
             usleep(delayMs * 1000);
         }
+    } else {
+        sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
+        if (hwOutputDesc != 0) {
+          //   create Hwoutput and add to mHwOutputs
+        } else {
+            ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
+        }
     }
-
-    sourceDesc->patchDesc()->mAfPatchHandle = afPatchHandle;
-    addAudioPatch(sourceDesc->patchDesc()->mHandle, sourceDesc->patchDesc());
-
     return NO_ERROR;
+
+FailureSourceActive:
+    swOutput->stop();
+    releaseOutput(sourceDesc->portId());
+FailureSourceAdded:
+    sourceDesc->setSwOutput(nullptr);
+FailureReleasePatch:
+    releaseAudioPatchInternal(handle);
+    return INVALID_OPERATION;
 }
 
 status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
@@ -4260,33 +4260,22 @@
 status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
 {
     ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
-
-    sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->patchDesc()->mHandle);
-    if (patchDesc == 0) {
-        ALOGW("%s source has no patch with handle %d", __FUNCTION__,
-              sourceDesc->patchDesc()->mHandle);
-        return BAD_VALUE;
-    }
-    removeAudioPatch(sourceDesc->patchDesc()->mHandle);
-
-    sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->swOutput().promote();
-    if (swOutputDesc != 0) {
-        status_t status = stopSource(swOutputDesc, sourceDesc);
+    sp<SwAudioOutputDescriptor> swOutput = sourceDesc->swOutput().promote();
+    if (swOutput != 0) {
+        status_t status = stopSource(swOutput, sourceDesc);
         if (status == NO_ERROR) {
-            swOutputDesc->stop();
+            swOutput->stop();
         }
-        swOutputDesc->removeClient(sourceDesc->portId());
-        mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+        releaseOutput(sourceDesc->portId());
     } else {
         sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
         if (hwOutputDesc != 0) {
-          //   release patch between src device and output device
           //   close Hwoutput and remove from mHwOutputs
         } else {
             ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
         }
     }
-    return NO_ERROR;
+    return releaseAudioPatchInternal(sourceDesc->getPatchHandle());
 }
 
 sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput(
@@ -4994,7 +4983,8 @@
     ssize_t index = mAudioPatches.indexOfKey(closingOutput->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-        (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+        (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(
+                    patchDesc->getAfHandle(), 0);
         mAudioPatches.removeItemsAt(index);
         mpClientInterface->onAudioPatchListUpdate();
     }
@@ -5042,7 +5032,8 @@
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-        (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+        (void) /*status_t status*/ mpClientInterface->releaseAudioPatch(
+                    patchDesc->getAfHandle(), 0);
         mAudioPatches.removeItemsAt(index);
         mpClientInterface->onAudioPatchListUpdate();
     }
@@ -5255,7 +5246,7 @@
     ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-        if (patchDesc->mUid != mUidCached) {
+        if (patchDesc->getUid() != mUidCached) {
             ALOGV("%s device %s forced by patch %d", __func__,
                   outputDesc->devices().toString().c_str(), outputDesc->getPatchHandle());
             return  outputDesc->devices();
@@ -5283,7 +5274,8 @@
         auto attr = mEngine->getAllAttributesForProductStrategy(productStrategy).front();
 
         if ((hasVoiceStream(streams) &&
-             (isInCall() || mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc))) ||
+             (isInCall() || mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) &&
+             !isStreamActive(AUDIO_STREAM_ENFORCED_AUDIBLE, 0)) ||
              ((hasStream(streams, AUDIO_STREAM_ALARM) || hasStream(streams, AUDIO_STREAM_ENFORCED_AUDIBLE)) &&
                 mOutputs.isStrategyActiveOnSameModule(productStrategy, outputDesc)) ||
                 outputDesc->isStrategyActive(productStrategy)) {
@@ -5305,7 +5297,7 @@
     ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
     if (index >= 0) {
         sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-        if (patchDesc->mUid != mUidCached) {
+        if (patchDesc->getUid() != mUidCached) {
             ALOGV("getNewInputDevice() device %s forced by patch %d",
                   inputDesc->getDevice()->toString().c_str(), inputDesc->getPatchHandle());
             return inputDesc->getDevice();
@@ -5632,10 +5624,10 @@
         return INVALID_OPERATION;
     }
     sp< AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-    status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, delayMs);
+    status_t status = mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), delayMs);
     ALOGV("resetOutputDevice() releaseAudioPatch returned %d", status);
     outputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
-    removeAudioPatch(patchDesc->mHandle);
+    removeAudioPatch(patchDesc->getHandle());
     nextAudioPortGeneration();
     mpClientInterface->onAudioPatchListUpdate();
     return status;
@@ -5685,10 +5677,10 @@
         return INVALID_OPERATION;
     }
     sp< AudioPatch> patchDesc = mAudioPatches.valueAt(index);
-    status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+    status_t status = mpClientInterface->releaseAudioPatch(patchDesc->getAfHandle(), 0);
     ALOGV("resetInputDevice() releaseAudioPatch returned %d", status);
     inputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
-    removeAudioPatch(patchDesc->mHandle);
+    removeAudioPatch(patchDesc->getHandle());
     nextAudioPortGeneration();
     mpClientInterface->onAudioPatchListUpdate();
     return status;
@@ -6101,8 +6093,8 @@
             }
         }
         if (release) {
-            ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->mHandle);
-            releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
+            ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->getHandle());
+            releaseAudioPatch(patchDesc->getHandle(), patchDesc->getUid());
         }
     }
 
@@ -6277,7 +6269,7 @@
     status_t status = installPatch(
             caller, index, patchHandle, patch, delayMs, mUidCached, &patchDesc);
     if (status == NO_ERROR) {
-        ioDescriptor->setPatchHandle(patchDesc->mHandle);
+        ioDescriptor->setPatchHandle(patchDesc->getHandle());
     }
     return status;
 }
@@ -6294,7 +6286,7 @@
     audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
     if (index >= 0) {
         patchDesc = mAudioPatches.valueAt(index);
-        afPatchHandle = patchDesc->mAfPatchHandle;
+        afPatchHandle = patchDesc->getAfHandle();
     }
 
     status_t status = mpClientInterface->createAudioPatch(patch, &afPatchHandle, delayMs);
@@ -6303,13 +6295,13 @@
     if (status == NO_ERROR) {
         if (index < 0) {
             patchDesc = new AudioPatch(patch, uid);
-            addAudioPatch(patchDesc->mHandle, patchDesc);
+            addAudioPatch(patchDesc->getHandle(), patchDesc);
         } else {
             patchDesc->mPatch = *patch;
         }
-        patchDesc->mAfPatchHandle = afPatchHandle;
+        patchDesc->setAfHandle(afPatchHandle);
         if (patchHandle) {
-            *patchHandle = patchDesc->mHandle;
+            *patchHandle = patchDesc->getHandle();
         }
         nextAudioPortGeneration();
         mpClientInterface->onAudioPatchListUpdate();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index d516d7b..634eb31 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -233,7 +233,10 @@
         virtual status_t getAudioPort(struct audio_port *port);
         virtual status_t createAudioPatch(const struct audio_patch *patch,
                                            audio_patch_handle_t *handle,
-                                           uid_t uid);
+                                           uid_t uid) {
+            return createAudioPatchInternal(patch, handle, uid);
+        }
+
         virtual status_t releaseAudioPatch(audio_patch_handle_t handle,
                                               uid_t uid);
         virtual status_t listAudioPatches(unsigned int *num_patches,
@@ -868,6 +871,29 @@
             param.addInt(String8(AudioParameter::keyMonoOutput), (int)mMasterMono);
             mpClientInterface->setParameters(output, param.toString());
         }
+
+        /**
+         * @brief createAudioPatchInternal internal function to manage audio patch creation
+         * @param[in] patch structure containing sink and source ports configuration
+         * @param[out] handle patch handle to be provided if patch installed correctly
+         * @param[in] uid of the client
+         * @param[in] delayMs if required
+         * @param[in] sourceDesc [optional] in case of external source, source client to be
+         * configured by the patch, i.e. assigning an Output (HW or SW)
+         * @return NO_ERROR if patch installed correclty, error code otherwise.
+         */
+        status_t createAudioPatchInternal(const struct audio_patch *patch,
+                                          audio_patch_handle_t *handle,
+                                          uid_t uid, uint32_t delayMs = 0,
+                                          const sp<SourceClientDescriptor>& sourceDesc = nullptr);
+        /**
+         * @brief releaseAudioPatchInternal internal function to remove an audio patch
+         * @param[in] handle of the patch to be removed
+         * @param[in] delayMs if required
+         * @return NO_ERROR if patch removed correclty, error code otherwise.
+         */
+        status_t releaseAudioPatchInternal(audio_patch_handle_t handle, uint32_t delayMs = 0);
+
         status_t installPatch(const char *caller,
                 audio_patch_handle_t *patchHandle,
                 AudioIODescriptorInterface *ioDescriptor,
diff --git a/services/audiopolicy/service/Android.mk b/services/audiopolicy/service/Android.mk
index 1144970..fdf3eae 100644
--- a/services/audiopolicy/service/Android.mk
+++ b/services/audiopolicy/service/Android.mk
@@ -24,6 +24,7 @@
     libbinder \
     libaudioclient \
     libaudioutils \
+    libaudiofoundation \
     libhardware_legacy \
     libaudiopolicymanager \
     libmedia_helper \
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 4947714..738a279 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -42,7 +42,10 @@
 AudioPolicyEffects::AudioPolicyEffects()
 {
     status_t loadResult = loadAudioEffectXmlConfig();
-    if (loadResult < 0) {
+    if (loadResult == NO_ERROR) {
+        mDefaultDeviceEffectFuture = std::async(
+                    std::launch::async, &AudioPolicyEffects::initDefaultDeviceEffects, this);
+    } else if (loadResult < 0) {
         ALOGW("Failed to load XML effect configuration, fallback to .conf");
         // load automatic audio effect modules
         if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
@@ -562,7 +565,8 @@
     AUDIO_STREAM_BLUETOOTH_SCO_TAG,
     AUDIO_STREAM_ENFORCED_AUDIBLE_TAG,
     AUDIO_STREAM_DTMF_TAG,
-    AUDIO_STREAM_TTS_TAG
+    AUDIO_STREAM_TTS_TAG,
+    AUDIO_STREAM_ASSISTANT_TAG
 };
 
 // returns the audio_stream_t enum corresponding to the output stream name or
@@ -907,8 +911,24 @@
             streams.add(stream.type, effectDescs.release());
         }
     };
+
+    auto loadDeviceProcessingChain = [](auto &processingChain, auto& devicesEffects) {
+        for (auto& deviceProcess : processingChain) {
+
+            auto effectDescs = std::make_unique<EffectDescVector>();
+            for (auto& effect : deviceProcess.effects) {
+                effectDescs->mEffects.add(
+                        new EffectDesc{effect.get().name.c_str(), effect.get().uuid});
+            }
+            auto deviceEffects = std::make_unique<DeviceEffects>(
+                        std::move(effectDescs), deviceProcess.type, deviceProcess.address);
+            devicesEffects.emplace(deviceProcess.address, std::move(deviceEffects));
+        }
+    };
+
     loadProcessingChain(result.parsedConfig->preprocess, mInputSources);
     loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams);
+    loadDeviceProcessingChain(result.parsedConfig->deviceprocess, mDeviceEffects);
     // Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors
     return result.nbSkippedElement;
 }
@@ -941,5 +961,32 @@
     return NO_ERROR;
 }
 
+void AudioPolicyEffects::initDefaultDeviceEffects()
+{
+    Mutex::Autolock _l(mLock);
+    for (const auto& deviceEffectsIter : mDeviceEffects) {
+        const auto& deviceEffects =  deviceEffectsIter.second;
+        for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) {
+            auto fx = std::make_unique<AudioEffect>(
+                        EFFECT_UUID_NULL, String16("android"), &effectDesc->mUuid, 0, nullptr,
+                        nullptr, AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE,
+                        AudioDeviceTypeAddr{deviceEffects->getDeviceType(),
+                                            deviceEffects->getDeviceAddress()});
+            status_t status = fx->initCheck();
+            if (status != NO_ERROR && status != ALREADY_EXISTS) {
+                ALOGE("%s(): failed to create Fx %s on port type=%d address=%s", __func__,
+                      effectDesc->mName, deviceEffects->getDeviceType(),
+                      deviceEffects->getDeviceAddress().c_str());
+                // fx goes out of scope and strong ref on AudioEffect is released
+                continue;
+            }
+            fx->setEnabled(true);
+            ALOGV("%s(): create Fx %s added on port type=%d address=%s", __func__,
+                  effectDesc->mName, deviceEffects->getDeviceType(),
+                  deviceEffects->getDeviceAddress().c_str());
+            deviceEffects->mEffects.push_back(std::move(fx));
+        }
+    }
+}
 
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index dcf093b..88be1ad 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -25,6 +25,9 @@
 #include <system/audio.h>
 #include <utils/Vector.h>
 #include <utils/SortedVector.h>
+#include <android-base/thread_annotations.h>
+
+#include <future>
 
 namespace android {
 
@@ -104,6 +107,7 @@
     status_t removeStreamDefaultEffect(audio_unique_id_t id);
 
 private:
+    void initDefaultDeviceEffects();
 
     // class to store the description of an effects and its parameters
     // as defined in audio_effects.conf
@@ -192,6 +196,28 @@
         Vector< sp<AudioEffect> >mEffects;
     };
 
+    /**
+     * @brief The DeviceEffects class stores the effects associated to a given Device Port.
+     */
+    class DeviceEffects {
+    public:
+        explicit DeviceEffects(std::unique_ptr<EffectDescVector> effectDescriptors,
+                               audio_devices_t device, const std::string& address) :
+            mEffectDescriptors(std::move(effectDescriptors)),
+            mDeviceType(device), mDeviceAddress(address) {}
+        /*virtual*/ ~DeviceEffects() = default;
+
+        std::vector<std::unique_ptr<AudioEffect>> mEffects;
+        audio_devices_t getDeviceType() const { return mDeviceType; }
+        std::string getDeviceAddress() const { return mDeviceAddress; }
+        const std::unique_ptr<EffectDescVector> mEffectDescriptors;
+
+    private:
+        const audio_devices_t mDeviceType;
+        const std::string mDeviceAddress;
+
+    };
+
 
     static const char * const kInputSourceNames[AUDIO_SOURCE_CNT -1];
     static audio_source_t inputSourceNameToEnum(const char *name);
@@ -237,6 +263,19 @@
     KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams;
     // Automatic output effects are unique for audiosession ID
     KeyedVector< audio_session_t, EffectVector* > mOutputSessions;
+
+    /**
+     * @brief mDeviceEffects map of device effects indexed by the device address
+     */
+    std::map<std::string, std::unique_ptr<DeviceEffects>> mDeviceEffects GUARDED_BY(mLock);
+
+    /**
+     * Device Effect initialization must be asynchronous: the audio_policy service parses and init
+     * effect on first reference. AudioFlinger will handle effect creation and register these
+     * effect on audio_policy service.
+     * We must store the reference of the furture garantee real asynchronous operation.
+     */
+    std::future<void> mDefaultDeviceEffectFuture;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 47a103b..c1190be 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -351,12 +351,17 @@
         return NO_INIT;
     }
 
+    audio_source_t inputSource = attr->source;
+    if (inputSource == AUDIO_SOURCE_DEFAULT) {
+        inputSource = AUDIO_SOURCE_MIC;
+    }
+
     // already checked by client, but double-check in case the client wrapper is bypassed
-    if ((attr->source < AUDIO_SOURCE_DEFAULT)
-            || (attr->source >= AUDIO_SOURCE_CNT
-                && attr->source != AUDIO_SOURCE_HOTWORD
-                && attr->source != AUDIO_SOURCE_FM_TUNER
-                && attr->source != AUDIO_SOURCE_ECHO_REFERENCE)) {
+    if ((inputSource < AUDIO_SOURCE_DEFAULT)
+            || (inputSource >= AUDIO_SOURCE_CNT
+                && inputSource != AUDIO_SOURCE_HOTWORD
+                && inputSource != AUDIO_SOURCE_FM_TUNER
+                && inputSource != AUDIO_SOURCE_ECHO_REFERENCE)) {
         return BAD_VALUE;
     }
 
@@ -385,16 +390,16 @@
     }
 
     bool canCaptureOutput = captureAudioOutputAllowed(pid, uid);
-    if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
-        attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
-        attr->source == AUDIO_SOURCE_VOICE_CALL ||
-        attr->source == AUDIO_SOURCE_ECHO_REFERENCE) &&
+    if ((inputSource == AUDIO_SOURCE_VOICE_UPLINK ||
+        inputSource == AUDIO_SOURCE_VOICE_DOWNLINK ||
+        inputSource == AUDIO_SOURCE_VOICE_CALL ||
+        inputSource == AUDIO_SOURCE_ECHO_REFERENCE) &&
         !canCaptureOutput) {
         return PERMISSION_DENIED;
     }
 
     bool canCaptureHotword = captureHotwordAllowed(opPackageName, pid, uid);
-    if ((attr->source == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
+    if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
         return BAD_VALUE;
     }
 
@@ -459,7 +464,7 @@
 
     if (audioPolicyEffects != 0) {
         // create audio pre processors according to input source
-        status_t status = audioPolicyEffects->addInputEffects(*input, attr->source, session);
+        status_t status = audioPolicyEffects->addInputEffects(*input, inputSource, session);
         if (status != NO_ERROR && status != ALREADY_EXISTS) {
             ALOGW("Failed to add effects on input %d", *input);
         }
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 299a50f..0263597 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -794,6 +794,8 @@
                 (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VIRTUAL_SOURCE,
                                      AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
                 (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
                                      AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"}
                 )
         );
@@ -835,6 +837,8 @@
                 (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
                                      AUDIO_SOURCE_DEFAULT, 0, ""},
                 (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
                                      AUDIO_SOURCE_DEFAULT, 0, ""}
                 )
         );
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4227a3b..bda35f3 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2165,7 +2165,9 @@
 }
 
 void Camera3Device::pauseStateNotify(bool enable) {
-    Mutex::Autolock il(mInterfaceLock);
+    // We must not hold mInterfaceLock here since this function is called from
+    // RequestThread::threadLoop and holding mInterfaceLock could lead to
+    // deadlocks (http://b/143513518)
     Mutex::Autolock l(mLock);
 
     mPauseStateNotify = enable;
@@ -2742,7 +2744,9 @@
     ATRACE_CALL();
     bool ret = false;
 
-    Mutex::Autolock il(mInterfaceLock);
+    // We must not hold mInterfaceLock here since this function is called from
+    // RequestThread::threadLoop and holding mInterfaceLock could lead to
+    // deadlocks (http://b/143513518)
     nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
 
     Mutex::Autolock l(mLock);
@@ -5371,6 +5375,9 @@
 bool Camera3Device::RequestThread::threadLoop() {
     ATRACE_CALL();
     status_t res;
+    // Any function called from threadLoop() must not hold mInterfaceLock since
+    // it could lead to deadlocks (disconnect() -> hold mInterfaceMutex -> wait for request thread
+    // to finish -> request thread waits on mInterfaceMutex) http://b/143513518
 
     // Handle paused state.
     if (waitIfPaused()) {
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
index 9f03964..72d42ae 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -27,6 +27,7 @@
 LOCAL_SHARED_LIBRARIES:= \
     libbinder \
     liblog \
+    libmedia \
     libmediadrm \
     libutils \
     libhidlbase \
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index f3339a0..d468406 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -23,4 +23,6 @@
         "-Wall",
     ],
 
+    export_include_dirs: ["."],
+
 }
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index bdcd5e4..45eea0f 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -290,6 +290,18 @@
     }
 }
 
+void ResourceManagerService::mergeResources(
+        MediaResource& r1, const MediaResource& r2) {
+    if (r1.mType == MediaResource::kDrmSession) {
+        // This means we are using a session. Each session's mValue is initialized to UINT64_MAX.
+        // The oftener a session is used the lower it's mValue. During reclaim the session with
+        // the highest mValue/lowest usage would be closed.
+        r1.mValue -= (r1.mValue == 0 ? 0 : 1);
+    } else {
+        r1.mValue += r2.mValue;
+    }
+}
+
 void ResourceManagerService::addResource(
         int pid,
         int uid,
@@ -309,15 +321,16 @@
     ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
 
     for (size_t i = 0; i < resources.size(); ++i) {
-        const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+        const auto &res = resources[i];
+        const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
         if (info.resources.find(resType) == info.resources.end()) {
-            onFirstAdded(resources[i], info);
-            info.resources[resType] = resources[i];
+            onFirstAdded(res, info);
+            info.resources[resType] = res;
         } else {
-            info.resources[resType].mValue += resources[i].mValue;
+            mergeResources(info.resources[resType], res);
         }
     }
-    if (info.deathNotifier == nullptr) {
+    if (info.deathNotifier == nullptr && client != nullptr) {
         info.deathNotifier = new DeathNotifier(this, pid, clientId);
         IInterface::asBinder(client)->linkToDeath(info.deathNotifier);
     }
@@ -351,14 +364,17 @@
     ResourceInfo &info = infos.editValueAt(index);
 
     for (size_t i = 0; i < resources.size(); ++i) {
-        const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+        const auto &res = resources[i];
+        const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
         // ignore if we don't have it
         if (info.resources.find(resType) != info.resources.end()) {
             MediaResource &resource = info.resources[resType];
-            if (resource.mValue > resources[i].mValue) {
-                resource.mValue -= resources[i].mValue;
+            if (resource.mValue > res.mValue) {
+                resource.mValue -= res.mValue;
             } else {
-                onLastRemoved(resources[i], info);
+                // drm sessions always take this branch because res.mValue is set
+                // to UINT64_MAX
+                onLastRemoved(res, info);
                 info.resources.erase(resType);
             }
         }
@@ -430,6 +446,7 @@
         const MediaResource *secureCodec = NULL;
         const MediaResource *nonSecureCodec = NULL;
         const MediaResource *graphicMemory = NULL;
+        const MediaResource *drmSession = NULL;
         for (size_t i = 0; i < resources.size(); ++i) {
             MediaResource::Type type = resources[i].mType;
             if (resources[i].mType == MediaResource::kSecureCodec) {
@@ -438,6 +455,8 @@
                 nonSecureCodec = &resources[i];
             } else if (type == MediaResource::kGraphicMemory) {
                 graphicMemory = &resources[i];
+            } else if (type == MediaResource::kDrmSession) {
+                drmSession = &resources[i];
             }
         }
 
@@ -461,6 +480,12 @@
                 }
             }
         }
+        if (drmSession != NULL) {
+            getClientForResource_l(callingPid, drmSession, &clients);
+            if (clients.size() == 0) {
+                return false;
+            }
+        }
 
         if (clients.size() == 0) {
             // if no secure/non-secure codec conflict, run second pass to handle other resources.
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f086dc3..44d0c28 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -33,7 +33,7 @@
 class ServiceLog;
 struct ProcessInfoInterface;
 
-typedef std::map<std::pair<MediaResource::Type, MediaResource::SubType>, MediaResource> ResourceList;
+typedef std::map<std::tuple<MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>, MediaResource> ResourceList;
 struct ResourceInfo {
     int64_t clientId;
     uid_t uid;
@@ -126,6 +126,9 @@
     void onFirstAdded(const MediaResource& res, const ResourceInfo& clientInfo);
     void onLastRemoved(const MediaResource& res, const ResourceInfo& clientInfo);
 
+    // Merge r2 into r1
+    void mergeResources(MediaResource& r1, const MediaResource& r2);
+
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
     sp<SystemCallbackInterface> mSystemCB;
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ae97ec8..9e14151 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -173,8 +173,9 @@
         // convert resource1 to ResourceList
         ResourceList r1;
         for (size_t i = 0; i < resources1.size(); ++i) {
-            const auto resType = std::make_pair(resources1[i].mType, resources1[i].mSubType);
-            r1[resType] = resources1[i];
+            const auto &res = resources1[i];
+            const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
+            r1[resType] = res;
         }
         return r1 == resources2;
     }