Merge "Set legacy_android10_support to apex modules"
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
index 701ced7..477c371 100644
--- a/apex/testing/Android.bp
+++ b/apex/testing/Android.bp
@@ -15,7 +15,7 @@
 apex {
     name: "test_com.android.media",
     manifest: "test_manifest.json",
-    file_contexts: "com.android.media",
+    file_contexts: ":com.android.media-file_contexts",
     defaults: ["com.android.media-defaults"],
     installable: false,
 }
@@ -23,7 +23,7 @@
 apex {
     name: "test_com.android.media.swcodec",
     manifest: "test_manifest_codec.json",
-    file_contexts: "com.android.media.swcodec",
+    file_contexts: ":com.android.media.swcodec-file_contexts",
     defaults: ["com.android.media.swcodec-defaults"],
     installable: false,
 }
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
index 53b3d84..cef8ef5 100644
--- a/camera/cameraserver/main_cameraserver.cpp
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -34,6 +34,7 @@
     sp<IServiceManager> sm = defaultServiceManager();
     ALOGI("ServiceManager: %p", sm.get());
     CameraService::instantiate();
+    ALOGI("ServiceManager: %p done instantiate", sm.get());
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
 }
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 9d40fd7..457dea9 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -76,6 +76,10 @@
 
 sp<hardware::ICameraService> CameraManagerGlobal::getCameraService() {
     Mutex::Autolock _l(mLock);
+    return getCameraServiceLocked();
+}
+
+sp<hardware::ICameraService> CameraManagerGlobal::getCameraServiceLocked() {
     if (mCameraService.get() == nullptr) {
         if (isCameraServiceDisabled()) {
             return mCameraService;
@@ -216,8 +220,12 @@
     if (pair.second) {
         for (auto& pair : mDeviceStatusMap) {
             const String8& cameraId = pair.first;
-            int32_t status = pair.second;
-
+            int32_t status = pair.second.status;
+            // Don't send initial callbacks for camera ids which don't support
+            // camera2
+            if (!pair.second.supportsHAL3) {
+                continue;
+            }
             sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
             ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
                     callback->onCameraAvailable : callback->onCameraUnavailable;
@@ -236,20 +244,32 @@
     mCallbacks.erase(cb);
 }
 
+bool CameraManagerGlobal::supportsCamera2ApiLocked(const String8 &cameraId) {
+    bool camera2Support = false;
+    auto cs = getCameraServiceLocked();
+    binder::Status serviceRet =
+        cs->supportsCameraApi(String16(cameraId),
+                hardware::ICameraService::API_VERSION_2, &camera2Support);
+    if (!serviceRet.isOk()) {
+        ALOGE("%s: supportsCameraApi2Locked() call failed for cameraId  %s",
+                __FUNCTION__, cameraId.c_str());
+        return false;
+    }
+    return camera2Support;
+}
+
 void CameraManagerGlobal::getCameraIdList(std::vector<String8>* cameraIds) {
     // Ensure that we have initialized/refreshed the list of available devices
-    auto cs = getCameraService();
     Mutex::Autolock _l(mLock);
-
+    // Needed to make sure we're connected to cameraservice
+    getCameraServiceLocked();
     for(auto& deviceStatus : mDeviceStatusMap) {
-        if (deviceStatus.second == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
-                deviceStatus.second == hardware::ICameraServiceListener::STATUS_ENUMERATING) {
+        if (deviceStatus.second.status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT ||
+                deviceStatus.second.status ==
+                        hardware::ICameraServiceListener::STATUS_ENUMERATING) {
             continue;
         }
-        bool camera2Support = false;
-        binder::Status serviceRet = cs->supportsCameraApi(String16(deviceStatus.first),
-                hardware::ICameraService::API_VERSION_2, &camera2Support);
-        if (!serviceRet.isOk() || !camera2Support) {
+        if (!deviceStatus.second.supportsHAL3) {
             continue;
         }
         cameraIds->push_back(deviceStatus.first);
@@ -377,7 +397,7 @@
     bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
     int32_t oldStatus = firstStatus ?
             status : // first status
-            mDeviceStatusMap[cameraId];
+            mDeviceStatusMap[cameraId].status;
 
     if (!firstStatus &&
             isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
@@ -385,16 +405,19 @@
         return;
     }
 
+    bool supportsHAL3 = supportsCamera2ApiLocked(cameraId);
     // Iterate through all registered callbacks
-    mDeviceStatusMap[cameraId] = status;
-    for (auto cb : mCallbacks) {
-        sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
-        ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
-                cb.mAvailable : cb.mUnavailable;
-        msg->setPointer(kCallbackFpKey, (void *) cbFp);
-        msg->setPointer(kContextKey, cb.mContext);
-        msg->setString(kCameraIdKey, AString(cameraId));
-        msg->post();
+    mDeviceStatusMap[cameraId] = StatusAndHAL3Support(status, supportsHAL3);
+    if (supportsHAL3) {
+        for (auto cb : mCallbacks) {
+            sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+            ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+                    cb.mAvailable : cb.mUnavailable;
+            msg->setPointer(kCallbackFpKey, (void *) cbFp);
+            msg->setPointer(kContextKey, cb.mContext);
+            msg->setString(kCameraIdKey, AString(cameraId));
+            msg->post();
+        }
     }
     if (status == hardware::ICameraServiceListener::STATUS_NOT_PRESENT) {
         mDeviceStatusMap.erase(cameraId);
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 8c1da36..e945ba0 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -66,9 +66,9 @@
 
   private:
     sp<hardware::ICameraService> mCameraService;
-    const int          kCameraServicePollDelay = 500000; // 0.5s
-    const char*        kCameraServiceName      = "media.camera";
-    Mutex              mLock;
+    const int                    kCameraServicePollDelay = 500000; // 0.5s
+    const char*                  kCameraServiceName      = "media.camera";
+    Mutex                        mLock;
 
     class DeathNotifier : public IBinder::DeathRecipient {
       public:
@@ -156,12 +156,14 @@
     sp<CallbackHandler> mHandler;
     sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
 
+    sp<hardware::ICameraService> getCameraServiceLocked();
     void onCameraAccessPrioritiesChanged();
     void onStatusChanged(int32_t status, const String8& cameraId);
     void onStatusChangedLocked(int32_t status, const String8& cameraId);
     // Utils for status
     static bool validStatus(int32_t status);
     static bool isStatusAvailable(int32_t status);
+    bool supportsCamera2ApiLocked(const String8 &cameraId);
 
     // The sort logic must match the logic in
     // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
@@ -184,8 +186,16 @@
         }
     };
 
+    struct StatusAndHAL3Support {
+        int32_t status = hardware::ICameraServiceListener::STATUS_NOT_PRESENT;
+        bool supportsHAL3 = false;
+        StatusAndHAL3Support(int32_t st, bool HAL3support):
+                status(st), supportsHAL3(HAL3support) { };
+        StatusAndHAL3Support() = default;
+    };
+
     // Map camera_id -> status
-    std::map<String8, int32_t, CameraIdComparator> mDeviceStatusMap;
+    std::map<String8, StatusAndHAL3Support, CameraIdComparator> mDeviceStatusMap;
 
     // For the singleton instance
     static Mutex sLock;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index 23a35e5..f164f28 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -62,10 +62,8 @@
       secure, keyId, iv, mode, pattern, subSamples, source, offset, destination,
       [&](Status_V1_2 hStatus, uint32_t hBytesWritten, hidl_string hDetailedError) {
         status = toStatus_1_0(hStatus);
-        if (status == Status::OK) {
-          bytesWritten = hBytesWritten;
-          detailedError = hDetailedError;
-        }
+        bytesWritten = hBytesWritten;
+        detailedError = hDetailedError;
       }
     );
 
@@ -109,6 +107,10 @@
                  "destination decrypt buffer base not set");
         return Void();
       }
+    } else {
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
+                 "destination type not supported");
+        return Void();
     }
 
     sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
@@ -126,38 +128,45 @@
             (static_cast<void *>(sourceBase->getPointer()));
     uint8_t* srcPtr = static_cast<uint8_t *>(base + source.offset + offset);
     void* destPtr = NULL;
-    if (destination.type == BufferType::SHARED_MEMORY) {
-        const SharedBuffer& destBuffer = destination.nonsecureMemory;
-        sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
-        if (destBase == nullptr) {
-            _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
-            return Void();
-        }
-
-        if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
-            _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
-            return Void();
-        }
-        destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
-    } else if (destination.type == BufferType::NATIVE_HANDLE) {
-        native_handle_t *handle = const_cast<native_handle_t *>(
-        destination.secureMemory.getNativeHandle());
-        destPtr = static_cast<void *>(handle);
+    // destination.type == BufferType::SHARED_MEMORY
+    const SharedBuffer& destBuffer = destination.nonsecureMemory;
+    sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
+    if (destBase == nullptr) {
+        _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
+        return Void();
     }
 
+    if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
+        _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
+        return Void();
+    }
+    destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
+
+
     // Calculate the output buffer size and determine if any subsamples are
     // encrypted.
     size_t destSize = 0;
     bool haveEncryptedSubsamples = false;
     for (size_t i = 0; i < subSamples.size(); i++) {
         const SubSample &subSample = subSamples[i];
-        destSize += subSample.numBytesOfClearData;
-        destSize += subSample.numBytesOfEncryptedData;
+        if (__builtin_add_overflow(destSize, subSample.numBytesOfClearData, &destSize)) {
+            _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample clear size overflow");
+            return Void();
+        }
+        if (__builtin_add_overflow(destSize, subSample.numBytesOfEncryptedData, &destSize)) {
+            _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample encrypted size overflow");
+            return Void();
+        }
         if (subSample.numBytesOfEncryptedData > 0) {
         haveEncryptedSubsamples = true;
         }
     }
 
+    if (destSize > destBuffer.size) {
+        _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample sum too large");
+        return Void();
+    }
+
     if (mode == Mode::UNENCRYPTED) {
         if (haveEncryptedSubsamples) {
             _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index d75f71c..d5f3ba2 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -317,14 +317,6 @@
     ~DecryptHandle() {
         delete decryptInfo; decryptInfo = NULL;
     }
-
-    bool operator<(const DecryptHandle& handle) const {
-        return (decryptId < handle.decryptId);
-    }
-
-    bool operator==(const DecryptHandle& handle) const {
-        return (decryptId == handle.decryptId);
-    }
 };
 
 };
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 6697cb5..e33804d 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -40,21 +40,6 @@
 	frameworks/av/media/libmedia \
 	external/sonic \
 
-# If AUDIOSERVER_MULTILIB in device.mk is non-empty then it is used to control
-# the LOCAL_MULTILIB for all audioserver exclusive libraries.
-# This is relevant for 64 bit architectures where either or both
-# 32 and 64 bit libraries may be built.
-#
-# AUDIOSERVER_MULTILIB may be set as follows:
-#   32      to build 32 bit audioserver libraries and 32 bit audioserver.
-#   64      to build 64 bit audioserver libraries and 64 bit audioserver.
-#   both    to build both 32 bit and 64 bit libraries,
-#           and use primary target architecture (32 or 64) for audioserver.
-#   first   to build libraries and audioserver for the primary target architecture only.
-#   <empty> to build both 32 and 64 bit libraries and primary target audioserver.
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
 LOCAL_MODULE := audioserver
 
 LOCAL_INIT_RC := audioserver.rc
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 4ae3b24..97f114a 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -1,9 +1,5 @@
-cc_library {
-    name: "libstagefright_bufferpool@2.0",
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
+cc_defaults {
+    name: "libstagefright_bufferpool@2.0-default",
     srcs: [
         "Accessor.cpp",
         "AccessorImpl.cpp",
@@ -29,3 +25,23 @@
         "android.hardware.media.bufferpool@2.0",
     ],
 }
+
+cc_library {
+    name: "libstagefright_bufferpool@2.0.1",
+    defaults: ["libstagefright_bufferpool@2.0-default"],
+    vendor_available: true,
+    cflags: [
+        "-DBUFFERPOOL_CLONE_HANDLES",
+    ],
+}
+
+// Deprecated. Do not use. Use libstagefright_bufferpool@2.0.1 instead.
+cc_library {
+    name: "libstagefright_bufferpool@2.0",
+    defaults: ["libstagefright_bufferpool@2.0-default"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+}
+
diff --git a/media/bufferpool/2.0/ClientManager.cpp b/media/bufferpool/2.0/ClientManager.cpp
index c31d313..87ee4e8 100644
--- a/media/bufferpool/2.0/ClientManager.cpp
+++ b/media/bufferpool/2.0/ClientManager.cpp
@@ -351,7 +351,21 @@
         }
         client = it->second;
     }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+    native_handle_t *origHandle;
+    ResultStatus res = client->allocate(params, &origHandle, buffer);
+    if (res != ResultStatus::OK) {
+        return res;
+    }
+    *handle = native_handle_clone(origHandle);
+    if (handle == NULL) {
+        buffer->reset();
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+#else
     return client->allocate(params, handle, buffer);
+#endif
 }
 
 ResultStatus ClientManager::Impl::receive(
@@ -367,7 +381,22 @@
         }
         client = it->second;
     }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+    native_handle_t *origHandle;
+    ResultStatus res = client->receive(
+            transactionId, bufferId, timestampUs, &origHandle, buffer);
+    if (res != ResultStatus::OK) {
+        return res;
+    }
+    *handle = native_handle_clone(origHandle);
+    if (handle == NULL) {
+        buffer->reset();
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+#else
     return client->receive(transactionId, bufferId, timestampUs, handle, buffer);
+#endif
 }
 
 ResultStatus ClientManager::Impl::postSend(
diff --git a/media/bufferpool/2.0/include/bufferpool/ClientManager.h b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
index 953c304..24b61f4 100644
--- a/media/bufferpool/2.0/include/bufferpool/ClientManager.h
+++ b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
@@ -104,7 +104,9 @@
     ResultStatus flush(ConnectionId connectionId);
 
     /**
-     * Allocates a buffer from the specified connection.
+     * Allocates a buffer from the specified connection. The output parameter
+     * handle is cloned from the internal handle. So it is safe to use directly,
+     * and it should be deleted and destroyed after use.
      *
      * @param connectionId  The id of the connection.
      * @param params        The allocation parameters.
@@ -123,7 +125,9 @@
                           std::shared_ptr<BufferPoolData> *buffer);
 
     /**
-     * Receives a buffer for the transaction.
+     * Receives a buffer for the transaction. The output parameter handle is
+     * cloned from the internal handle. So it is safe to use directly, and it
+     * should be deleted and destoyed after use.
      *
      * @param connectionId  The id of the receiving connection.
      * @param transactionId The id for the transaction.
diff --git a/media/codec2/components/aom/Android.bp b/media/codec2/components/aom/Android.bp
index 0fabf5c..61dbd4c 100644
--- a/media/codec2/components/aom/Android.bp
+++ b/media/codec2/components/aom/Android.bp
@@ -1,10 +1,16 @@
 cc_library_shared {
-    name: "libcodec2_soft_av1dec",
+    name: "libcodec2_soft_av1dec_aom",
     defaults: [
         "libcodec2_soft-defaults",
         "libcodec2_soft_sanitize_all-defaults",
     ],
 
+    // coordinated with frameworks/av/media/codec2/components/gav1/Android.bp
+    // so only 1 of them has the official c2.android.av1.decoder name
+    cflags: [
+        "-DCODECNAME=\"c2.android.av1-aom.decoder\"",
+    ],
+
     srcs: ["C2SoftAomDec.cpp"],
     static_libs: ["libaom"],
 
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index 769895c..36137e6 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -29,7 +29,8 @@
 
 namespace android {
 
-constexpr char COMPONENT_NAME[] = "c2.android.av1.decoder";
+// codecname set and passed in as a compile flag from Android.bp
+constexpr char COMPONENT_NAME[] = CODECNAME;
 
 class C2SoftAomDec::IntfImpl : public SimpleInterface<void>::BaseParams {
   public:
@@ -340,6 +341,7 @@
     aom_codec_flags_t flags;
     memset(&flags, 0, sizeof(aom_codec_flags_t));
 
+    ALOGV("Using libaom AV1 software decoder.");
     aom_codec_err_t err;
     if ((err = aom_codec_dec_init(mCodecCtx, aom_codec_av1_dx(), &cfg, 0))) {
         ALOGE("av1 decoder failed to initialize. (%d)", err);
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 3f015b4..fa98178 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -33,7 +33,8 @@
 namespace {
 
 constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
-
+constexpr uint32_t kDefaultOutputDelay = 8;
+constexpr uint32_t kMaxOutputDelay = 16;
 }  // namespace
 
 class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -54,7 +55,9 @@
         // TODO: Proper support for reorder depth.
         addParameter(
                 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
-                .withConstValue(new C2PortActualDelayTuning::output(8u))
+                .withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay))
+                .withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)})
+                .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
                 .build());
 
         // TODO: output latency and reordering
@@ -196,7 +199,6 @@
                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
                 .build());
     }
-
     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
                           C2P<C2StreamPictureSizeInfo::output> &me) {
         (void)mayBlock;
@@ -333,6 +335,7 @@
       mDecHandle(nullptr),
       mOutBufferFlush(nullptr),
       mIvColorFormat(IV_YUV_420P),
+      mOutputDelay(kDefaultOutputDelay),
       mWidth(320),
       mHeight(240),
       mHeaderDecoded(false),
@@ -882,6 +885,26 @@
             work->result = C2_CORRUPTED;
             return;
         }
+        if (s_decode_op.i4_reorder_depth >= 0 && mOutputDelay != s_decode_op.i4_reorder_depth) {
+            mOutputDelay = s_decode_op.i4_reorder_depth;
+            ALOGV("New Output delay %d ", mOutputDelay);
+
+            C2PortActualDelayTuning::output outputDelay(mOutputDelay);
+            std::vector<std::unique_ptr<C2SettingResult>> failures;
+            c2_status_t err =
+                mIntf->config({&outputDelay}, C2_MAY_BLOCK, &failures);
+            if (err == OK) {
+                work->worklets.front()->output.configUpdate.push_back(
+                    C2Param::Copy(outputDelay));
+            } else {
+                ALOGE("Cannot set output delay");
+                mSignalledError = true;
+                work->workletsProcessed = 1u;
+                work->result = C2_CORRUPTED;
+                return;
+            }
+            continue;
+        }
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
             if (mHeaderDecoded == false) {
                 mHeaderDecoded = true;
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index 72ee583..4414a26 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -157,7 +157,7 @@
 
     size_t mNumCores;
     IV_COLOR_FORMAT_T mIvColorFormat;
-
+    uint32_t mOutputDelay;
     uint32_t mWidth;
     uint32_t mHeight;
     uint32_t mStride;
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index b41c271..e3d419c 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -40,7 +40,7 @@
 namespace {
 
 constexpr char COMPONENT_NAME[] = "c2.android.avc.encoder";
-
+constexpr uint32_t kMinOutBufferSize = 524288;
 void ParseGop(
         const C2StreamGopTuning::output &gop,
         uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) {
@@ -440,8 +440,7 @@
       mSignalledError(false),
       mCodecCtx(nullptr),
       mOutBlock(nullptr),
-      // TODO: output buffer size
-      mOutBufferSize(524288) {
+      mOutBufferSize(kMinOutBufferSize) {
 
     // If dump is enabled, then open create an empty file
     GENERATE_FILE_NAMES();
@@ -951,6 +950,9 @@
 
     mStride = width;
 
+    // Assume worst case output buffer size to be equal to number of bytes in input
+    mOutBufferSize = std::max(width * height * 3 / 2, kMinOutBufferSize);
+
     // TODO
     mIvVideoColorFormat = IV_YUV_420P;
 
diff --git a/media/codec2/components/g711/C2SoftG711Dec.cpp b/media/codec2/components/g711/C2SoftG711Dec.cpp
index 43b843a..b6cc32e 100644
--- a/media/codec2/components/g711/C2SoftG711Dec.cpp
+++ b/media/codec2/components/g711/C2SoftG711Dec.cpp
@@ -73,7 +73,7 @@
 
         addParameter(
                 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
-                .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
+                .withDefault(new C2StreamChannelCountInfo::output(0u, 6))
                 .withFields({C2F(mChannelCount, value).equalTo(1)})
                 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
                 .build());
diff --git a/media/codec2/components/gav1/Android.bp b/media/codec2/components/gav1/Android.bp
new file mode 100644
index 0000000..5c4abb7
--- /dev/null
+++ b/media/codec2/components/gav1/Android.bp
@@ -0,0 +1,20 @@
+cc_library_shared {
+    name: "libcodec2_soft_av1dec_gav1",
+    defaults: [
+        "libcodec2_soft-defaults",
+        "libcodec2_soft_sanitize_all-defaults",
+    ],
+
+    // coordinated with frameworks/av/media/codec2/components/aom/Android.bp
+    // so only 1 of them has the official c2.android.av1.decoder name
+    cflags: [
+        "-DCODECNAME=\"c2.android.av1.decoder\"",
+    ],
+
+    srcs: ["C2SoftGav1Dec.cpp"],
+    static_libs: ["libgav1"],
+
+    include_dirs: [
+        "external/libgav1/libgav1/",
+    ],
+}
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
new file mode 100644
index 0000000..ec5f549
--- /dev/null
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -0,0 +1,792 @@
+/*
+ * 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 "C2SoftGav1Dec"
+#include "C2SoftGav1Dec.h"
+
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+#include <log/log.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+
+namespace android {
+
+// codecname set and passed in as a compile flag from Android.bp
+constexpr char COMPONENT_NAME[] = CODECNAME;
+
+class C2SoftGav1Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
+ public:
+  explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
+      : SimpleInterface<void>::BaseParams(
+            helper, COMPONENT_NAME, C2Component::KIND_DECODER,
+            C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
+    noPrivateBuffers();  // TODO: account for our buffers here.
+    noInputReferences();
+    noOutputReferences();
+    noInputLatency();
+    noTimeStretch();
+
+    addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
+                     .withConstValue(new C2ComponentAttributesSetting(
+                         C2Component::ATTRIB_IS_TEMPORAL))
+                     .build());
+
+    addParameter(
+        DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
+            .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
+            .withFields({
+                C2F(mSize, width).inRange(2, 2048, 2),
+                C2F(mSize, height).inRange(2, 2048, 2),
+            })
+            .withSetter(SizeSetter)
+            .build());
+
+    addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+                     .withDefault(new C2StreamProfileLevelInfo::input(
+                         0u, C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1))
+                     .withFields({C2F(mProfileLevel, profile)
+                                      .oneOf({C2Config::PROFILE_AV1_0,
+                                              C2Config::PROFILE_AV1_1}),
+                                  C2F(mProfileLevel, level)
+                                      .oneOf({
+                                          C2Config::LEVEL_AV1_2,
+                                          C2Config::LEVEL_AV1_2_1,
+                                          C2Config::LEVEL_AV1_2_2,
+                                          C2Config::LEVEL_AV1_3,
+                                          C2Config::LEVEL_AV1_3_1,
+                                          C2Config::LEVEL_AV1_3_2,
+                                      })})
+                     .withSetter(ProfileLevelSetter, mSize)
+                     .build());
+
+    mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
+    addParameter(
+        DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
+            .withDefault(mHdr10PlusInfoInput)
+            .withFields({
+                C2F(mHdr10PlusInfoInput, m.value).any(),
+            })
+            .withSetter(Hdr10PlusInfoInputSetter)
+            .build());
+
+    mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
+    addParameter(
+        DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
+            .withDefault(mHdr10PlusInfoOutput)
+            .withFields({
+                C2F(mHdr10PlusInfoOutput, m.value).any(),
+            })
+            .withSetter(Hdr10PlusInfoOutputSetter)
+            .build());
+
+    addParameter(
+        DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
+            .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
+            .withFields({
+                C2F(mSize, width).inRange(2, 2048, 2),
+                C2F(mSize, height).inRange(2, 2048, 2),
+            })
+            .withSetter(MaxPictureSizeSetter, mSize)
+            .build());
+
+    addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
+                     .withDefault(new C2StreamMaxBufferSizeInfo::input(
+                         0u, 320 * 240 * 3 / 4))
+                     .withFields({
+                         C2F(mMaxInputSize, value).any(),
+                     })
+                     .calculatedAs(MaxInputSizeSetter, mMaxSize)
+                     .build());
+
+    C2ChromaOffsetStruct locations[1] = {C2ChromaOffsetStruct::ITU_YUV_420_0()};
+    std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
+        C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
+                                               C2Color::YUV_420);
+    memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
+
+    defaultColorInfo = C2StreamColorInfo::output::AllocShared(
+        {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
+        C2Color::YUV_420);
+    helper->addStructDescriptors<C2ChromaOffsetStruct>();
+
+    addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
+                     .withConstValue(defaultColorInfo)
+                     .build());
+
+    addParameter(
+        DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
+            .withDefault(new C2StreamColorAspectsTuning::output(
+                0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
+                C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
+            .withFields(
+                {C2F(mDefaultColorAspects, range)
+                     .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
+                 C2F(mDefaultColorAspects, primaries)
+                     .inRange(C2Color::PRIMARIES_UNSPECIFIED,
+                              C2Color::PRIMARIES_OTHER),
+                 C2F(mDefaultColorAspects, transfer)
+                     .inRange(C2Color::TRANSFER_UNSPECIFIED,
+                              C2Color::TRANSFER_OTHER),
+                 C2F(mDefaultColorAspects, matrix)
+                     .inRange(C2Color::MATRIX_UNSPECIFIED,
+                              C2Color::MATRIX_OTHER)})
+            .withSetter(DefaultColorAspectsSetter)
+            .build());
+
+    // TODO: support more formats?
+    addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
+                     .withConstValue(new C2StreamPixelFormatInfo::output(
+                         0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
+                     .build());
+  }
+
+  static C2R SizeSetter(bool mayBlock,
+                        const C2P<C2StreamPictureSizeInfo::output> &oldMe,
+                        C2P<C2StreamPictureSizeInfo::output> &me) {
+    (void)mayBlock;
+    C2R res = C2R::Ok();
+    if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
+      res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
+      me.set().width = oldMe.v.width;
+    }
+    if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
+      res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
+      me.set().height = oldMe.v.height;
+    }
+    return res;
+  }
+
+  static C2R MaxPictureSizeSetter(
+      bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
+      const C2P<C2StreamPictureSizeInfo::output> &size) {
+    (void)mayBlock;
+    // TODO: get max width/height from the size's field helpers vs.
+    // hardcoding
+    me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
+    me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
+    return C2R::Ok();
+  }
+
+  static C2R MaxInputSizeSetter(
+      bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
+      const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
+    (void)mayBlock;
+    // assume compression ratio of 2
+    me.set().value =
+        (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+    return C2R::Ok();
+  }
+
+  static C2R DefaultColorAspectsSetter(
+      bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
+    (void)mayBlock;
+    if (me.v.range > C2Color::RANGE_OTHER) {
+      me.set().range = C2Color::RANGE_OTHER;
+    }
+    if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
+      me.set().primaries = C2Color::PRIMARIES_OTHER;
+    }
+    if (me.v.transfer > C2Color::TRANSFER_OTHER) {
+      me.set().transfer = C2Color::TRANSFER_OTHER;
+    }
+    if (me.v.matrix > C2Color::MATRIX_OTHER) {
+      me.set().matrix = C2Color::MATRIX_OTHER;
+    }
+    return C2R::Ok();
+  }
+
+  static C2R ProfileLevelSetter(
+      bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
+      const C2P<C2StreamPictureSizeInfo::output> &size) {
+    (void)mayBlock;
+    (void)size;
+    (void)me;  // TODO: validate
+    return C2R::Ok();
+  }
+
+  std::shared_ptr<C2StreamColorAspectsTuning::output>
+  getDefaultColorAspects_l() {
+    return mDefaultColorAspects;
+  }
+
+  static C2R Hdr10PlusInfoInputSetter(bool mayBlock,
+                                      C2P<C2StreamHdr10PlusInfo::input> &me) {
+    (void)mayBlock;
+    (void)me;  // TODO: validate
+    return C2R::Ok();
+  }
+
+  static C2R Hdr10PlusInfoOutputSetter(bool mayBlock,
+                                       C2P<C2StreamHdr10PlusInfo::output> &me) {
+    (void)mayBlock;
+    (void)me;  // TODO: validate
+    return C2R::Ok();
+  }
+
+ private:
+  std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
+  std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
+  std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
+  std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
+  std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
+  std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
+  std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
+  std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
+  std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
+};
+
+C2SoftGav1Dec::C2SoftGav1Dec(const char *name, c2_node_id_t id,
+                             const std::shared_ptr<IntfImpl> &intfImpl)
+    : SimpleC2Component(
+          std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
+      mIntf(intfImpl),
+      mCodecCtx(nullptr) {
+  gettimeofday(&mTimeStart, nullptr);
+  gettimeofday(&mTimeEnd, nullptr);
+}
+
+C2SoftGav1Dec::~C2SoftGav1Dec() { onRelease(); }
+
+c2_status_t C2SoftGav1Dec::onInit() {
+  return initDecoder() ? C2_OK : C2_CORRUPTED;
+}
+
+c2_status_t C2SoftGav1Dec::onStop() {
+  mSignalledError = false;
+  mSignalledOutputEos = false;
+  return C2_OK;
+}
+
+void C2SoftGav1Dec::onReset() {
+  (void)onStop();
+  c2_status_t err = onFlush_sm();
+  if (err != C2_OK) {
+    ALOGW("Failed to flush the av1 decoder. Trying to hard reset.");
+    destroyDecoder();
+    if (!initDecoder()) {
+      ALOGE("Hard reset failed.");
+    }
+  }
+}
+
+void C2SoftGav1Dec::onRelease() { destroyDecoder(); }
+
+c2_status_t C2SoftGav1Dec::onFlush_sm() {
+  Libgav1StatusCode status =
+      mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
+                              /*user_private_data=*/0);
+  if (status != kLibgav1StatusOk) {
+    ALOGE("Failed to flush av1 decoder. status: %d.", status);
+    return C2_CORRUPTED;
+  }
+
+  // Dequeue frame (if any) that was enqueued previously.
+  const libgav1::DecoderBuffer *buffer;
+  status = mCodecCtx->DequeueFrame(&buffer);
+  if (status != kLibgav1StatusOk) {
+    ALOGE("Failed to dequeue frame after flushing the av1 decoder. status: %d",
+          status);
+    return C2_CORRUPTED;
+  }
+
+  mSignalledError = false;
+  mSignalledOutputEos = false;
+
+  return C2_OK;
+}
+
+static int GetCPUCoreCount() {
+  int cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+  cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+  // _SC_NPROC_ONLN must be defined...
+  cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+  CHECK(cpuCoreCount >= 1);
+  ALOGV("Number of CPU cores: %d", cpuCoreCount);
+  return cpuCoreCount;
+}
+
+bool C2SoftGav1Dec::initDecoder() {
+  mSignalledError = false;
+  mSignalledOutputEos = false;
+  mCodecCtx.reset(new libgav1::Decoder());
+
+  if (mCodecCtx == nullptr) {
+    ALOGE("mCodecCtx is null");
+    return false;
+  }
+
+  libgav1::DecoderSettings settings = {};
+  settings.threads = GetCPUCoreCount();
+
+  ALOGV("Using libgav1 AV1 software decoder.");
+  Libgav1StatusCode status = mCodecCtx->Init(&settings);
+  if (status != kLibgav1StatusOk) {
+    ALOGE("av1 decoder failed to initialize. status: %d.", status);
+    return false;
+  }
+
+  return true;
+}
+
+void C2SoftGav1Dec::destroyDecoder() { mCodecCtx = nullptr; }
+
+void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
+  uint32_t flags = 0;
+  if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+    flags |= C2FrameData::FLAG_END_OF_STREAM;
+    ALOGV("signalling eos");
+  }
+  work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+  work->worklets.front()->output.buffers.clear();
+  work->worklets.front()->output.ordinal = work->input.ordinal;
+  work->workletsProcessed = 1u;
+}
+
+void C2SoftGav1Dec::finishWork(uint64_t index,
+                               const std::unique_ptr<C2Work> &work,
+                               const std::shared_ptr<C2GraphicBlock> &block) {
+  std::shared_ptr<C2Buffer> buffer =
+      createGraphicBuffer(block, C2Rect(mWidth, mHeight));
+  auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
+    uint32_t flags = 0;
+    if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
+        (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
+      flags |= C2FrameData::FLAG_END_OF_STREAM;
+      ALOGV("signalling eos");
+    }
+    work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+    work->worklets.front()->output.buffers.clear();
+    work->worklets.front()->output.buffers.push_back(buffer);
+    work->worklets.front()->output.ordinal = work->input.ordinal;
+    work->workletsProcessed = 1u;
+  };
+  if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
+    fillWork(work);
+  } else {
+    finish(index, fillWork);
+  }
+}
+
+void C2SoftGav1Dec::process(const std::unique_ptr<C2Work> &work,
+                            const std::shared_ptr<C2BlockPool> &pool) {
+  work->result = C2_OK;
+  work->workletsProcessed = 0u;
+  work->worklets.front()->output.configUpdate.clear();
+  work->worklets.front()->output.flags = work->input.flags;
+  if (mSignalledError || mSignalledOutputEos) {
+    work->result = C2_BAD_VALUE;
+    return;
+  }
+
+  size_t inOffset = 0u;
+  size_t inSize = 0u;
+  C2ReadView rView = mDummyReadView;
+  if (!work->input.buffers.empty()) {
+    rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
+    inSize = rView.capacity();
+    if (inSize && rView.error()) {
+      ALOGE("read view map failed %d", rView.error());
+      work->result = C2_CORRUPTED;
+      return;
+    }
+  }
+
+  bool codecConfig =
+      ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
+  bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
+
+  ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
+        (int)work->input.ordinal.timestamp.peeku(),
+        (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
+
+  if (codecConfig) {
+    fillEmptyWork(work);
+    return;
+  }
+
+  int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
+  if (inSize) {
+    uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
+    int32_t decodeTime = 0;
+    int32_t delay = 0;
+
+    GETTIME(&mTimeStart, nullptr);
+    TIME_DIFF(mTimeEnd, mTimeStart, delay);
+
+    const Libgav1StatusCode status =
+        mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex);
+
+    GETTIME(&mTimeEnd, nullptr);
+    TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
+    ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
+
+    if (status != kLibgav1StatusOk) {
+      ALOGE("av1 decoder failed to decode frame. status: %d.", status);
+      work->result = C2_CORRUPTED;
+      work->workletsProcessed = 1u;
+      mSignalledError = true;
+      return;
+    }
+
+  } else {
+    const Libgav1StatusCode status =
+        mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
+                                /*user_private_data=*/0);
+    if (status != kLibgav1StatusOk) {
+      ALOGE("Failed to flush av1 decoder. status: %d.", status);
+      work->result = C2_CORRUPTED;
+      work->workletsProcessed = 1u;
+      mSignalledError = true;
+      return;
+    }
+  }
+
+  (void)outputBuffer(pool, work);
+
+  if (eos) {
+    drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
+    mSignalledOutputEos = true;
+  } else if (!inSize) {
+    fillEmptyWork(work);
+  }
+}
+
+static void copyOutputBufferToYV12Frame(uint8_t *dst, const uint8_t *srcY,
+                                        const uint8_t *srcU,
+                                        const uint8_t *srcV, size_t srcYStride,
+                                        size_t srcUStride, size_t srcVStride,
+                                        uint32_t width, uint32_t height) {
+  const size_t dstYStride = align(width, 16);
+  const size_t dstUVStride = align(dstYStride / 2, 16);
+  uint8_t *const dstStart = dst;
+
+  for (size_t i = 0; i < height; ++i) {
+    memcpy(dst, srcY, width);
+    srcY += srcYStride;
+    dst += dstYStride;
+  }
+
+  dst = dstStart + dstYStride * height;
+  for (size_t i = 0; i < height / 2; ++i) {
+    memcpy(dst, srcV, width / 2);
+    srcV += srcVStride;
+    dst += dstUVStride;
+  }
+
+  dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
+  for (size_t i = 0; i < height / 2; ++i) {
+    memcpy(dst, srcU, width / 2);
+    srcU += srcUStride;
+    dst += dstUVStride;
+  }
+}
+
+static void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY,
+                                        const uint16_t *srcU,
+                                        const uint16_t *srcV, size_t srcYStride,
+                                        size_t srcUStride, size_t srcVStride,
+                                        size_t dstStride, size_t width,
+                                        size_t height) {
+  // Converting two lines at a time, slightly faster
+  for (size_t y = 0; y < height; y += 2) {
+    uint32_t *dstTop = (uint32_t *)dst;
+    uint32_t *dstBot = (uint32_t *)(dst + dstStride);
+    uint16_t *ySrcTop = (uint16_t *)srcY;
+    uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
+    uint16_t *uSrc = (uint16_t *)srcU;
+    uint16_t *vSrc = (uint16_t *)srcV;
+
+    uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
+    size_t x = 0;
+    for (; x < width - 3; x += 4) {
+      u01 = *((uint32_t *)uSrc);
+      uSrc += 2;
+      v01 = *((uint32_t *)vSrc);
+      vSrc += 2;
+
+      y01 = *((uint32_t *)ySrcTop);
+      ySrcTop += 2;
+      y23 = *((uint32_t *)ySrcTop);
+      ySrcTop += 2;
+      y45 = *((uint32_t *)ySrcBot);
+      ySrcBot += 2;
+      y67 = *((uint32_t *)ySrcBot);
+      ySrcBot += 2;
+
+      uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+      uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
+
+      *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
+      *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
+      *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
+      *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
+
+      *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
+      *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
+      *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
+      *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
+    }
+
+    // There should be at most 2 more pixels to process. Note that we don't
+    // need to consider odd case as the buffer is always aligned to even.
+    if (x < width) {
+      u01 = *uSrc;
+      v01 = *vSrc;
+      y01 = *((uint32_t *)ySrcTop);
+      y45 = *((uint32_t *)ySrcBot);
+      uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+      *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
+      *dstTop++ = ((y01 >> 16) << 10) | uv0;
+      *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
+      *dstBot++ = ((y45 >> 16) << 10) | uv0;
+    }
+
+    srcY += srcYStride * 2;
+    srcU += srcUStride;
+    srcV += srcVStride;
+    dst += dstStride * 2;
+  }
+}
+
+static void convertYUV420Planar16ToYUV420Planar(
+    uint8_t *dst, const uint16_t *srcY, const uint16_t *srcU,
+    const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
+    size_t srcVStride, size_t dstStride, size_t width, size_t height) {
+  uint8_t *dstY = (uint8_t *)dst;
+  size_t dstYSize = dstStride * height;
+  size_t dstUVStride = align(dstStride / 2, 16);
+  size_t dstUVSize = dstUVStride * height / 2;
+  uint8_t *dstV = dstY + dstYSize;
+  uint8_t *dstU = dstV + dstUVSize;
+
+  for (size_t y = 0; y < height; ++y) {
+    for (size_t x = 0; x < width; ++x) {
+      dstY[x] = (uint8_t)(srcY[x] >> 2);
+    }
+
+    srcY += srcYStride;
+    dstY += dstStride;
+  }
+
+  for (size_t y = 0; y < (height + 1) / 2; ++y) {
+    for (size_t x = 0; x < (width + 1) / 2; ++x) {
+      dstU[x] = (uint8_t)(srcU[x] >> 2);
+      dstV[x] = (uint8_t)(srcV[x] >> 2);
+    }
+
+    srcU += srcUStride;
+    srcV += srcVStride;
+    dstU += dstUVStride;
+    dstV += dstUVStride;
+  }
+}
+
+bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool,
+                                 const std::unique_ptr<C2Work> &work) {
+  if (!(work && pool)) return false;
+
+  const libgav1::DecoderBuffer *buffer;
+  const Libgav1StatusCode status = mCodecCtx->DequeueFrame(&buffer);
+
+  if (status != kLibgav1StatusOk) {
+    ALOGE("av1 decoder DequeueFrame failed. status: %d.", status);
+    return false;
+  }
+
+  // |buffer| can be NULL if status was equal to kLibgav1StatusOk. This is not
+  // an error. This could mean one of two things:
+  //  - The EnqueueFrame() call was either a flush (called with nullptr).
+  //  - The enqueued frame did not have any displayable frames.
+  if (!buffer) {
+    return false;
+  }
+
+  const int width = buffer->displayed_width[0];
+  const int height = buffer->displayed_height[0];
+  if (width != mWidth || height != mHeight) {
+    mWidth = width;
+    mHeight = height;
+
+    C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
+    c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+    if (err == C2_OK) {
+      work->worklets.front()->output.configUpdate.push_back(
+          C2Param::Copy(size));
+    } else {
+      ALOGE("Config update size failed");
+      mSignalledError = true;
+      work->result = C2_CORRUPTED;
+      work->workletsProcessed = 1u;
+      return false;
+    }
+  }
+
+  // TODO(vigneshv): Add support for monochrome videos since AV1 supports it.
+  CHECK(buffer->image_format == libgav1::kImageFormatYuv420);
+
+  std::shared_ptr<C2GraphicBlock> block;
+  uint32_t format = HAL_PIXEL_FORMAT_YV12;
+  if (buffer->bitdepth == 10) {
+    IntfImpl::Lock lock = mIntf->lock();
+    std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects =
+        mIntf->getDefaultColorAspects_l();
+
+    if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
+        defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
+        defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
+      format = HAL_PIXEL_FORMAT_RGBA_1010102;
+    }
+  }
+  C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+
+  c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format,
+                                            usage, &block);
+
+  if (err != C2_OK) {
+    ALOGE("fetchGraphicBlock for Output failed with status %d", err);
+    work->result = err;
+    return false;
+  }
+
+  C2GraphicView wView = block->map().get();
+
+  if (wView.error()) {
+    ALOGE("graphic view map failed %d", wView.error());
+    work->result = C2_CORRUPTED;
+    return false;
+  }
+
+  ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d", block->width(),
+        block->height(), mWidth, mHeight, (int)buffer->user_private_data);
+
+  uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
+  size_t srcYStride = buffer->stride[0];
+  size_t srcUStride = buffer->stride[1];
+  size_t srcVStride = buffer->stride[2];
+
+  if (buffer->bitdepth == 10) {
+    const uint16_t *srcY = (const uint16_t *)buffer->plane[0];
+    const uint16_t *srcU = (const uint16_t *)buffer->plane[1];
+    const uint16_t *srcV = (const uint16_t *)buffer->plane[2];
+
+    if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
+      convertYUV420Planar16ToY410(
+          (uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
+          srcVStride / 2, align(mWidth, 16), mWidth, mHeight);
+    } else {
+      convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2,
+                                          srcUStride / 2, srcVStride / 2,
+                                          align(mWidth, 16), mWidth, mHeight);
+    }
+  } else {
+    const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
+    const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
+    const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
+    copyOutputBufferToYV12Frame(dst, srcY, srcU, srcV, srcYStride, srcUStride,
+                                srcVStride, mWidth, mHeight);
+  }
+  finishWork(buffer->user_private_data, work, std::move(block));
+  block = nullptr;
+  return true;
+}
+
+c2_status_t C2SoftGav1Dec::drainInternal(
+    uint32_t drainMode, const std::shared_ptr<C2BlockPool> &pool,
+    const std::unique_ptr<C2Work> &work) {
+  if (drainMode == NO_DRAIN) {
+    ALOGW("drain with NO_DRAIN: no-op");
+    return C2_OK;
+  }
+  if (drainMode == DRAIN_CHAIN) {
+    ALOGW("DRAIN_CHAIN not supported");
+    return C2_OMITTED;
+  }
+
+  Libgav1StatusCode status =
+      mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
+                              /*user_private_data=*/0);
+  if (status != kLibgav1StatusOk) {
+    ALOGE("Failed to flush av1 decoder. status: %d.", status);
+    return C2_CORRUPTED;
+  }
+
+  while (outputBuffer(pool, work)) {
+  }
+
+  if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
+      work->workletsProcessed == 0u) {
+    fillEmptyWork(work);
+  }
+
+  return C2_OK;
+}
+
+c2_status_t C2SoftGav1Dec::drain(uint32_t drainMode,
+                                 const std::shared_ptr<C2BlockPool> &pool) {
+  return drainInternal(drainMode, pool, nullptr);
+}
+
+class C2SoftGav1Factory : public C2ComponentFactory {
+ public:
+  C2SoftGav1Factory()
+      : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
+            GetCodec2PlatformComponentStore()->getParamReflector())) {}
+
+  virtual c2_status_t createComponent(
+      c2_node_id_t id, std::shared_ptr<C2Component> *const component,
+      std::function<void(C2Component *)> deleter) override {
+    *component = std::shared_ptr<C2Component>(
+        new C2SoftGav1Dec(COMPONENT_NAME, id,
+                          std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)),
+        deleter);
+    return C2_OK;
+  }
+
+  virtual c2_status_t createInterface(
+      c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
+      std::function<void(C2ComponentInterface *)> deleter) override {
+    *interface = std::shared_ptr<C2ComponentInterface>(
+        new SimpleInterface<C2SoftGav1Dec::IntfImpl>(
+            COMPONENT_NAME, id,
+            std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)),
+        deleter);
+    return C2_OK;
+  }
+
+  virtual ~C2SoftGav1Factory() override = default;
+
+ private:
+  std::shared_ptr<C2ReflectorHelper> mHelper;
+};
+
+}  // namespace android
+
+extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
+  ALOGV("in %s", __func__);
+  return new ::android::C2SoftGav1Factory();
+}
+
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
+  ALOGV("in %s", __func__);
+  delete factory;
+}
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
new file mode 100644
index 0000000..a7c08bb
--- /dev/null
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -0,0 +1,77 @@
+/*
+ * 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 ANDROID_C2_SOFT_GAV1_DEC_H_
+#define ANDROID_C2_SOFT_GAV1_DEC_H_
+
+#include <SimpleC2Component.h>
+#include "libgav1/src/decoder.h"
+#include "libgav1/src/decoder_settings.h"
+
+#define GETTIME(a, b) gettimeofday(a, b);
+#define TIME_DIFF(start, end, diff)     \
+    diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
+            ((end).tv_usec - (start).tv_usec);
+
+namespace android {
+
+struct C2SoftGav1Dec : public SimpleC2Component {
+  class IntfImpl;
+
+  C2SoftGav1Dec(const char* name, c2_node_id_t id,
+                const std::shared_ptr<IntfImpl>& intfImpl);
+  ~C2SoftGav1Dec();
+
+  // Begin SimpleC2Component overrides.
+  c2_status_t onInit() override;
+  c2_status_t onStop() override;
+  void onReset() override;
+  void onRelease() override;
+  c2_status_t onFlush_sm() override;
+  void process(const std::unique_ptr<C2Work>& work,
+               const std::shared_ptr<C2BlockPool>& pool) override;
+  c2_status_t drain(uint32_t drainMode,
+                    const std::shared_ptr<C2BlockPool>& pool) override;
+  // End SimpleC2Component overrides.
+
+ private:
+  std::shared_ptr<IntfImpl> mIntf;
+  std::unique_ptr<libgav1::Decoder> mCodecCtx;
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+  bool mSignalledOutputEos;
+  bool mSignalledError;
+
+  struct timeval mTimeStart;  // Time at the start of decode()
+  struct timeval mTimeEnd;    // Time at the end of decode()
+
+  bool initDecoder();
+  void destroyDecoder();
+  void finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
+                  const std::shared_ptr<C2GraphicBlock>& block);
+  bool outputBuffer(const std::shared_ptr<C2BlockPool>& pool,
+                    const std::unique_ptr<C2Work>& work);
+  c2_status_t drainInternal(uint32_t drainMode,
+                            const std::shared_ptr<C2BlockPool>& pool,
+                            const std::unique_ptr<C2Work>& work);
+
+  C2_DO_NOT_COPY(C2SoftGav1Dec);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2_SOFT_GAV1_DEC_H_
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 7232572..df677c2 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -33,7 +33,8 @@
 namespace {
 
 constexpr char COMPONENT_NAME[] = "c2.android.hevc.decoder";
-
+constexpr uint32_t kDefaultOutputDelay = 8;
+constexpr uint32_t kMaxOutputDelay = 16;
 }  // namespace
 
 class C2SoftHevcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -54,7 +55,9 @@
         // TODO: Proper support for reorder depth.
         addParameter(
                 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
-                .withConstValue(new C2PortActualDelayTuning::output(8u))
+                .withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay))
+                .withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)})
+                .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
                 .build());
 
         addParameter(
@@ -327,6 +330,7 @@
         mDecHandle(nullptr),
         mOutBufferFlush(nullptr),
         mIvColorformat(IV_YUV_420P),
+        mOutputDelay(kDefaultOutputDelay),
         mWidth(320),
         mHeight(240),
         mHeaderDecoded(false),
@@ -877,6 +881,26 @@
             work->result = C2_CORRUPTED;
             return;
         }
+        if (s_decode_op.i4_reorder_depth >= 0 && mOutputDelay != s_decode_op.i4_reorder_depth) {
+            mOutputDelay = s_decode_op.i4_reorder_depth;
+            ALOGV("New Output delay %d ", mOutputDelay);
+
+            C2PortActualDelayTuning::output outputDelay(mOutputDelay);
+            std::vector<std::unique_ptr<C2SettingResult>> failures;
+            c2_status_t err =
+                mIntf->config({&outputDelay}, C2_MAY_BLOCK, &failures);
+            if (err == OK) {
+                work->worklets.front()->output.configUpdate.push_back(
+                    C2Param::Copy(outputDelay));
+            } else {
+                ALOGE("Cannot set output delay");
+                mSignalledError = true;
+                work->workletsProcessed = 1u;
+                work->result = C2_CORRUPTED;
+                return;
+            }
+            continue;
+        }
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
             if (mHeaderDecoded == false) {
                 mHeaderDecoded = true;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.h b/media/codec2/components/hevc/C2SoftHevcDec.h
index b7664e6..ce63a6c 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.h
+++ b/media/codec2/components/hevc/C2SoftHevcDec.h
@@ -115,7 +115,7 @@
 
     size_t mNumCores;
     IV_COLOR_FORMAT_T mIvColorformat;
-
+    uint32_t mOutputDelay;
     uint32_t mWidth;
     uint32_t mHeight;
     uint32_t mStride;
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index 9db85d5..bdff29a 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -24,7 +24,7 @@
         "libgui",
         "libhidlbase",
         "liblog",
-        "libstagefright_bufferpool@2.0",
+        "libstagefright_bufferpool@2.0.1",
         "libui",
         "libutils",
     ],
@@ -37,7 +37,7 @@
         "android.hardware.media.c2@1.0",
         "libcodec2",
         "libgui",
-        "libstagefright_bufferpool@2.0",
+        "libstagefright_bufferpool@2.0.1",
         "libui",
     ],
 }
@@ -81,7 +81,7 @@
         "libcutils",
         "libhidlbase",
         "liblog",
-        "libstagefright_bufferpool@2.0",
+        "libstagefright_bufferpool@2.0.1",
         "libstagefright_bufferqueue_helper",
         "libui",
         "libutils",
@@ -96,7 +96,7 @@
         "libcodec2",
         "libcodec2_vndk",
         "libhidlbase",
-        "libstagefright_bufferpool@2.0",
+        "libstagefright_bufferpool@2.0.1",
         "libui",
     ],
 }
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index 07dbf67..04fa59c 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -1434,6 +1434,11 @@
                 d->type = C2BaseBlock::GRAPHIC;
                 return true;
             }
+            if (cHandle) {
+                // Though we got cloned handle, creating block failed.
+                native_handle_close(cHandle);
+                native_handle_delete(cHandle);
+            }
 
             LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
             return false;
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 6469735..a8a552c 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -547,6 +547,10 @@
     if (mCompName == raw) {
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
+    } else if (mCompName == g711alaw || mCompName == g711mlaw) {
+        // g711 test data is all 1-channel and has no embedded config info.
+        bitStreamInfo[0] = 8000;
+        bitStreamInfo[1] = 1;
     } else {
         ASSERT_NO_FATAL_FAILURE(
             getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
diff --git a/media/codec2/hidl/1.0/vts/functional/common/README.md b/media/codec2/hidl/1.0/vts/functional/common/README.md
index 50e8356..f2f579c 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/README.md
+++ b/media/codec2/hidl/1.0/vts/functional/common/README.md
@@ -1,31 +1,36 @@
-## Codec2 VTS Hal @ 1.0 tests ##
----
-#### master :
+# Codec2 VTS Hal @ 1.0 tests #
+
+## master :
 Functionality of master is to enumerate all the Codec2 components available in C2 media service.
 
-usage: VtsHalMediaC2V1\_0TargetMasterTest -I default
+usage: `VtsHalMediaC2V1_0TargetMasterTest -I default`
 
-#### component :
+## component :
 Functionality of component test is to validate common functionality across all the Codec2 components available in C2 media service. For a standard C2 component, these tests are expected to pass.
 
-usage: VtsHalMediaC2V1\_0TargetComponentTest -I software -C <comp name>
-example: VtsHalMediaC2V1\_0TargetComponentTest -I software -C c2.android.vorbis.decoder
+usage: `VtsHalMediaC2V1_0TargetComponentTest -I software -C <comp name>`
 
-#### audio :
-Functionality of audio test is to validate audio specific functionality Codec2 components. The resource files for this test are taken from media/codec2/hidl/1.0/vts/functional/res. The path to these files on the device is required to be given for bitstream tests.
+example: `VtsHalMediaC2V1_0TargetComponentTest -I software -C c2.android.vorbis.decoder`
 
-usage: VtsHalMediaC2V1\_0TargetAudioDecTest -I default -C <comp name> -P /sdcard/media/
-usage: VtsHalMediaC2V1\_0TargetAudioEncTest -I software -C <comp name> -P /sdcard/media/
+## audio :
+Functionality of audio test is to validate audio specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
 
-example: VtsHalMediaC2V1\_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /sdcard/media/
-example: VtsHalMediaC2V1\_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /sdcard/media/
+usage: `VtsHalMediaC2V1_0TargetAudioDecTest -I default -C <comp name> -P <path to resource files>`
 
-#### video :
-Functionality of video test is to validate video specific functionality Codec2 components. The resource files for this test are taken from media/codec2/hidl/1.0/vts/functional/res. The path to these files on the device is required to be given for bitstream tests.
+usage: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C <comp name> -P <path to resource files>`
 
-usage: VtsHalMediaC2V1\_0TargetVideoDecTest -I default -C <comp name> -P /sdcard/media/
-usage: VtsHalMediaC2V1\_0TargetVideoEncTest -I software -C <comp name> -P /sdcard/media/
+example: `VtsHalMediaC2V1_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /data/local/tmp/media/`
 
-example: VtsHalMediaC2V1\_0TargetVideoDecTest -I software -C c2.android.avc.decoder -P /sdcard/media/
-example: VtsHalMediaC2V1\_0TargetVideoEncTest -I software -C c2.android.vp9.encoder -P /sdcard/media/
+example: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /data/local/tmp/media/`
+
+## video :
+Functionality of video test is to validate video specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
+
+usage: `VtsHalMediaC2V1_0TargetVideoDecTest -I default -C <comp name> -P <path to resource files>`
+
+usage: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C <comp name> -P <path to resource files>`
+
+example: `VtsHalMediaC2V1_0TargetVideoDecTest -I software -C c2.android.avc.decoder -P /data/local/tmp/media/`
+
+example: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C c2.android.vp9.encoder -P /data/local/tmp/media/`
 
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index c577dac..db59e54 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -118,7 +118,7 @@
         registerTestService<IComponentStore>();
     }
 
-    ComponentTestEnvironment() : res("/sdcard/media/") {}
+    ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
 
     void setComponent(const char* _component) { component = _component; }
 
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index 672369c..89c1c4a 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -18,7 +18,7 @@
         "libgui",
         "libhidlbase",
         "liblog",
-        "libstagefright_bufferpool@2.0",
+        "libstagefright_bufferpool@2.0.1",
         "libui",
         "libutils",
     ],
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 5ed54f1..c620bad 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -883,66 +883,72 @@
         Codec2Client::CreateComponentByName(
         const char* componentName,
         const std::shared_ptr<Listener>& listener,
-        std::shared_ptr<Codec2Client>* owner) {
-    std::shared_ptr<Component> component;
-    c2_status_t status = ForAllServices(
-            componentName,
-            [owner, &component, componentName, &listener](
-                    const std::shared_ptr<Codec2Client> &client)
-                        -> c2_status_t {
-                c2_status_t status = client->createComponent(componentName,
-                                                             listener,
-                                                             &component);
-                if (status == C2_OK) {
-                    if (owner) {
-                        *owner = client;
+        std::shared_ptr<Codec2Client>* owner,
+        size_t numberOfAttempts) {
+    while (true) {
+        std::shared_ptr<Component> component;
+        c2_status_t status = ForAllServices(
+                componentName,
+                [owner, &component, componentName, &listener](
+                        const std::shared_ptr<Codec2Client> &client)
+                            -> c2_status_t {
+                    c2_status_t status = client->createComponent(componentName,
+                                                                 listener,
+                                                                 &component);
+                    if (status == C2_OK) {
+                        if (owner) {
+                            *owner = client;
+                        }
+                    } else if (status != C2_NOT_FOUND) {
+                        LOG(DEBUG) << "IComponentStore("
+                                       << client->getServiceName()
+                                   << ")::createComponent(\"" << componentName
+                                   << "\") returned status = "
+                                   << status << ".";
                     }
-                } else if (status != C2_NOT_FOUND) {
-                    LOG(DEBUG) << "IComponentStore("
-                                   << client->getServiceName()
-                               << ")::createComponent(\"" << componentName
-                               << "\") returned status = "
-                               << status << ".";
-                }
-                return status;
-            });
-    if (status != C2_OK) {
-        LOG(DEBUG) << "Could not create component \"" << componentName << "\". "
-                      "Status = " << status << ".";
+                    return status;
+                });
+        if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
+            --numberOfAttempts;
+            continue;
+        }
+        return component;
     }
-    return component;
 }
 
 std::shared_ptr<Codec2Client::Interface>
         Codec2Client::CreateInterfaceByName(
         const char* interfaceName,
-        std::shared_ptr<Codec2Client>* owner) {
-    std::shared_ptr<Interface> interface;
-    c2_status_t status = ForAllServices(
-            interfaceName,
-            [owner, &interface, interfaceName](
-                    const std::shared_ptr<Codec2Client> &client)
-                        -> c2_status_t {
-                c2_status_t status = client->createInterface(interfaceName,
-                                                             &interface);
-                if (status == C2_OK) {
-                    if (owner) {
-                        *owner = client;
+        std::shared_ptr<Codec2Client>* owner,
+        size_t numberOfAttempts) {
+    while (true) {
+        std::shared_ptr<Interface> interface;
+        c2_status_t status = ForAllServices(
+                interfaceName,
+                [owner, &interface, interfaceName](
+                        const std::shared_ptr<Codec2Client> &client)
+                            -> c2_status_t {
+                    c2_status_t status = client->createInterface(interfaceName,
+                                                                 &interface);
+                    if (status == C2_OK) {
+                        if (owner) {
+                            *owner = client;
+                        }
+                    } else if (status != C2_NOT_FOUND) {
+                        LOG(DEBUG) << "IComponentStore("
+                                       << client->getServiceName()
+                                   << ")::createInterface(\"" << interfaceName
+                                   << "\") returned status = "
+                                   << status << ".";
                     }
-                } else if (status != C2_NOT_FOUND) {
-                    LOG(DEBUG) << "IComponentStore("
-                                   << client->getServiceName()
-                               << ")::createInterface(\"" << interfaceName
-                               << "\") returned status = "
-                               << status << ".";
-                }
-                return status;
-            });
-    if (status != C2_OK) {
-        LOG(DEBUG) << "Could not create interface \"" << interfaceName << "\". "
-                      "Status = " << status << ".";
+                    return status;
+                });
+        if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
+            --numberOfAttempts;
+            continue;
+        }
+        return interface;
     }
-    return interface;
 }
 
 std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index b8a7fb5..848901d 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -179,17 +179,21 @@
     static std::vector<std::shared_ptr<Codec2Client>> CreateFromAllServices();
 
     // Try to create a component with a given name from all known
-    // IComponentStore services.
+    // IComponentStore services. numberOfAttempts determines the number of times
+    // to retry the HIDL call if the transaction fails.
     static std::shared_ptr<Component> CreateComponentByName(
             char const* componentName,
             std::shared_ptr<Listener> const& listener,
-            std::shared_ptr<Codec2Client>* owner = nullptr);
+            std::shared_ptr<Codec2Client>* owner = nullptr,
+            size_t numberOfAttempts = 10);
 
     // Try to create a component interface with a given name from all known
-    // IComponentStore services.
+    // IComponentStore services. numberOfAttempts determines the number of times
+    // to retry the HIDL call if the transaction fails.
     static std::shared_ptr<Interface> CreateInterfaceByName(
             char const* interfaceName,
-            std::shared_ptr<Codec2Client>* owner = nullptr);
+            std::shared_ptr<Codec2Client>* owner = nullptr,
+            size_t numberOfAttempts = 10);
 
     // List traits from all known IComponentStore services.
     static std::vector<C2Component::Traits> const& ListComponents();
diff --git a/media/codec2/hidl/services/vendor.cpp b/media/codec2/hidl/services/vendor.cpp
index ef2f98e..a4e079d 100644
--- a/media/codec2/hidl/services/vendor.cpp
+++ b/media/codec2/hidl/services/vendor.cpp
@@ -22,7 +22,9 @@
 #include <binder/ProcessState.h>
 #include <minijail.h>
 
+#include <util/C2InterfaceHelper.h>
 #include <C2Component.h>
+#include <C2Config.h>
 
 // OmxStore is added for visibility by dumpstate.
 #include <media/stagefright/omx/1.0/OmxStore.h>
@@ -35,11 +37,14 @@
 static constexpr char kExtSeccompPolicyPath[] =
         "/vendor/etc/seccomp_policy/codec2.vendor.ext.policy";
 
-class DummyC2Store : public C2ComponentStore {
+class StoreImpl : public C2ComponentStore {
 public:
-    DummyC2Store() = default;
+    StoreImpl()
+        : mReflectorHelper(std::make_shared<C2ReflectorHelper>()),
+          mInterface(mReflectorHelper) {
+    }
 
-    virtual ~DummyC2Store() override = default;
+    virtual ~StoreImpl() override = default;
 
     virtual C2String getName() const override {
         return "default";
@@ -69,31 +74,69 @@
     }
 
     virtual c2_status_t query_sm(
-        const std::vector<C2Param*>& /* stackParams */,
-        const std::vector<C2Param::Index>& /* heapParamIndices */,
-        std::vector<std::unique_ptr<C2Param>>* const /* heapParams */) const override {
-        return C2_OMITTED;
+        const std::vector<C2Param*>& stackParams,
+        const std::vector<C2Param::Index>& heapParamIndices,
+        std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
+        return mInterface.query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
     }
 
     virtual c2_status_t config_sm(
-            const std::vector<C2Param*>& /* params */,
-            std::vector<std::unique_ptr<C2SettingResult>>* const /* failures */) override {
-        return C2_OMITTED;
+            const std::vector<C2Param*>& params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
+        return mInterface.config(params, C2_MAY_BLOCK, failures);
     }
 
     virtual std::shared_ptr<C2ParamReflector> getParamReflector() const override {
-        return nullptr;
+        return mReflectorHelper;
     }
 
     virtual c2_status_t querySupportedParams_nb(
-            std::vector<std::shared_ptr<C2ParamDescriptor>>* const /* params */) const override {
-        return C2_OMITTED;
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
+        return mInterface.querySupportedParams(params);
     }
 
     virtual c2_status_t querySupportedValues_sm(
-            std::vector<C2FieldSupportedValuesQuery>& /* fields */) const override {
-        return C2_OMITTED;
+            std::vector<C2FieldSupportedValuesQuery>& fields) const override {
+        return mInterface.querySupportedValues(fields, C2_MAY_BLOCK);
     }
+
+private:
+    class Interface : public C2InterfaceHelper {
+    public:
+        Interface(const std::shared_ptr<C2ReflectorHelper> &helper)
+            : C2InterfaceHelper(helper) {
+            setDerivedInstance(this);
+
+            addParameter(
+                DefineParam(mIonUsageInfo, "ion-usage")
+                .withDefault(new C2StoreIonUsageInfo())
+                .withFields({
+                    C2F(mIonUsageInfo, usage).flags(
+                            {C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE}),
+                    C2F(mIonUsageInfo, capacity).inRange(0, UINT32_MAX, 1024),
+                    C2F(mIonUsageInfo, heapMask).any(),
+                    C2F(mIonUsageInfo, allocFlags).flags({}),
+                    C2F(mIonUsageInfo, minAlignment).equalTo(0)
+                })
+                .withSetter(SetIonUsage)
+                .build());
+        }
+
+        virtual ~Interface() = default;
+
+    private:
+        static C2R SetIonUsage(bool /* mayBlock */, C2P<C2StoreIonUsageInfo> &me) {
+            // Vendor's TODO: put appropriate mapping logic
+            me.set().heapMask = ~0;
+            me.set().allocFlags = 0;
+            me.set().minAlignment = 0;
+            return C2R::Ok();
+        }
+
+        std::shared_ptr<C2StoreIonUsageInfo> mIonUsageInfo;
+    };
+    std::shared_ptr<C2ReflectorHelper> mReflectorHelper;
+    Interface mInterface;
 };
 
 int main(int /* argc */, char** /* argv */) {
@@ -120,7 +163,7 @@
         //         /* implementation of C2ComponentStore */);
         ALOGD("Instantiating Codec2's dummy IComponentStore service...");
         store = new utils::ComponentStore(
-                std::make_shared<DummyC2Store>());
+                std::make_shared<StoreImpl>());
 
         if (store == nullptr) {
             ALOGE("Cannot create Codec2's IComponentStore service.");
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 8223273..4a31953 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -814,9 +814,17 @@
             }
 
             {
-                double value;
-                if (msg->findDouble("time-lapse-fps", &value)) {
-                    config->mISConfig->mCaptureFps = value;
+                bool captureFpsFound = false;
+                double timeLapseFps;
+                float captureRate;
+                if (msg->findDouble("time-lapse-fps", &timeLapseFps)) {
+                    config->mISConfig->mCaptureFps = timeLapseFps;
+                    captureFpsFound = true;
+                } else if (msg->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {
+                    config->mISConfig->mCaptureFps = captureRate;
+                    captureFpsFound = true;
+                }
+                if (captureFpsFound) {
                     (void)msg->findAsFloat(KEY_FRAME_RATE, &config->mISConfig->mCodedFps);
                 }
             }
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 0cbf62b..2efb987 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -224,7 +224,7 @@
       mFirstValidFrameIndex(0u),
       mMetaMode(MODE_NONE),
       mInputMetEos(false) {
-    mOutputSurface.lock()->maxDequeueBuffers = 2 * kSmoothnessFactor + kRenderingDepth;
+    mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth;
     {
         Mutexed<Input>::Locked input(mInput);
         input->buffers.reset(new DummyInputBuffers(""));
@@ -948,8 +948,11 @@
         uint32_t outputGeneration;
         {
             Mutexed<OutputSurface>::Locked output(mOutputSurface);
-            output->maxDequeueBuffers = numOutputSlots + numInputSlots +
+            output->maxDequeueBuffers = numOutputSlots +
                     reorderDepth.value + kRenderingDepth;
+            if (!secure) {
+                output->maxDequeueBuffers += numInputSlots;
+            }
             outputSurface = output->surface ?
                     output->surface->getIGraphicBufferProducer() : nullptr;
             if (outputSurface) {
@@ -1329,14 +1332,18 @@
             case C2PortReorderBufferDepthTuning::CORE_INDEX: {
                 C2PortReorderBufferDepthTuning::output reorderDepth;
                 if (reorderDepth.updateFrom(*param)) {
+                    bool secure = mComponent->getName().find(".secure") != std::string::npos;
                     mReorderStash.lock()->setDepth(reorderDepth.value);
                     ALOGV("[%s] onWorkDone: updated reorder depth to %u",
                           mName, reorderDepth.value);
                     size_t numOutputSlots = mOutput.lock()->numSlots;
                     size_t numInputSlots = mInput.lock()->numSlots;
                     Mutexed<OutputSurface>::Locked output(mOutputSurface);
-                    output->maxDequeueBuffers = numOutputSlots + numInputSlots +
+                    output->maxDequeueBuffers = numOutputSlots +
                             reorderDepth.value + kRenderingDepth;
+                    if (!secure) {
+                        output->maxDequeueBuffers += numInputSlots;
+                    }
                     if (output->surface) {
                         output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
                     }
@@ -1380,6 +1387,7 @@
                     if (outputDelay.updateFrom(*param)) {
                         ALOGV("[%s] onWorkDone: updating output delay %u",
                               mName, outputDelay.value);
+                        bool secure = mComponent->getName().find(".secure") != std::string::npos;
                         (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
 
                         bool outputBuffersChanged = false;
@@ -1409,8 +1417,10 @@
 
                         uint32_t depth = mReorderStash.lock()->depth();
                         Mutexed<OutputSurface>::Locked output(mOutputSurface);
-                        output->maxDequeueBuffers = numOutputSlots + numInputSlots +
-                                depth + kRenderingDepth;
+                        output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
+                        if (!secure) {
+                            output->maxDequeueBuffers += numInputSlots;
+                        }
                         if (output->surface) {
                             output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
                         }
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index b6ddfab..52cc7ad 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -66,7 +66,7 @@
         "liblog",
         "libnativewindow",
         "libstagefright_foundation",
-        "libstagefright_bufferpool@2.0",
+        "libstagefright_bufferpool@2.0.1",
         "libui",
         "libutils",
     ],
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 710b536..2d99b53 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -413,17 +413,14 @@
 
     std::shared_ptr<C2LinearAllocation> alloc;
     if (C2AllocatorIon::isValid(cHandle)) {
-        native_handle_t *handle = native_handle_clone(cHandle);
-        if (handle) {
-            c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
-            const std::shared_ptr<C2PooledBlockPoolData> poolData =
-                    std::make_shared<C2PooledBlockPoolData>(data);
-            if (err == C2_OK && poolData) {
-                // TODO: config params?
-                std::shared_ptr<C2LinearBlock> block =
-                        _C2BlockFactory::CreateLinearBlock(alloc, poolData);
-                return block;
-            }
+        c2_status_t err = sAllocator->priorLinearAllocation(cHandle, &alloc);
+        const std::shared_ptr<C2PooledBlockPoolData> poolData =
+                std::make_shared<C2PooledBlockPoolData>(data);
+        if (err == C2_OK && poolData) {
+            // TODO: config params?
+            std::shared_ptr<C2LinearBlock> block =
+                    _C2BlockFactory::CreateLinearBlock(alloc, poolData);
+            return block;
         }
     }
     return nullptr;
@@ -674,17 +671,14 @@
         ResultStatus status = mBufferPoolManager->allocate(
                 mConnectionId, params, &cHandle, &bufferPoolData);
         if (status == ResultStatus::OK) {
-            native_handle_t *handle = native_handle_clone(cHandle);
-            if (handle) {
-                std::shared_ptr<C2LinearAllocation> alloc;
-                std::shared_ptr<C2PooledBlockPoolData> poolData =
-                        std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
-                c2_status_t err = mAllocator->priorLinearAllocation(handle, &alloc);
-                if (err == C2_OK && poolData && alloc) {
-                    *block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
-                    if (*block) {
-                        return C2_OK;
-                    }
+            std::shared_ptr<C2LinearAllocation> alloc;
+            std::shared_ptr<C2PooledBlockPoolData> poolData =
+                    std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
+            c2_status_t err = mAllocator->priorLinearAllocation(cHandle, &alloc);
+            if (err == C2_OK && poolData && alloc) {
+                *block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
+                if (*block) {
+                    return C2_OK;
                 }
             }
             return C2_NO_MEMORY;
@@ -710,19 +704,16 @@
         ResultStatus status = mBufferPoolManager->allocate(
                 mConnectionId, params, &cHandle, &bufferPoolData);
         if (status == ResultStatus::OK) {
-            native_handle_t *handle = native_handle_clone(cHandle);
-            if (handle) {
-                std::shared_ptr<C2GraphicAllocation> alloc;
-                std::shared_ptr<C2PooledBlockPoolData> poolData =
-                    std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
-                c2_status_t err = mAllocator->priorGraphicAllocation(
-                        handle, &alloc);
-                if (err == C2_OK && poolData && alloc) {
-                    *block = _C2BlockFactory::CreateGraphicBlock(
-                            alloc, poolData, C2Rect(width, height));
-                    if (*block) {
-                        return C2_OK;
-                    }
+            std::shared_ptr<C2GraphicAllocation> alloc;
+            std::shared_ptr<C2PooledBlockPoolData> poolData =
+                std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
+            c2_status_t err = mAllocator->priorGraphicAllocation(
+                    cHandle, &alloc);
+            if (err == C2_OK && poolData && alloc) {
+                *block = _C2BlockFactory::CreateGraphicBlock(
+                        alloc, poolData, C2Rect(width, height));
+                if (*block) {
+                    return C2_OK;
                 }
             }
             return C2_NO_MEMORY;
@@ -1117,17 +1108,14 @@
 
     std::shared_ptr<C2GraphicAllocation> alloc;
     if (C2AllocatorGralloc::isValid(cHandle)) {
-        native_handle_t *handle = native_handle_clone(cHandle);
-        if (handle) {
-            c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
-            const std::shared_ptr<C2PooledBlockPoolData> poolData =
-                    std::make_shared<C2PooledBlockPoolData>(data);
-            if (err == C2_OK && poolData) {
-                // TODO: config setup?
-                std::shared_ptr<C2GraphicBlock> block =
-                        _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
-                return block;
-            }
+        c2_status_t err = sAllocator->priorGraphicAllocation(cHandle, &alloc);
+        const std::shared_ptr<C2PooledBlockPoolData> poolData =
+                std::make_shared<C2PooledBlockPoolData>(data);
+        if (err == C2_OK && poolData) {
+            // TODO: config setup?
+            std::shared_ptr<C2GraphicBlock> block =
+                    _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+            return block;
         }
     }
     return nullptr;
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index f8afa7c..5b2bd7b 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -848,7 +848,8 @@
     emplace("libcodec2_soft_amrnbenc.so");
     emplace("libcodec2_soft_amrwbdec.so");
     emplace("libcodec2_soft_amrwbenc.so");
-    emplace("libcodec2_soft_av1dec.so");
+    //emplace("libcodec2_soft_av1dec_aom.so"); // deprecated for the gav1 implementation
+    emplace("libcodec2_soft_av1dec_gav1.so");
     emplace("libcodec2_soft_avcdec.so");
     emplace("libcodec2_soft_avcenc.so");
     emplace("libcodec2_soft_flacdec.so");
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 850b1d0..25246b3 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -40,6 +40,11 @@
         "libutils",
         "libbinder",
     ],
+
+    stubs: {
+        symbol_file: "libaaudio.map.txt",
+        versions: ["28"],
+    },
 }
 
 cc_library {
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 32904bb..d1812e6 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -1,7 +1,15 @@
 cc_library_headers {
     name: "libaudioclient_headers",
     vendor_available: true,
-    export_include_dirs: ["include"],
+    header_libs: [
+        "libaudiofoundation_headers",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    export_header_lib_headers: [
+        "libaudiofoundation_headers",
+    ],
 }
 
 cc_library_shared {
@@ -13,6 +21,7 @@
         "AudioVolumeGroup.cpp",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "libaudioutils",
         "libbinder",
         "libcutils",
@@ -63,6 +72,7 @@
         "TrackPlayerBase.cpp",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "libaudioutils",
         "libaudiopolicy",
         "libaudiomanager",
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 3cdf095..06fc23c 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -22,22 +22,6 @@
 namespace android {
 
 //
-//  AudioDeviceTypeAddr implementation
-//
-status_t AudioDeviceTypeAddr::readFromParcel(Parcel *parcel) {
-    mType = (audio_devices_t) parcel->readInt32();
-    mAddress = parcel->readString8();
-    return NO_ERROR;
-}
-
-status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
-    parcel->writeInt32((int32_t) mType);
-    parcel->writeString8(mAddress);
-    return NO_ERROR;
-}
-
-
-//
 //  AudioMixMatchCriterion implementation
 //
 AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 02dc516..cb9c7ba 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1392,6 +1392,12 @@
     return af->getMicrophones(microphones);
 }
 
+status_t AudioSystem::setAudioHalPids(const std::vector<pid_t>& pids) {
+  const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+  if (af == nullptr) return PERMISSION_DENIED;
+  return af->setAudioHalPids(pids);
+}
+
 status_t AudioSystem::getSurroundFormats(unsigned int *numSurroundFormats,
                                          audio_format_t *surroundFormats,
                                          bool *surroundFormatsEnabled,
@@ -1519,6 +1525,35 @@
     return aps->setRttEnabled(enabled);
 }
 
+status_t AudioSystem::setPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                    const AudioDeviceTypeAddr &device)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) {
+        return PERMISSION_DENIED;
+    }
+    return aps->setPreferredDeviceForStrategy(strategy, device);
+}
+
+status_t AudioSystem::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) {
+        return PERMISSION_DENIED;
+    }
+    return aps->removePreferredDeviceForStrategy(strategy);
+}
+
+status_t AudioSystem::getPreferredDeviceForStrategy(product_strategy_t strategy,
+        AudioDeviceTypeAddr &device)
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) {
+        return PERMISSION_DENIED;
+    }
+    return aps->getPreferredDeviceForStrategy(strategy, device);
+}
+
 // ---------------------------------------------------------------------------
 
 int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index e3e64af..90783eb 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -90,10 +90,12 @@
     SET_MASTER_BALANCE,
     GET_MASTER_BALANCE,
     SET_EFFECT_SUSPENDED,
+    SET_AUDIO_HAL_PIDS
 };
 
 #define MAX_ITEMS_PER_LIST 1024
 
+
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
 {
 public:
@@ -392,20 +394,18 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags)
     {
-        if (output == NULL || config == NULL || devices == NULL || latencyMs == NULL) {
+        if (output == nullptr || config == nullptr || device == nullptr || latencyMs == nullptr) {
             return BAD_VALUE;
         }
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(module);
         data.write(config, sizeof(audio_config_t));
-        data.writeInt32(*devices);
-        data.writeString8(address);
+        data.writeParcelable(*device);
         data.writeInt32((int32_t) flags);
         status_t status = remote()->transact(OPEN_OUTPUT, data, &reply);
         if (status != NO_ERROR) {
@@ -420,7 +420,6 @@
         *output = (audio_io_handle_t)reply.readInt32();
         ALOGV("openOutput() returned output, %d", *output);
         reply.read(config, sizeof(audio_config_t));
-        *devices = (audio_devices_t)reply.readInt32();
         *latencyMs = reply.readInt32();
         return NO_ERROR;
     }
@@ -903,6 +902,20 @@
         status = reply.readParcelableVector(microphones);
         return status;
     }
+    virtual status_t setAudioHalPids(const std::vector<pid_t>& pids)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(pids.size());
+        for (auto pid : pids) {
+            data.writeInt32(pid);
+        }
+        status_t status = remote()->transact(SET_AUDIO_HAL_PIDS, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast <status_t> (reply.readInt32());
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -958,7 +971,8 @@
         case SET_MODE:
         case SET_MIC_MUTE:
         case SET_LOW_RAM_DEVICE:
-        case SYSTEM_READY: {
+        case SYSTEM_READY:
+        case SET_AUDIO_HAL_PIDS: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1200,19 +1214,21 @@
             if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
                 ALOGE("b/23905951");
             }
-            audio_devices_t devices = (audio_devices_t)data.readInt32();
-            String8 address(data.readString8());
+            sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+            status_t status = NO_ERROR;
+            if ((status = data.readParcelable(device.get())) != NO_ERROR) {
+                reply->writeInt32((int32_t)status);
+                return NO_ERROR;
+            }
             audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
             uint32_t latencyMs = 0;
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-            status_t status = openOutput(module, &output, &config,
-                                         &devices, address, &latencyMs, flags);
+            status = openOutput(module, &output, &config, device, &latencyMs, flags);
             ALOGV("OPEN_OUTPUT output, %d", output);
             reply->writeInt32((int32_t)status);
             if (status == NO_ERROR) {
                 reply->writeInt32((int32_t)output);
                 reply->write(&config, sizeof(audio_config_t));
-                reply->writeInt32(devices);
                 reply->writeInt32(latencyMs);
             }
             return NO_ERROR;
@@ -1543,6 +1559,31 @@
             }
             return NO_ERROR;
         }
+        case SET_AUDIO_HAL_PIDS: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            std::vector<pid_t> pids;
+            int32_t size;
+            status_t status = data.readInt32(&size);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            if (size < 0) {
+                return BAD_VALUE;
+            }
+            if (size > MAX_ITEMS_PER_LIST) {
+                size = MAX_ITEMS_PER_LIST;
+            }
+            for (int32_t i = 0; i < size; i++) {
+                int32_t pid;
+                status =  data.readInt32(&pid);
+                if (status != NO_ERROR) {
+                    return status;
+                }
+                pids.push_back(pid);
+            }
+            reply->writeInt32(setAudioHalPids(pids));
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 7cc95e5..0facaf8 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -104,7 +104,10 @@
     GET_VOLUME_GROUP_FOR_ATTRIBUTES,
     SET_ALLOWED_CAPTURE_POLICY,
     MOVE_EFFECTS_TO_IO,
-    SET_RTT_ENABLED
+    SET_RTT_ENABLED,
+    SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+    REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+    GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -1284,6 +1287,55 @@
         }
         return static_cast<status_t>(reply.readInt32());
     }
+
+    virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+            const AudioDeviceTypeAddr &device)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeUint32(static_cast<uint32_t>(strategy));
+        status_t status = device.writeToParcel(&data);
+        if (status != NO_ERROR) {
+            return BAD_VALUE;
+        }
+        status = remote()->transact(SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+                data, &reply);
+        if (status != NO_ERROR) {
+           return status;
+        }
+        return static_cast<status_t>(reply.readInt32());
+    }
+
+    virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeUint32(static_cast<uint32_t>(strategy));
+        status_t status = remote()->transact(REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+                data, &reply);
+        if (status != NO_ERROR) {
+           return status;
+        }
+        return static_cast<status_t>(reply.readInt32());
+    }
+
+    virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+            AudioDeviceTypeAddr &device)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeUint32(static_cast<uint32_t>(strategy));
+        status_t status = remote()->transact(GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
+                data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        status = device.readFromParcel(&reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast<status_t>(reply.readInt32());
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1346,7 +1398,10 @@
         case GET_OFFLOAD_FORMATS_A2DP:
         case LIST_AUDIO_VOLUME_GROUPS:
         case GET_VOLUME_GROUP_FOR_ATTRIBUTES:
-        case SET_RTT_ENABLED: {
+        case SET_RTT_ENABLED:
+        case SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
+        case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
+        case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -2369,6 +2424,40 @@
             return NO_ERROR;
         }
 
+        case SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            product_strategy_t strategy = (product_strategy_t) data.readUint32();
+            AudioDeviceTypeAddr device;
+            status_t status = device.readFromParcel((Parcel*)&data);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            status = setPreferredDeviceForStrategy(strategy, device);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
+        case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            product_strategy_t strategy = (product_strategy_t) data.readUint32();
+            status_t status = removePreferredDeviceForStrategy(strategy);
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
+        case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            product_strategy_t strategy = (product_strategy_t) data.readUint32();
+            AudioDeviceTypeAddr device;
+            status_t status = getPreferredDeviceForStrategy(strategy, device);
+            status_t marshall_status = device.writeToParcel(reply);
+            if (marshall_status != NO_ERROR) {
+                return marshall_status;
+            }
+            reply->writeInt32(status);
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index ef39fd1..0ab1c9d 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -18,9 +18,10 @@
 #ifndef ANDROID_AUDIO_POLICY_H
 #define ANDROID_AUDIO_POLICY_H
 
+#include <binder/Parcel.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
-#include <binder/Parcel.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
@@ -60,19 +61,6 @@
 #define MAX_MIXES_PER_POLICY 10
 #define MAX_CRITERIA_PER_MIX 20
 
-class AudioDeviceTypeAddr {
-public:
-    AudioDeviceTypeAddr() {}
-    AudioDeviceTypeAddr(audio_devices_t type, String8 address) :
-        mType(type), mAddress(address) {}
-
-    status_t readFromParcel(Parcel *parcel);
-    status_t writeToParcel(Parcel *parcel) const;
-
-    audio_devices_t mType;
-    String8 mAddress;
-};
-
 class AudioMixMatchCriterion {
 public:
     AudioMixMatchCriterion() {}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 09e80b2..a86297d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -19,6 +19,7 @@
 
 #include <sys/types.h>
 
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioPolicy.h>
 #include <media/AudioProductStrategy.h>
 #include <media/AudioVolumeGroup.h>
@@ -396,6 +397,23 @@
 
     static status_t setRttEnabled(bool enabled);
 
+     /**
+     * Send audio HAL server process pids to native audioserver process for use
+     * when generating audio HAL servers tombstones
+     */
+    static status_t setAudioHalPids(const std::vector<pid_t>& pids);
+
+    static status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+            const AudioDeviceTypeAddr &device);
+
+    static status_t removePreferredDeviceForStrategy(product_strategy_t strategy);
+
+    static status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+            AudioDeviceTypeAddr &device);
+
+    static status_t getDeviceForStrategy(product_strategy_t strategy,
+            AudioDeviceTypeAddr &device);
+
     // ----------------------------------------------------------------------------
 
     class AudioVolumeGroupCallback : public RefBase
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 8ec8931..8e8a1f5 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -27,6 +27,7 @@
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 #include <media/AudioClient.h>
+#include <media/DeviceDescriptorBase.h>
 #include <media/IAudioTrack.h>
 #include <media/IAudioFlingerClient.h>
 #include <system/audio.h>
@@ -404,8 +405,7 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags) = 0;
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
@@ -511,6 +511,8 @@
 
     /* List available microphones and their characteristics */
     virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
+
+    virtual status_t setAudioHalPids(const std::vector<pid_t>& pids) = 0;
 };
 
 
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 32275cf..9b91d6d 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -23,6 +23,7 @@
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
 #include <media/IAudioPolicyServiceClient.h>
@@ -222,6 +223,14 @@
                                                        volume_group_t &volumeGroup) = 0;
 
     virtual status_t setRttEnabled(bool enabled) = 0;
+
+    virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   const AudioDeviceTypeAddr &device) = 0;
+
+    virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0;
+
+    virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   AudioDeviceTypeAddr &device) = 0;
 };
 
 
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
new file mode 100644
index 0000000..8dcc421
--- /dev/null
+++ b/media/libaudiofoundation/Android.bp
@@ -0,0 +1,50 @@
+cc_library_headers {
+    name: "libaudiofoundation_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    header_libs: [
+        "libaudio_system_headers",
+        "libmedia_helper_headers",
+    ],
+    export_header_lib_headers: [
+        "libaudio_system_headers",
+        "libmedia_helper_headers",
+    ],
+}
+
+cc_library_shared {
+    name: "libaudiofoundation",
+    vendor_available: true,
+    double_loadable: true,
+
+    srcs: [
+        "AudioContainers.cpp",
+        "AudioDeviceTypeAddr.cpp",
+        "AudioGain.cpp",
+        "AudioPort.cpp",
+        "AudioProfile.cpp",
+        "DeviceDescriptorBase.cpp",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+    ],
+
+    header_libs: [
+        "libaudiofoundation_headers",
+    ],
+
+    export_header_lib_headers: [
+        "libaudiofoundation_headers",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
new file mode 100644
index 0000000..31257d5
--- /dev/null
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+#include <string>
+
+#include <media/AudioContainers.h>
+
+namespace android {
+
+const DeviceTypeSet& getAudioDeviceOutAllSet() {
+    static const DeviceTypeSet audioDeviceOutAllSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_ALL_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_ALL_ARRAY));
+    return audioDeviceOutAllSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet() {
+    static const DeviceTypeSet audioDeviceOutAllA2dpSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY));
+    return audioDeviceOutAllA2dpSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllScoSet() {
+    static const DeviceTypeSet audioDeviceOutAllScoSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY));
+    return audioDeviceOutAllScoSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllUsbSet() {
+    static const DeviceTypeSet audioDeviceOutAllUsbSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_ALL_USB_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_ALL_USB_ARRAY));
+    return audioDeviceOutAllUsbSet;
+}
+
+const DeviceTypeSet& getAudioDeviceInAllSet() {
+    static const DeviceTypeSet audioDeviceInAllSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_IN_ALL_ARRAY),
+            std::end(AUDIO_DEVICE_IN_ALL_ARRAY));
+    return audioDeviceInAllSet;
+}
+
+const DeviceTypeSet& getAudioDeviceInAllUsbSet() {
+    static const DeviceTypeSet audioDeviceInAllUsbSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_IN_ALL_USB_ARRAY),
+            std::end(AUDIO_DEVICE_IN_ALL_USB_ARRAY));
+    return audioDeviceInAllUsbSet;
+}
+
+bool deviceTypesToString(const DeviceTypeSet &deviceTypes, std::string &str) {
+    if (deviceTypes.empty()) {
+        str = "Empty device types";
+        return true;
+    }
+    bool ret = true;
+    for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+        std::string deviceTypeStr;
+        ret = audio_is_output_device(*it) ?
+              OutputDeviceConverter::toString(*it, deviceTypeStr) :
+              InputDeviceConverter::toString(*it, deviceTypeStr);
+        if (!ret) {
+            break;
+        }
+        str.append(deviceTypeStr);
+        if (++it != deviceTypes.end()) {
+            str.append(" , ");
+        }
+    }
+    if (!ret) {
+        str = "Unknown values";
+    }
+    return ret;
+}
+
+std::string dumpDeviceTypes(const DeviceTypeSet &deviceTypes) {
+    std::string ret;
+    for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+        std::stringstream ss;
+        ss << "0x" << std::hex << (*it);
+        ret.append(ss.str());
+        if (++it != deviceTypes.end()) {
+            ret.append(" , ");
+        }
+    }
+    return ret;
+}
+
+std::string toString(const DeviceTypeSet& deviceTypes) {
+    std::string ret;
+    deviceTypesToString(deviceTypes, ret);
+    return ret;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
new file mode 100644
index 0000000..d390467
--- /dev/null
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include <media/AudioDeviceTypeAddr.h>
+
+namespace android {
+
+const char* AudioDeviceTypeAddr::getAddress() const {
+    return mAddress.c_str();
+}
+
+bool AudioDeviceTypeAddr::equals(const AudioDeviceTypeAddr& other) const {
+    return mType == other.mType && mAddress == other.mAddress;
+}
+
+void AudioDeviceTypeAddr::reset() {
+    mType = AUDIO_DEVICE_NONE;
+    mAddress = "";
+}
+
+status_t AudioDeviceTypeAddr::readFromParcel(const Parcel *parcel) {
+    status_t status;
+    if ((status = parcel->readUint32(&mType)) != NO_ERROR) return status;
+    status = parcel->readUtf8FromUtf16(&mAddress);
+    return status;
+}
+
+status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
+    status_t status;
+    if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+    status = parcel->writeUtf8AsUtf16(mAddress);
+    return status;
+}
+
+
+DeviceTypeSet getAudioDeviceTypes(const AudioDeviceTypeAddrVector& deviceTypeAddrs) {
+    DeviceTypeSet deviceTypes;
+    for (const auto& deviceTypeAddr : deviceTypeAddrs) {
+        deviceTypes.insert(deviceTypeAddr.mType);
+    }
+    return deviceTypes;
+}
+
+}
\ No newline at end of file
diff --git a/media/libaudiofoundation/AudioGain.cpp b/media/libaudiofoundation/AudioGain.cpp
new file mode 100644
index 0000000..0d28335
--- /dev/null
+++ b/media/libaudiofoundation/AudioGain.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2015 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 "AudioGain"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <algorithm>
+
+#include <android-base/stringprintf.h>
+#include <media/AudioGain.h>
+#include <utils/Log.h>
+
+#include <math.h>
+
+namespace android {
+
+AudioGain::AudioGain(int index, bool useInChannelMask)
+{
+    mIndex = index;
+    mUseInChannelMask = useInChannelMask;
+    memset(&mGain, 0, sizeof(struct audio_gain));
+}
+
+void AudioGain::getDefaultConfig(struct audio_gain_config *config)
+{
+    config->index = mIndex;
+    config->mode = mGain.mode;
+    config->channel_mask = mGain.channel_mask;
+    if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+        config->values[0] = mGain.default_value;
+    } else {
+        uint32_t numValues;
+        if (mUseInChannelMask) {
+            numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
+        } else {
+            numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
+        }
+        for (size_t i = 0; i < numValues; i++) {
+            config->values[i] = mGain.default_value;
+        }
+    }
+    if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+        config->ramp_duration_ms = mGain.min_ramp_ms;
+    }
+}
+
+status_t AudioGain::checkConfig(const struct audio_gain_config *config)
+{
+    if ((config->mode & ~mGain.mode) != 0) {
+        return BAD_VALUE;
+    }
+    if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+        if ((config->values[0] < mGain.min_value) ||
+                    (config->values[0] > mGain.max_value)) {
+            return BAD_VALUE;
+        }
+    } else {
+        if ((config->channel_mask & ~mGain.channel_mask) != 0) {
+            return BAD_VALUE;
+        }
+        uint32_t numValues;
+        if (mUseInChannelMask) {
+            numValues = audio_channel_count_from_in_mask(config->channel_mask);
+        } else {
+            numValues = audio_channel_count_from_out_mask(config->channel_mask);
+        }
+        for (size_t i = 0; i < numValues; i++) {
+            if ((config->values[i] < mGain.min_value) ||
+                    (config->values[i] > mGain.max_value)) {
+                return BAD_VALUE;
+            }
+        }
+    }
+    if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+        if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
+                    (config->ramp_duration_ms > mGain.max_ramp_ms)) {
+            return BAD_VALUE;
+        }
+    }
+    return NO_ERROR;
+}
+
+void AudioGain::dump(std::string *dst, int spaces, int index) const
+{
+    dst->append(base::StringPrintf("%*sGain %d:\n", spaces, "", index+1));
+    dst->append(base::StringPrintf("%*s- mode: %08x\n", spaces, "", mGain.mode));
+    dst->append(base::StringPrintf("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask));
+    dst->append(base::StringPrintf("%*s- min_value: %d mB\n", spaces, "", mGain.min_value));
+    dst->append(base::StringPrintf("%*s- max_value: %d mB\n", spaces, "", mGain.max_value));
+    dst->append(base::StringPrintf("%*s- default_value: %d mB\n", spaces, "", mGain.default_value));
+    dst->append(base::StringPrintf("%*s- step_value: %d mB\n", spaces, "", mGain.step_value));
+    dst->append(base::StringPrintf("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms));
+    dst->append(base::StringPrintf("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms));
+}
+
+bool AudioGain::equals(const sp<AudioGain>& other) const
+{
+    return other != nullptr &&
+           mUseInChannelMask == other->mUseInChannelMask &&
+           mUseForVolume == other->mUseForVolume &&
+           // Compare audio gain
+           mGain.mode == other->mGain.mode &&
+           mGain.channel_mask == other->mGain.channel_mask &&
+           mGain.min_value == other->mGain.min_value &&
+           mGain.max_value == other->mGain.max_value &&
+           mGain.default_value == other->mGain.default_value &&
+           mGain.step_value == other->mGain.step_value &&
+           mGain.min_ramp_ms == other->mGain.min_ramp_ms &&
+           mGain.max_ramp_ms == other->mGain.max_ramp_ms;
+}
+
+status_t AudioGain::writeToParcel(android::Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeInt32(mIndex)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mUseInChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mUseForVolume)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mGain.min_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mGain.max_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mGain.default_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.step_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.min_ramp_ms)) != NO_ERROR) return status;
+    status = parcel->writeUint32(mGain.max_ramp_ms);
+    return status;
+}
+
+status_t AudioGain::readFromParcel(const android::Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readInt32(&mIndex)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mUseInChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mUseForVolume)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mGain.min_value)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mGain.max_value)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mGain.default_value)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.step_value)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.min_ramp_ms)) != NO_ERROR) return status;
+    status = parcel->readUint32(&mGain.max_ramp_ms);
+    return status;
+}
+
+bool AudioGains::equals(const AudioGains &other) const
+{
+    return std::equal(begin(), end(), other.begin(), other.end(),
+                      [](const sp<AudioGain>& left, const sp<AudioGain>& right) {
+                          return left->equals(right);
+                      });
+}
+
+status_t AudioGains::writeToParcel(android::Parcel *parcel) const {
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
+    for (const auto &audioGain : *this) {
+        if ((status = parcel->writeParcelable(*audioGain)) != NO_ERROR) {
+            break;
+        }
+    }
+    return status;
+}
+
+status_t AudioGains::readFromParcel(const android::Parcel *parcel) {
+    status_t status = NO_ERROR;
+    this->clear();
+    if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+    for (size_t i = 0; i < this->size(); i++) {
+        this->at(i) = new AudioGain(0, false);
+        if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
+            this->clear();
+            break;
+        }
+    }
+    return status;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
new file mode 100644
index 0000000..f988690
--- /dev/null
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -0,0 +1,287 @@
+/*
+ * 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_TAG "AudioPort"
+
+#include <algorithm>
+
+#include <android-base/stringprintf.h>
+#include <media/AudioPort.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
+{
+    for (const auto& profileToImport : port->mProfiles) {
+        // Import only valid port, i.e. valid format, non empty rates and channels masks
+        if (!profileToImport->isValid()) {
+            continue;
+        }
+        if (std::find_if(mProfiles.begin(), mProfiles.end(),
+                [profileToImport](const auto &profile) {
+                        return *profile == *profileToImport; }) == mProfiles.end()) {
+            addAudioProfile(profileToImport);
+        }
+    }
+}
+
+void AudioPort::toAudioPort(struct audio_port *port) const {
+    // TODO: update this function once audio_port structure reflects the new profile definition.
+    // For compatibility reason: flatening the AudioProfile into audio_port structure.
+    FormatSet flatenedFormats;
+    SampleRateSet flatenedRates;
+    ChannelMaskSet flatenedChannels;
+    for (const auto& profile : mProfiles) {
+        if (profile->isValid()) {
+            audio_format_t formatToExport = profile->getFormat();
+            const SampleRateSet &ratesToExport = profile->getSampleRates();
+            const ChannelMaskSet &channelsToExport = profile->getChannels();
+
+            flatenedFormats.insert(formatToExport);
+            flatenedRates.insert(ratesToExport.begin(), ratesToExport.end());
+            flatenedChannels.insert(channelsToExport.begin(), channelsToExport.end());
+
+            if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
+                    flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
+                    flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
+                ALOGE("%s: bailing out: cannot export profiles to port config", __func__);
+                return;
+            }
+        }
+    }
+    port->role = mRole;
+    port->type = mType;
+    strlcpy(port->name, mName.c_str(), AUDIO_PORT_MAX_NAME_LEN);
+    port->num_sample_rates = flatenedRates.size();
+    port->num_channel_masks = flatenedChannels.size();
+    port->num_formats = flatenedFormats.size();
+    std::copy(flatenedRates.begin(), flatenedRates.end(), port->sample_rates);
+    std::copy(flatenedChannels.begin(), flatenedChannels.end(), port->channel_masks);
+    std::copy(flatenedFormats.begin(), flatenedFormats.end(), port->formats);
+
+    ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
+
+    port->num_gains = std::min(mGains.size(), (size_t) AUDIO_PORT_MAX_GAINS);
+    for (size_t i = 0; i < port->num_gains; i++) {
+        port->gains[i] = mGains[i]->getGain();
+    }
+}
+
+void AudioPort::dump(std::string *dst, int spaces, bool verbose) const {
+    if (!mName.empty()) {
+        dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
+    }
+    if (verbose) {
+        std::string profilesStr;
+        mProfiles.dump(&profilesStr, spaces);
+        dst->append(profilesStr);
+
+        if (mGains.size() != 0) {
+            dst->append(base::StringPrintf("%*s- gains:\n", spaces, ""));
+            for (size_t i = 0; i < mGains.size(); i++) {
+                std::string gainStr;
+                mGains[i]->dump(&gainStr, spaces + 2, i);
+                dst->append(gainStr);
+            }
+        }
+    }
+}
+
+void AudioPort::log(const char* indent) const
+{
+    ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.c_str(), mType, mRole);
+}
+
+bool AudioPort::equals(const sp<AudioPort> &other) const
+{
+    return other != nullptr &&
+           mGains.equals(other->getGains()) &&
+           mName.compare(other->getName()) == 0 &&
+           mType == other->getType() &&
+           mRole == other->getRole() &&
+           mProfiles.equals(other->getAudioProfiles());
+}
+
+status_t AudioPort::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mRole)) != NO_ERROR) return status;
+    if ((status = parcel->writeParcelable(mProfiles)) != NO_ERROR) return status;
+    if ((status = parcel->writeParcelable(mGains)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t AudioPort::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+    static_assert(sizeof(mType) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mType))) != NO_ERROR) {
+        return status;
+    }
+    static_assert(sizeof(mRole) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mRole))) != NO_ERROR) {
+        return status;
+    }
+    mProfiles.clear();
+    if ((status = parcel->readParcelable(&mProfiles)) != NO_ERROR) return status;
+    mGains.clear();
+    if ((status = parcel->readParcelable(&mGains)) != NO_ERROR) return status;
+    return status;
+}
+
+// --- AudioPortConfig class implementation
+
+status_t AudioPortConfig::applyAudioPortConfig(
+        const struct audio_port_config *config,
+        struct audio_port_config *backupConfig __unused)
+{
+    if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+        mSamplingRate = config->sample_rate;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+        mChannelMask = config->channel_mask;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+        mFormat = config->format;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+        mGain = config->gain;
+    }
+
+    return NO_ERROR;
+}
+
+namespace {
+
+template<typename T>
+void updateField(
+        const T& portConfigField, T audio_port_config::*port_config_field,
+        struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
+        unsigned int configMask, T defaultValue)
+{
+    if (dstConfig->config_mask & configMask) {
+        if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
+            dstConfig->*port_config_field = srcConfig->*port_config_field;
+        } else {
+            dstConfig->*port_config_field = portConfigField;
+        }
+    } else {
+        dstConfig->*port_config_field = defaultValue;
+    }
+}
+
+} // namespace
+
+void AudioPortConfig::toAudioPortConfig(
+        struct audio_port_config *dstConfig,
+        const struct audio_port_config *srcConfig) const
+{
+    updateField(mSamplingRate, &audio_port_config::sample_rate,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
+    updateField(mChannelMask, &audio_port_config::channel_mask,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
+            (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
+    updateField(mFormat, &audio_port_config::format,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
+    dstConfig->id = mId;
+
+    sp<AudioPort> audioport = getAudioPort();
+    if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
+        dstConfig->gain = mGain;
+        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
+                && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
+            dstConfig->gain = srcConfig->gain;
+        }
+    } else {
+        dstConfig->gain.index = -1;
+    }
+    if (dstConfig->gain.index != -1) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
+    } else {
+        dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+    }
+}
+
+bool AudioPortConfig::hasGainController(bool canUseForVolume) const
+{
+    sp<AudioPort> audioport = getAudioPort();
+    if (!audioport) {
+        return false;
+    }
+    return canUseForVolume ? audioport->getGains().canUseForVolume()
+                           : audioport->getGains().size() > 0;
+}
+
+bool AudioPortConfig::equals(const sp<AudioPortConfig> &other) const
+{
+    return other != nullptr &&
+           mSamplingRate == other->getSamplingRate() &&
+           mFormat == other->getFormat() &&
+           mChannelMask == other->getChannelMask() &&
+           // Compare audio gain config
+           mGain.index == other->mGain.index &&
+           mGain.mode == other->mGain.mode &&
+           mGain.channel_mask == other->mGain.channel_mask &&
+           std::equal(std::begin(mGain.values), std::end(mGain.values),
+                      std::begin(other->mGain.values)) &&
+           mGain.ramp_duration_ms == other->mGain.ramp_duration_ms;
+}
+
+status_t AudioPortConfig::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeUint32(mSamplingRate)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mId)) != NO_ERROR) return status;
+    // Write mGain to parcel.
+    if ((status = parcel->writeInt32(mGain.index)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.ramp_duration_ms)) != NO_ERROR) return status;
+    std::vector<int> values(std::begin(mGain.values), std::end(mGain.values));
+    if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t AudioPortConfig::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readUint32(&mSamplingRate)) != NO_ERROR) return status;
+    static_assert(sizeof(mFormat) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+        return status;
+    }
+    if ((status = parcel->readUint32(&mChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mId)) != NO_ERROR) return status;
+    // Read mGain from parcel.
+    if ((status = parcel->readInt32(&mGain.index)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.ramp_duration_ms)) != NO_ERROR) return status;
+    std::vector<int> values;
+    if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+    if (values.size() != std::size(mGain.values)) {
+        return BAD_VALUE;
+    }
+    std::copy(values.begin(), values.end(), mGain.values);
+    return status;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
new file mode 100644
index 0000000..91be346
--- /dev/null
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+#include <set>
+
+#define LOG_TAG "AudioProfile"
+//#define LOG_NDEBUG 0
+
+#include <android-base/stringprintf.h>
+#include <media/AudioContainers.h>
+#include <media/AudioProfile.h>
+#include <media/TypeConverter.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+bool operator == (const AudioProfile &left, const AudioProfile &right)
+{
+    return (left.getFormat() == right.getFormat()) &&
+            (left.getChannels() == right.getChannels()) &&
+            (left.getSampleRates() == right.getSampleRates());
+}
+
+// static
+sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
+{
+    AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
+            ChannelMaskSet(), SampleRateSet());
+    dynamicProfile->setDynamicFormat(true);
+    dynamicProfile->setDynamicChannels(true);
+    dynamicProfile->setDynamicRate(true);
+    return dynamicProfile;
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+                           audio_channel_mask_t channelMasks,
+                           uint32_t samplingRate) :
+        mName(""),
+        mFormat(format)
+{
+    mChannelMasks.insert(channelMasks);
+    mSamplingRates.insert(samplingRate);
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+                           const ChannelMaskSet &channelMasks,
+                           const SampleRateSet &samplingRateCollection) :
+        mName(""),
+        mFormat(format),
+        mChannelMasks(channelMasks),
+        mSamplingRates(samplingRateCollection) {}
+
+void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
+{
+    if (mIsDynamicChannels) {
+        mChannelMasks = channelMasks;
+    }
+}
+
+void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
+{
+    if (mIsDynamicRate) {
+        mSamplingRates = sampleRates;
+    }
+}
+
+void AudioProfile::clear()
+{
+    if (mIsDynamicChannels) {
+        mChannelMasks.clear();
+    }
+    if (mIsDynamicRate) {
+        mSamplingRates.clear();
+    }
+}
+
+void AudioProfile::dump(std::string *dst, int spaces) const
+{
+    dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+             mIsDynamicChannels ? "[dynamic channels]" : "",
+             mIsDynamicRate ? "[dynamic rates]" : ""));
+    if (mName.length() != 0) {
+        dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
+    }
+    std::string formatLiteral;
+    if (FormatConverter::toString(mFormat, formatLiteral)) {
+        dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
+    }
+    if (!mSamplingRates.empty()) {
+        dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
+        for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
+            dst->append(base::StringPrintf("%d", *it));
+            dst->append(++it == mSamplingRates.end() ? "" : ", ");
+        }
+        dst->append("\n");
+    }
+
+    if (!mChannelMasks.empty()) {
+        dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
+        for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
+            dst->append(base::StringPrintf("0x%04x", *it));
+            dst->append(++it == mChannelMasks.end() ? "" : ", ");
+        }
+        dst->append("\n");
+    }
+}
+
+bool AudioProfile::equals(const sp<AudioProfile>& other) const
+{
+    return other != nullptr &&
+           mName.compare(other->mName) == 0 &&
+           mFormat == other->getFormat() &&
+           mChannelMasks == other->getChannels() &&
+           mSamplingRates == other->getSampleRates() &&
+           mIsDynamicFormat == other->isDynamicFormat() &&
+           mIsDynamicChannels == other->isDynamicChannels() &&
+           mIsDynamicRate == other->isDynamicRate();
+}
+
+status_t AudioProfile::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+    std::vector<int> values(mChannelMasks.begin(), mChannelMasks.end());
+    if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+    values.clear();
+    values.assign(mSamplingRates.begin(), mSamplingRates.end());
+    if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mIsDynamicFormat)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mIsDynamicChannels)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mIsDynamicRate)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t AudioProfile::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+    static_assert(sizeof(mFormat) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+        return status;
+    }
+    std::vector<int> values;
+    if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+    mChannelMasks.clear();
+    mChannelMasks.insert(values.begin(), values.end());
+    values.clear();
+    if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+    mSamplingRates.clear();
+    mSamplingRates.insert(values.begin(), values.end());
+    if ((status = parcel->readBool(&mIsDynamicFormat)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mIsDynamicChannels)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mIsDynamicRate)) != NO_ERROR) return status;
+    return status;
+}
+
+ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
+{
+    ssize_t index = size();
+    push_back(profile);
+    return index;
+}
+
+void AudioProfileVector::clearProfiles()
+{
+    for (auto it = begin(); it != end();) {
+        if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
+            it = erase(it);
+        } else {
+            (*it)->clear();
+            ++it;
+        }
+    }
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
+{
+    for (const auto &profile : *this) {
+        if (profile->isValid()) {
+            return profile;
+        }
+    }
+    return nullptr;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
+{
+    for (const auto &profile : *this) {
+        if (profile->isValid() && profile->getFormat() == format) {
+            return profile;
+        }
+    }
+    return nullptr;
+}
+
+FormatVector AudioProfileVector::getSupportedFormats() const
+{
+    FormatVector supportedFormats;
+    for (const auto &profile : *this) {
+        if (profile->hasValidFormat()) {
+            supportedFormats.push_back(profile->getFormat());
+        }
+    }
+    return supportedFormats;
+}
+
+bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
+{
+    for (const auto &profile : *this) {
+        if (profile->getFormat() == format && profile->isDynamicChannels()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicFormat() const
+{
+    for (const auto &profile : *this) {
+        if (profile->isDynamicFormat()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicProfile() const
+{
+    for (const auto &profile : *this) {
+        if (profile->isDynamic()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
+{
+    for (const auto &profile : *this) {
+        if (profile->getFormat() == format && profile->isDynamicRate()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void AudioProfileVector::dump(std::string *dst, int spaces) const
+{
+    dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
+    for (size_t i = 0; i < size(); i++) {
+        dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
+        std::string profileStr;
+        at(i)->dump(&profileStr, spaces + 8);
+        dst->append(profileStr);
+    }
+}
+
+status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
+    for (const auto &audioProfile : *this) {
+        if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
+            break;
+        }
+    }
+    return status;
+}
+
+status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    this->clear();
+    if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+    for (size_t i = 0; i < this->size(); ++i) {
+        this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
+        if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
+            this->clear();
+            break;
+        }
+    }
+    return status;
+}
+
+bool AudioProfileVector::equals(const AudioProfileVector& other) const
+{
+    return std::equal(begin(), end(), other.begin(), other.end(),
+                      [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
+                          return left->equals(right);
+                      });
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/DeviceDescriptorBase.cpp b/media/libaudiofoundation/DeviceDescriptorBase.cpp
new file mode 100644
index 0000000..ef7576e
--- /dev/null
+++ b/media/libaudiofoundation/DeviceDescriptorBase.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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_TAG "DeviceDescriptorBase"
+//#define LOG_NDEBUG 0
+
+#include <android-base/stringprintf.h>
+#include <audio_utils/string.h>
+#include <media/DeviceDescriptorBase.h>
+#include <media/TypeConverter.h>
+
+namespace android {
+
+DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type) :
+        DeviceDescriptorBase(type, "")
+{
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type, const std::string& address) :
+        DeviceDescriptorBase(AudioDeviceTypeAddr(type, address))
+{
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(const AudioDeviceTypeAddr &deviceTypeAddr) :
+        AudioPort("", AUDIO_PORT_TYPE_DEVICE,
+                  audio_is_output_device(deviceTypeAddr.mType) ? AUDIO_PORT_ROLE_SINK :
+                                         AUDIO_PORT_ROLE_SOURCE),
+        mDeviceTypeAddr(deviceTypeAddr)
+{
+    if (mDeviceTypeAddr.mAddress.empty() && audio_is_remote_submix_device(mDeviceTypeAddr.mType)) {
+        mDeviceTypeAddr.mAddress = "0";
+    }
+}
+
+void DeviceDescriptorBase::toAudioPortConfig(struct audio_port_config *dstConfig,
+                                             const struct audio_port_config *srcConfig) const
+{
+    dstConfig->config_mask = AUDIO_PORT_CONFIG_GAIN;
+    if (mSamplingRate != 0) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
+    }
+    if (mChannelMask != AUDIO_CHANNEL_NONE) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
+    }
+    if (mFormat != AUDIO_FORMAT_INVALID) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
+    }
+
+    if (srcConfig != NULL) {
+        dstConfig->config_mask |= srcConfig->config_mask;
+    }
+
+    AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
+    dstConfig->role = audio_is_output_device(mDeviceTypeAddr.mType) ?
+                        AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+    dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
+    dstConfig->ext.device.type = mDeviceTypeAddr.mType;
+
+    (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mDeviceTypeAddr.getAddress());
+}
+
+void DeviceDescriptorBase::toAudioPort(struct audio_port *port) const
+{
+    ALOGV("DeviceDescriptorBase::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
+    AudioPort::toAudioPort(port);
+    toAudioPortConfig(&port->active_config);
+    port->id = mId;
+    port->ext.device.type = mDeviceTypeAddr.mType;
+    (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mDeviceTypeAddr.getAddress());
+}
+
+void DeviceDescriptorBase::dump(std::string *dst, int spaces, int index,
+                                const char* extraInfo, bool verbose) const
+{
+    dst->append(base::StringPrintf("%*sDevice %d:\n", spaces, "", index + 1));
+    if (mId != 0) {
+        dst->append(base::StringPrintf("%*s- id: %2d\n", spaces, "", mId));
+    }
+
+    if (extraInfo != nullptr) {
+        dst->append(extraInfo);
+    }
+
+    dst->append(base::StringPrintf("%*s- type: %-48s\n",
+            spaces, "", ::android::toString(mDeviceTypeAddr.mType).c_str()));
+
+    if (mDeviceTypeAddr.mAddress.size() != 0) {
+        dst->append(base::StringPrintf(
+                "%*s- address: %-32s\n", spaces, "", mDeviceTypeAddr.getAddress()));
+    }
+    AudioPort::dump(dst, spaces, verbose);
+}
+
+std::string DeviceDescriptorBase::toString() const
+{
+    std::stringstream sstream;
+    sstream << "type:0x" << std::hex << type() << ",@:" << mDeviceTypeAddr.mAddress;
+    return sstream.str();
+}
+
+void DeviceDescriptorBase::log() const
+{
+    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceTypeAddr.mType,
+          ::android::toString(mDeviceTypeAddr.mType).c_str(),
+          mDeviceTypeAddr.getAddress());
+
+    AudioPort::log("  ");
+}
+
+bool DeviceDescriptorBase::equals(const sp<DeviceDescriptorBase> &other) const
+{
+    return other != nullptr &&
+           static_cast<const AudioPort*>(this)->equals(other) &&
+           static_cast<const AudioPortConfig*>(this)->equals(other) &&
+           mDeviceTypeAddr.equals(other->mDeviceTypeAddr);
+}
+
+status_t DeviceDescriptorBase::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = AudioPort::writeToParcel(parcel)) != NO_ERROR) return status;
+    if ((status = AudioPortConfig::writeToParcel(parcel)) != NO_ERROR) return status;
+    if ((status = parcel->writeParcelable(mDeviceTypeAddr)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t DeviceDescriptorBase::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = AudioPort::readFromParcel(parcel)) != NO_ERROR) return status;
+    if ((status = AudioPortConfig::readFromParcel(parcel)) != NO_ERROR) return status;
+    if ((status = parcel->readParcelable(&mDeviceTypeAddr)) != NO_ERROR) return status;
+    return status;
+}
+
+std::string toString(const DeviceDescriptorBaseVector& devices)
+{
+    std::string ret;
+    for (const auto& device : devices) {
+        if (device != *devices.begin()) {
+            ret += ";";
+        }
+        ret += device->toString();
+    }
+    return ret;
+}
+
+AudioDeviceTypeAddrVector deviceTypeAddrsFromDescriptors(const DeviceDescriptorBaseVector& devices)
+{
+    AudioDeviceTypeAddrVector deviceTypeAddrs;
+    for (const auto& device : devices) {
+        deviceTypeAddrs.push_back(device->getDeviceTypeAddr());
+    }
+    return deviceTypeAddrs;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/TEST_MAPPING b/media/libaudiofoundation/TEST_MAPPING
new file mode 100644
index 0000000..f6d249a
--- /dev/null
+++ b/media/libaudiofoundation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+       "name": "audiofoundation_parcelable_test"
+    }
+  ]
+}
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
new file mode 100644
index 0000000..72fda49
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <set>
+#include <vector>
+
+#include <media/TypeConverter.h>
+#include <system/audio.h>
+
+namespace android {
+
+using ChannelMaskSet = std::set<audio_channel_mask_t>;
+using DeviceTypeSet = std::set<audio_devices_t>;
+using FormatSet = std::set<audio_format_t>;
+using SampleRateSet = std::set<uint32_t>;
+
+using FormatVector = std::vector<audio_format_t>;
+
+const DeviceTypeSet& getAudioDeviceOutAllSet();
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet();
+const DeviceTypeSet& getAudioDeviceOutAllScoSet();
+const DeviceTypeSet& getAudioDeviceOutAllUsbSet();
+const DeviceTypeSet& getAudioDeviceInAllSet();
+const DeviceTypeSet& getAudioDeviceInAllUsbSet();
+
+template<typename T>
+static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
+    std::vector<T> intersection;
+    std::set_intersection(a.begin(), a.end(),
+                          b.begin(), b.end(),
+                          std::back_inserter(intersection));
+    return intersection;
+}
+
+static inline ChannelMaskSet asInMask(const ChannelMaskSet& channelMasks) {
+    ChannelMaskSet inMaskSet;
+    for (const auto &channel : channelMasks) {
+        if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
+            inMaskSet.insert(audio_channel_mask_out_to_in(channel));
+        }
+    }
+    return inMaskSet;
+}
+
+static inline ChannelMaskSet asOutMask(const ChannelMaskSet& channelMasks) {
+    ChannelMaskSet outMaskSet;
+    for (const auto &channel : channelMasks) {
+        if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
+            outMaskSet.insert(audio_channel_mask_in_to_out(channel));
+        }
+    }
+    return outMaskSet;
+}
+
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+                                      audio_devices_t deviceType) {
+    return deviceTypes.size() == 1 && *(deviceTypes.begin()) == deviceType;
+}
+
+typedef bool (*DeviceTypeUnaryPredicate)(audio_devices_t);
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+                                      DeviceTypeUnaryPredicate p) {
+    return deviceTypes.size() == 1 && p(*(deviceTypes.begin()));
+}
+
+static inline bool areAllOfSameDeviceType(const DeviceTypeSet& deviceTypes,
+                                          std::function<bool(audio_devices_t)> p) {
+    return std::all_of(deviceTypes.begin(), deviceTypes.end(), p);
+}
+
+static inline void resetDeviceTypes(DeviceTypeSet& deviceTypes, audio_devices_t typeToAdd) {
+    deviceTypes.clear();
+    deviceTypes.insert(typeToAdd);
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+//  bit mask usages of audio device types.
+static inline audio_devices_t deviceTypesToBitMask(const DeviceTypeSet& deviceTypes) {
+    audio_devices_t types = AUDIO_DEVICE_NONE;
+    for (auto deviceType : deviceTypes) {
+        types |= deviceType;
+    }
+    return types;
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+//  bit mask usages of audio device types.
+static inline DeviceTypeSet deviceTypesFromBitMask(audio_devices_t types) {
+    DeviceTypeSet deviceTypes;
+    if ((types & AUDIO_DEVICE_BIT_IN) == 0) {
+        for (auto deviceType : AUDIO_DEVICE_OUT_ALL_ARRAY) {
+            if ((types & deviceType) == deviceType) {
+                deviceTypes.insert(deviceType);
+            }
+        }
+    } else {
+        for (auto deviceType : AUDIO_DEVICE_IN_ALL_ARRAY) {
+            if ((types & deviceType) == deviceType) {
+                deviceTypes.insert(deviceType);
+            }
+        }
+    }
+    return deviceTypes;
+}
+
+bool deviceTypesToString(const DeviceTypeSet& deviceTypes, std::string &str);
+
+std::string dumpDeviceTypes(const DeviceTypeSet& deviceTypes);
+
+/**
+ * Return human readable string for device types.
+ */
+std::string toString(const DeviceTypeSet& deviceTypes);
+
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
new file mode 100644
index 0000000..acc37ca
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcelable.h>
+#include <binder/Parcel.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+struct AudioDeviceTypeAddr : public Parcelable {
+    AudioDeviceTypeAddr() = default;
+
+    AudioDeviceTypeAddr(audio_devices_t type, const std::string& address) :
+            mType(type), mAddress(address) {}
+
+    const char* getAddress() const;
+
+    bool equals(const AudioDeviceTypeAddr& other) const;
+
+    AudioDeviceTypeAddr& operator= (const AudioDeviceTypeAddr&) = default;
+
+    void reset();
+
+    status_t readFromParcel(const Parcel *parcel) override;
+
+    status_t writeToParcel(Parcel *parcel) const override;
+
+    audio_devices_t mType = AUDIO_DEVICE_NONE;
+    std::string mAddress;
+};
+
+using AudioDeviceTypeAddrVector = std::vector<AudioDeviceTypeAddr>;
+
+/**
+ * Return a collection of audio device types from a collection of AudioDeviceTypeAddr
+ */
+DeviceTypeSet getAudioDeviceTypes(const AudioDeviceTypeAddrVector& deviceTypeAddrs);
+
+}
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/media/libaudiofoundation/include/media/AudioGain.h
similarity index 82%
rename from services/audiopolicy/common/managerdefinitions/include/AudioGain.h
rename to media/libaudiofoundation/include/media/AudioGain.h
index 4af93e1..859f1e7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/media/libaudiofoundation/include/media/AudioGain.h
@@ -16,15 +16,17 @@
 
 #pragma once
 
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <system/audio.h>
+#include <string>
 #include <vector>
 
 namespace android {
 
-class AudioGain: public RefBase
+class AudioGain: public RefBase, public Parcelable
 {
 public:
     AudioGain(int index, bool useInChannelMask);
@@ -55,7 +57,7 @@
     int getMaxRampInMs() const { return mGain.max_ramp_ms; }
 
     // TODO: remove dump from here (split serialization)
-    void dump(String8 *dst, int spaces, int index) const;
+    void dump(std::string *dst, int spaces, int index) const;
 
     void getDefaultConfig(struct audio_gain_config *config);
     status_t checkConfig(const struct audio_gain_config *config);
@@ -65,6 +67,11 @@
 
     const struct audio_gain &getGain() const { return mGain; }
 
+    bool equals(const sp<AudioGain>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
 private:
     int               mIndex;
     struct audio_gain mGain;
@@ -72,7 +79,7 @@
     bool              mUseForVolume = false;
 };
 
-class AudioGains : public std::vector<sp<AudioGain> >
+class AudioGains : public std::vector<sp<AudioGain> >, public Parcelable
 {
 public:
     bool canUseForVolume() const
@@ -90,6 +97,11 @@
         push_back(gain);
         return 0;
     }
+
+    bool equals(const AudioGains& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
 };
 
 } // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioPort.h b/media/libaudiofoundation/include/media/AudioPort.h
new file mode 100644
index 0000000..3c013cb
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioPort.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioGain.h>
+#include <media/AudioProfile.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort : public virtual RefBase, public virtual Parcelable
+{
+public:
+    AudioPort(const std::string& name, audio_port_type_t type,  audio_port_role_t role) :
+            mName(name), mType(type), mRole(role) {}
+
+    virtual ~AudioPort() = default;
+
+    void setName(const std::string &name) { mName = name; }
+    const std::string &getName() const { return mName; }
+
+    audio_port_type_t getType() const { return mType; }
+    audio_port_role_t getRole() const { return mRole; }
+
+    void setGains(const AudioGains &gains) { mGains = gains; }
+    const AudioGains &getGains() const { return mGains; }
+
+    virtual void toAudioPort(struct audio_port *port) const;
+
+    virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+        mProfiles.add(profile);
+    }
+    virtual void clearAudioProfiles() {
+        mProfiles.clearProfiles();
+    }
+
+    bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+    bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
+
+    void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+    AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
+
+    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const {
+        if (index < 0 || (size_t)index >= mGains.size()) {
+            return BAD_VALUE;
+        }
+        return mGains[index]->checkConfig(gainConfig);
+    }
+
+    bool useInputChannelMask() const
+    {
+        return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
+                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
+    }
+
+    void dump(std::string *dst, int spaces, bool verbose = true) const;
+
+    void log(const char* indent) const;
+
+    bool equals(const sp<AudioPort>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+    AudioGains mGains; // gain controllers
+protected:
+    std::string  mName;
+    audio_port_type_t mType;
+    audio_port_role_t mRole;
+    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+};
+
+
+class AudioPortConfig : public virtual RefBase, public virtual Parcelable
+{
+public:
+    virtual ~AudioPortConfig() = default;
+
+    virtual sp<AudioPort> getAudioPort() const = 0;
+
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
+
+    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+                                   const struct audio_port_config *srcConfig = NULL) const;
+
+    unsigned int getSamplingRate() const { return mSamplingRate; }
+    audio_format_t getFormat() const { return mFormat; }
+    audio_channel_mask_t getChannelMask() const { return mChannelMask; }
+    audio_port_handle_t getId() const { return mId; }
+
+    bool hasGainController(bool canUseForVolume = false) const;
+
+    bool equals(const sp<AudioPortConfig>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+protected:
+    unsigned int mSamplingRate = 0u;
+    audio_format_t mFormat = AUDIO_FORMAT_INVALID;
+    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
+    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
+    struct audio_gain_config mGain = { .index = -1 };
+};
+
+} // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
new file mode 100644
index 0000000..730138a
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class AudioProfile final : public RefBase, public Parcelable
+{
+public:
+    static sp<AudioProfile> createFullDynamic(audio_format_t dynamicFormat = AUDIO_FORMAT_DEFAULT);
+
+    AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
+    AudioProfile(audio_format_t format,
+                 const ChannelMaskSet &channelMasks,
+                 const SampleRateSet &samplingRateCollection);
+
+    audio_format_t getFormat() const { return mFormat; }
+    const ChannelMaskSet &getChannels() const { return mChannelMasks; }
+    const SampleRateSet &getSampleRates() const { return mSamplingRates; }
+    void setChannels(const ChannelMaskSet &channelMasks);
+    void setSampleRates(const SampleRateSet &sampleRates);
+
+    void clear();
+    bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
+    bool supportsChannels(audio_channel_mask_t channels) const
+    {
+        return mChannelMasks.count(channels) != 0;
+    }
+    bool supportsRate(uint32_t rate) const { return mSamplingRates.count(rate) != 0; }
+
+    bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
+    bool hasValidRates() const { return !mSamplingRates.empty(); }
+    bool hasValidChannels() const { return !mChannelMasks.empty(); }
+
+    void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
+    bool isDynamicChannels() const { return mIsDynamicChannels; }
+
+    void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
+    bool isDynamicRate() const { return mIsDynamicRate; }
+
+    void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
+    bool isDynamicFormat() const { return mIsDynamicFormat; }
+
+    bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+
+    void dump(std::string *dst, int spaces) const;
+
+    bool equals(const sp<AudioProfile>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+private:
+    std::string  mName;
+    audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
+    ChannelMaskSet mChannelMasks;
+    SampleRateSet mSamplingRates;
+
+    bool mIsDynamicFormat = false;
+    bool mIsDynamicChannels = false;
+    bool mIsDynamicRate = false;
+};
+
+class AudioProfileVector : public std::vector<sp<AudioProfile>>, public Parcelable
+{
+public:
+    virtual ~AudioProfileVector() = default;
+
+    virtual ssize_t add(const sp<AudioProfile> &profile);
+
+    // If the profile is dynamic format and has valid format, it will be removed when doing
+    // clearProfiles(). Otherwise, AudioProfile::clear() will be called.
+    virtual void clearProfiles();
+
+    sp<AudioProfile> getFirstValidProfile() const;
+    sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
+    bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+
+    FormatVector getSupportedFormats() const;
+    bool hasDynamicChannelsFor(audio_format_t format) const;
+    bool hasDynamicFormat() const;
+    bool hasDynamicProfile() const;
+    bool hasDynamicRateFor(audio_format_t format) const;
+
+    virtual void dump(std::string *dst, int spaces) const;
+
+    bool equals(const AudioProfileVector& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+} // namespace android
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
new file mode 100644
index 0000000..4c03667
--- /dev/null
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioContainers.h>
+#include <media/AudioPort.h>
+#include <media/AudioDeviceTypeAddr.h>
+#include <utils/Errors.h>
+#include <cutils/config_utils.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
+namespace android {
+
+class DeviceDescriptorBase : public AudioPort, public AudioPortConfig
+{
+public:
+     // Note that empty name refers by convention to a generic device.
+    explicit DeviceDescriptorBase(audio_devices_t type);
+    DeviceDescriptorBase(audio_devices_t type, const std::string& address);
+    explicit DeviceDescriptorBase(const AudioDeviceTypeAddr& deviceTypeAddr);
+
+    virtual ~DeviceDescriptorBase() {}
+
+    audio_devices_t type() const { return mDeviceTypeAddr.mType; }
+    std::string address() const { return mDeviceTypeAddr.mAddress; }
+    void setAddress(const std::string &address) { mDeviceTypeAddr.mAddress = address; }
+    const AudioDeviceTypeAddr& getDeviceTypeAddr() const { return mDeviceTypeAddr; }
+
+    // AudioPortConfig
+    virtual sp<AudioPort> getAudioPort() const {
+        return static_cast<AudioPort*>(const_cast<DeviceDescriptorBase*>(this));
+    }
+    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+            const struct audio_port_config *srcConfig = NULL) const;
+
+    // AudioPort
+    virtual void toAudioPort(struct audio_port *port) const;
+
+    void dump(std::string *dst, int spaces, int index,
+              const char* extraInfo = nullptr, bool verbose = true) const;
+    void log() const;
+    std::string toString() const;
+
+    bool equals(const sp<DeviceDescriptorBase>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+protected:
+    AudioDeviceTypeAddr mDeviceTypeAddr;
+};
+
+using DeviceDescriptorBaseVector = std::vector<sp<DeviceDescriptorBase>>;
+
+/**
+ * Return human readable string for collection of DeviceDescriptorBase.
+ * For a DeviceDescriptorBase, it contains port id, audio device type and address.
+ */
+std::string toString(const DeviceDescriptorBaseVector& devices);
+
+/**
+ * Return a set of device types and addresses from collection of DeviceDescriptorBase.
+ */
+AudioDeviceTypeAddrVector deviceTypeAddrsFromDescriptors(const DeviceDescriptorBaseVector& devices);
+
+} // namespace android
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
new file mode 100644
index 0000000..f258b14
--- /dev/null
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+    name: "audiofoundation_parcelable_test",
+
+    shared_libs: [
+        "libaudiofoundation",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+    ],
+
+    srcs: [
+        "audiofoundation_parcelable_test.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+}
diff --git a/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
new file mode 100644
index 0000000..5baa072
--- /dev/null
+++ b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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_TAG "audiofoundation_parcelable_test"
+
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <media/AudioProfile.h>
+#include <media/DeviceDescriptorBase.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+namespace android {
+
+static const audio_port_config TEST_AUDIO_PORT_CONFIG = {
+        .id = 0,
+        .role = AUDIO_PORT_ROLE_SINK,
+        .type = AUDIO_PORT_TYPE_DEVICE,
+        .config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE | AUDIO_PORT_CONFIG_CHANNEL_MASK |
+                       AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_GAIN,
+        .sample_rate = 48000,
+        .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+        .format = AUDIO_FORMAT_PCM_16_BIT,
+        .gain = {
+                .index = 0,
+                .mode = AUDIO_GAIN_MODE_JOINT,
+                .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+        }
+};
+
+class AudioPortConfigTestStub : public AudioPortConfig {
+public:
+    sp<AudioPort> getAudioPort() const override { return nullptr; }
+};
+
+AudioGains getAudioGainsForTest() {
+    AudioGains audioGains;
+    sp<AudioGain> audioGain = new AudioGain(0 /*index*/, false /*useInChannelMask*/);
+    audioGain->setMode(AUDIO_GAIN_MODE_JOINT);
+    audioGain->setChannelMask(AUDIO_CHANNEL_OUT_STEREO);
+    audioGain->setMinValueInMb(-3200);
+    audioGain->setMaxValueInMb(600);
+    audioGain->setDefaultValueInMb(0);
+    audioGain->setStepValueInMb(100);
+    audioGain->setMinRampInMs(100);
+    audioGain->setMaxRampInMs(500);
+    audioGains.push_back(audioGain);
+    return audioGains;
+}
+
+AudioProfileVector getAudioProfileVectorForTest() {
+    AudioProfileVector audioProfiles;
+    sp<AudioProfile> audioProfile = AudioProfile::createFullDynamic();
+    audioProfile->setChannels({AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO});
+    audioProfile->setSampleRates({48000});
+    audioProfiles.add(audioProfile);
+    return audioProfiles;
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioGain) {
+    Parcel data;
+    AudioGains audioGains = getAudioGainsForTest();
+
+    ASSERT_EQ(data.writeParcelable(audioGains), NO_ERROR);
+    data.setDataPosition(0);
+    AudioGains audioGainsFromParcel;
+    ASSERT_EQ(data.readParcelable(&audioGainsFromParcel), NO_ERROR);
+    ASSERT_TRUE(audioGainsFromParcel.equals(audioGains));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioProfileVector) {
+    Parcel data;
+    AudioProfileVector audioProfiles = getAudioProfileVectorForTest();
+
+    ASSERT_EQ(data.writeParcelable(audioProfiles), NO_ERROR);
+    data.setDataPosition(0);
+    AudioProfileVector audioProfilesFromParcel;
+    ASSERT_EQ(data.readParcelable(&audioProfilesFromParcel), NO_ERROR);
+    ASSERT_TRUE(audioProfilesFromParcel.equals(audioProfiles));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPort) {
+    Parcel data;
+    sp<AudioPort> audioPort = new AudioPort(
+            "AudioPortName", AUDIO_PORT_TYPE_DEVICE, AUDIO_PORT_ROLE_SINK);
+    audioPort->setGains(getAudioGainsForTest());
+    audioPort->setAudioProfiles(getAudioProfileVectorForTest());
+
+    ASSERT_EQ(data.writeParcelable(*audioPort), NO_ERROR);
+    data.setDataPosition(0);
+    sp<AudioPort> audioPortFromParcel = new AudioPort(
+            "", AUDIO_PORT_TYPE_NONE, AUDIO_PORT_ROLE_NONE);
+    ASSERT_EQ(data.readParcelable(audioPortFromParcel.get()), NO_ERROR);
+    ASSERT_TRUE(audioPortFromParcel->equals(audioPort));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPortConfig) {
+    Parcel data;
+    sp<AudioPortConfig> audioPortConfig = new AudioPortConfigTestStub();
+    audioPortConfig->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+
+    ASSERT_EQ(data.writeParcelable(*audioPortConfig), NO_ERROR);
+    data.setDataPosition(0);
+    sp<AudioPortConfig> audioPortConfigFromParcel = new AudioPortConfigTestStub();
+    ASSERT_EQ(data.readParcelable(audioPortConfigFromParcel.get()), NO_ERROR);
+    ASSERT_TRUE(audioPortConfigFromParcel->equals(audioPortConfig));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingDeviceDescriptorBase) {
+    Parcel data;
+    sp<DeviceDescriptorBase> desc = new DeviceDescriptorBase(AUDIO_DEVICE_OUT_SPEAKER);
+    desc->setGains(getAudioGainsForTest());
+    desc->setAudioProfiles(getAudioProfileVectorForTest());
+    desc->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+    desc->setAddress("DeviceDescriptorBaseTestAddress");
+
+    ASSERT_EQ(data.writeParcelable(*desc), NO_ERROR);
+    data.setDataPosition(0);
+    sp<DeviceDescriptorBase> descFromParcel = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+    ASSERT_EQ(data.readParcelable(descFromParcel.get()), NO_ERROR);
+    ASSERT_TRUE(descFromParcel->equals(desc));
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index 8669e2a..e96a68c 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -27,6 +27,7 @@
         "android.hardware.audio.common-util",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "libaudiofoundation",
         "libaudiohal_deathhandler",
         "libaudioutils",
         "libbase",
diff --git a/media/libaudiohal/impl/ConversionHelperHidl.cpp b/media/libaudiohal/impl/ConversionHelperHidl.cpp
index 9f8a520..f29b0f3 100644
--- a/media/libaudiohal/impl/ConversionHelperHidl.cpp
+++ b/media/libaudiohal/impl/ConversionHelperHidl.cpp
@@ -17,6 +17,7 @@
 #include <string.h>
 
 #define LOG_TAG "HalHidl"
+#include <media/AudioContainers.h>
 #include <media/AudioParameter.h>
 #include <utils/Log.h>
 
@@ -109,26 +110,22 @@
     char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
     memset(halAddress, 0, sizeof(halAddress));
     audio_devices_t halDevice = static_cast<audio_devices_t>(address.device);
-    const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
-        (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+    if (getAudioDeviceOutAllA2dpSet().count(halDevice) > 0 ||
+        halDevice == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
         snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
                  address.address.mac[0], address.address.mac[1], address.address.mac[2],
                  address.address.mac[3], address.address.mac[4], address.address.mac[5]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_IP || halDevice == AUDIO_DEVICE_IN_IP) {
         snprintf(halAddress, sizeof(halAddress), "%d.%d.%d.%d", address.address.ipv4[0],
                  address.address.ipv4[1], address.address.ipv4[2], address.address.ipv4[3]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) {
+    } else if (getAudioDeviceOutAllUsbSet().count(halDevice) > 0 ||
+               getAudioDeviceInAllUsbSet().count(halDevice) > 0) {
         snprintf(halAddress, sizeof(halAddress), "card=%d;device=%d", address.address.alsa.card,
                  address.address.alsa.device);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_BUS || halDevice == AUDIO_DEVICE_IN_BUS) {
         snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str());
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
-               (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+    } else if (halDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+               halDevice == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
         snprintf(halAddress, sizeof(halAddress), "%s", address.rSubmixAddress.c_str());
     } else {
         snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str());
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index b25f82e..42c16c0 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -22,6 +22,7 @@
 #include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
 #include <cutils/native_handle.h>
 #include <hwbinder/IPCThreadState.h>
+#include <media/AudioContainers.h>
 #include <utils/Log.h>
 
 #include <common/all-versions/VersionUtils.h>
@@ -51,42 +52,32 @@
     if (halAddress == nullptr || strnlen(halAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
         return OK;
     }
-    const bool isInput = (device & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) device &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_A2DP) != 0)
-            || (isInput && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+    if (getAudioDeviceOutAllA2dpSet().count(device) > 0
+            || device == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
         int status = sscanf(halAddress,
                 "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
                 &address->address.mac[0], &address->address.mac[1], &address->address.mac[2],
                 &address->address.mac[3], &address->address.mac[4], &address->address.mac[5]);
         return status == 6 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_IP) != 0)
-            || (isInput && (device & AUDIO_DEVICE_IN_IP) != 0)) {
+    } else if (device == AUDIO_DEVICE_OUT_IP || device == AUDIO_DEVICE_IN_IP) {
         int status = sscanf(halAddress,
                 "%hhu.%hhu.%hhu.%hhu",
                 &address->address.ipv4[0], &address->address.ipv4[1],
                 &address->address.ipv4[2], &address->address.ipv4[3]);
         return status == 4 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_ALL_USB)) != 0
-            || (isInput && (device & AUDIO_DEVICE_IN_ALL_USB)) != 0) {
+    } else if (getAudioDeviceOutAllUsbSet().count(device) > 0
+            || getAudioDeviceInAllUsbSet().count(device) > 0) {
         int status = sscanf(halAddress,
                 "card=%d;device=%d",
                 &address->address.alsa.card, &address->address.alsa.device);
         return status == 2 ? OK : BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_BUS) != 0)
-            || (isInput && (device & AUDIO_DEVICE_IN_BUS) != 0)) {
-        if (halAddress != NULL) {
-            address->busAddress = halAddress;
-            return OK;
-        }
-        return BAD_VALUE;
-    } else if ((!isInput && (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0
-            || (isInput && (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
-        if (halAddress != NULL) {
-            address->rSubmixAddress = halAddress;
-            return OK;
-        }
-        return BAD_VALUE;
+    } else if (device == AUDIO_DEVICE_OUT_BUS || device == AUDIO_DEVICE_IN_BUS) {
+        address->busAddress = halAddress;
+        return OK;
+    } else if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+            || device == AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+        address->rSubmixAddress = halAddress;
+        return OK;
     }
     return OK;
 }
@@ -100,8 +91,12 @@
 
 DeviceHalHidl::~DeviceHalHidl() {
     if (mDevice != 0) {
+#if MAJOR_VERSION <= 5
         mDevice.clear();
         hardware::IPCThreadState::self()->flushCommands();
+#elif MAJOR_VERSION >= 6
+        mDevice->close();
+#endif
     }
 }
 
@@ -229,14 +224,14 @@
 
 status_t DeviceHalHidl::openOutputStream(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address,
         sp<StreamOutHalInterface> *outStream) {
     if (mDevice == 0) return NO_INIT;
     DeviceAddress hidlDevice;
-    status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
+    status_t status = deviceAddressFromHal(deviceType, address, &hidlDevice);
     if (status != OK) return status;
     AudioConfig hidlConfig;
     HidlUtils::audioConfigFromHal(*config, &hidlConfig);
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
index ee68252..dfbb6b2 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -104,7 +104,7 @@
 
 status_t DeviceHalLocal::openOutputStream(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address,
@@ -112,11 +112,11 @@
     audio_stream_out_t *halStream;
     ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
             "srate: %d format %#x channels %x address %s",
-            handle, devices, flags,
+            handle, deviceType, flags,
             config->sample_rate, config->format, config->channel_mask,
             address);
     int openResut = mDev->open_output_stream(
-            mDev, handle, devices, flags, config, &halStream, address);
+            mDev, handle, deviceType, flags, config, &halStream, address);
     if (openResut == OK) {
         *outStream = new StreamOutHalLocal(halStream, this);
     }
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index 1335a0c..c30da3c 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -20,6 +20,7 @@
 #define LOG_TAG "DevicesFactoryHalHidl"
 //#define LOG_NDEBUG 0
 
+#include "android/hidl/manager/1.0/IServiceManager.h"
 #include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
 #include <media/audiohal/hidl/HalDeathHandler.h>
 #include <utils/Log.h>
@@ -28,6 +29,8 @@
 #include "DeviceHalHidl.h"
 #include "DevicesFactoryHalHidl.h"
 
+#include <set>
+
 using ::android::hardware::audio::CPP_VERSION::IDevice;
 using ::android::hardware::audio::CPP_VERSION::Result;
 using ::android::hardware::Return;
@@ -108,5 +111,29 @@
     return BAD_VALUE;
 }
 
+status_t DevicesFactoryHalHidl::getHalPids(std::vector<pid_t> *pids) {
+    std::set<pid_t> pidsSet;
+
+    for (const auto& factory : mDeviceFactories) {
+        using ::android::hidl::base::V1_0::DebugInfo;
+        using android::hidl::manager::V1_0::IServiceManager;
+
+        DebugInfo debugInfo;
+        auto ret = factory->getDebugInfo([&] (const auto &info) {
+               debugInfo = info;
+            });
+        if (!ret.isOk()) {
+           return INVALID_OPERATION;
+        }
+        if (debugInfo.pid == (int)IServiceManager::PidConstant::NO_PID) {
+            continue;
+        }
+        pidsSet.insert(debugInfo.pid);
+    }
+
+    *pids = {pidsSet.begin(), pidsSet.end()};
+    return NO_ERROR;
+}
+
 } // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 8775e7b..52185c8 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -37,6 +37,9 @@
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+
+            status_t getHalPids(std::vector<pid_t> *pids) override;
+
   private:
     std::vector<sp<IDevicesFactory>> mDeviceFactories;
 
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index 0e1f1bb..a5aef1b 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -37,6 +37,14 @@
     }
     return mLocalFactory->openDevice(name, device);
 }
+
+status_t DevicesFactoryHalHybrid::getHalPids(std::vector<pid_t> *pids) {
+    if (mHidlFactory != 0) {
+        return mHidlFactory->getHalPids(pids);
+    }
+    return INVALID_OPERATION;
+}
+
 } // namespace CPP_VERSION
 
 template <>
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index 545bb70..2189b36 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -36,6 +36,8 @@
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
 
+            status_t getHalPids(std::vector<pid_t> *pids) override;
+
   private:
     sp<DevicesFactoryHalInterface> mLocalFactory;
     sp<DevicesFactoryHalInterface> mHidlFactory;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
index 5d108dd..2b011f4 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
@@ -33,6 +33,10 @@
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
 
+            status_t getHalPids(std::vector<pid_t> *pids __unused) override {
+                return INVALID_OPERATION;
+            }
+
   private:
     friend class DevicesFactoryHalHybrid;
 
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index e565237..2200a7f 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -69,7 +69,7 @@
     // by releasing all references to the returned object.
     virtual status_t openOutputStream(
             audio_io_handle_t handle,
-            audio_devices_t devices,
+            audio_devices_t deviceType,
             audio_output_flags_t flags,
             struct audio_config *config,
             const char *address,
diff --git a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
index 14af384..e9ac1ce 100644
--- a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -20,6 +20,7 @@
 #include <media/audiohal/DeviceHalInterface.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <vector>
 
 namespace android {
 
@@ -30,6 +31,8 @@
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device) = 0;
 
+    virtual status_t getHalPids(std::vector<pid_t> *pids) = 0;
+
     static sp<DevicesFactoryHalInterface> create();
 
   protected:
diff --git a/media/libdatasource/NuCachedSource2.cpp b/media/libdatasource/NuCachedSource2.cpp
index 7f5ae61..6d63ffb 100644
--- a/media/libdatasource/NuCachedSource2.cpp
+++ b/media/libdatasource/NuCachedSource2.cpp
@@ -689,10 +689,6 @@
     restartPrefetcherIfNecessary_l(true /* ignore low water threshold */);
 }
 
-sp<DecryptHandle> NuCachedSource2::DrmInitialization(const char* mime) {
-    return mSource->DrmInitialization(mime);
-}
-
 String8 NuCachedSource2::getUri() {
     return mSource->getUri();
 }
diff --git a/media/libdatasource/include/datasource/NuCachedSource2.h b/media/libdatasource/include/datasource/NuCachedSource2.h
index 596efb8..4c253ad 100644
--- a/media/libdatasource/include/datasource/NuCachedSource2.h
+++ b/media/libdatasource/include/datasource/NuCachedSource2.h
@@ -44,7 +44,6 @@
     virtual status_t getSize(off64_t *size);
     virtual uint32_t flags();
 
-    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
     virtual String8 getUri();
 
     virtual String8 getMIMEType() const;
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index a977300..bbc14a9 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -66,9 +66,6 @@
     void close() {}
     uint32_t getFlags() override { return 0; }
     String8 toString() override { return String8("HeifDataSource"); }
-    sp<DecryptHandle> DrmInitialization(const char*) override {
-        return nullptr;
-    }
 
 private:
     enum {
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index b49df9e..778ee44 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -15,31 +15,6 @@
     ],
 }
 
-cc_library {
-    name: "libmedia_helper",
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
-    double_loadable: true,
-    srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
-    cflags: [
-        "-Werror",
-        "-Wno-error=deprecated-declarations",
-        "-Wall",
-    ],
-    shared_libs: ["libutils", "liblog"],
-    header_libs: [
-        "libmedia_headers",
-        "libaudioclient_headers",
-        "libaudio_system_headers",
-    ],
-    export_header_lib_headers: [
-        "libmedia_headers",
-    ],
-    clang: true,
-}
-
 filegroup {
     name: "libmedia_omx_aidl",
     srcs: [
diff --git a/media/libmedia/IDataSource.cpp b/media/libmedia/IDataSource.cpp
index 31c85af..61f0a68 100644
--- a/media/libmedia/IDataSource.cpp
+++ b/media/libmedia/IDataSource.cpp
@@ -23,7 +23,6 @@
 
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
-#include <drm/drm_framework_common.h>
 #include <media/stagefright/foundation/ADebug.h>
 
 namespace android {
@@ -35,7 +34,6 @@
     CLOSE,
     GET_FLAGS,
     TO_STRING,
-    DRM_INITIALIZATION,
 };
 
 struct BpDataSource : public BpInterface<IDataSource> {
@@ -95,47 +93,6 @@
         remote()->transact(TO_STRING, data, &reply);
         return reply.readString8();
     }
-
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDataSource::getInterfaceDescriptor());
-        if (mime == NULL) {
-            data.writeInt32(0);
-        } else {
-            data.writeInt32(1);
-            data.writeCString(mime);
-        }
-        remote()->transact(DRM_INITIALIZATION, data, &reply);
-        sp<DecryptHandle> handle;
-        if (reply.dataAvail() != 0) {
-            handle = new DecryptHandle();
-            handle->decryptId = reply.readInt32();
-            handle->mimeType = reply.readString8();
-            handle->decryptApiType = reply.readInt32();
-            handle->status = reply.readInt32();
-
-            const int bufferLength = data.readInt32();
-            if (bufferLength != -1) {
-                handle->decryptInfo = new DecryptInfo();
-                handle->decryptInfo->decryptBufferLength = bufferLength;
-            }
-
-            size_t size = data.readInt32();
-            for (size_t i = 0; i < size; ++i) {
-                DrmCopyControl key = (DrmCopyControl)data.readInt32();
-                int value = data.readInt32();
-                handle->copyControlVector.add(key, value);
-            }
-
-            size = data.readInt32();
-            for (size_t i = 0; i < size; ++i) {
-                String8 key = data.readString8();
-                String8 value = data.readString8();
-                handle->extendedData.add(key, value);
-            }
-        }
-        return handle;
-    }
 };
 
 IMPLEMENT_META_INTERFACE(DataSource, "android.media.IDataSource");
@@ -178,42 +135,6 @@
             reply->writeString8(toString());
             return NO_ERROR;
         } break;
-        case DRM_INITIALIZATION: {
-            CHECK_INTERFACE(IDataSource, data, reply);
-            const char *mime = NULL;
-            const int32_t flag = data.readInt32();
-            if (flag != 0) {
-                mime = data.readCString();
-            }
-            sp<DecryptHandle> handle = DrmInitialization(mime);
-            if (handle != NULL) {
-                reply->writeInt32(handle->decryptId);
-                reply->writeString8(handle->mimeType);
-                reply->writeInt32(handle->decryptApiType);
-                reply->writeInt32(handle->status);
-
-                if (handle->decryptInfo != NULL) {
-                    reply->writeInt32(handle->decryptInfo->decryptBufferLength);
-                } else {
-                    reply->writeInt32(-1);
-                }
-
-                size_t size = handle->copyControlVector.size();
-                reply->writeInt32(size);
-                for (size_t i = 0; i < size; ++i) {
-                    reply->writeInt32(handle->copyControlVector.keyAt(i));
-                    reply->writeInt32(handle->copyControlVector.valueAt(i));
-                }
-
-                size = handle->extendedData.size();
-                reply->writeInt32(size);
-                for (size_t i = 0; i < size; ++i) {
-                    reply->writeString8(handle->extendedData.keyAt(i));
-                    reply->writeString8(handle->extendedData.valueAt(i));
-                }
-            }
-            return NO_ERROR;
-        } break;
 
         default:
             return BBinder::onTransact(code, data, reply, flags);
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 9724fc1..f8a0a14 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -32,6 +32,7 @@
     CONFIG = IBinder::FIRST_CALL_TRANSACTION,
     ADD_RESOURCE,
     REMOVE_RESOURCE,
+    REMOVE_CLIENT,
     RECLAIM_RESOURCE,
 };
 
@@ -72,12 +73,14 @@
 
     virtual void addResource(
             int pid,
+            int uid,
             int64_t clientId,
             const sp<IResourceManagerClient> client,
             const Vector<MediaResource> &resources) {
         Parcel data, reply;
         data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
         data.writeInt32(pid);
+        data.writeInt32(uid);
         data.writeInt64(clientId);
         data.writeStrongBinder(IInterface::asBinder(client));
         writeToParcel(&data, resources);
@@ -85,13 +88,23 @@
         remote()->transact(ADD_RESOURCE, data, &reply);
     }
 
-    virtual void removeResource(int pid, int64_t clientId) {
+    virtual void removeResource(int pid, int64_t clientId, const Vector<MediaResource> &resources) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        data.writeInt64(clientId);
+        writeToParcel(&data, resources);
+
+        remote()->transact(REMOVE_RESOURCE, data, &reply);
+    }
+
+    virtual void removeClient(int pid, int64_t clientId) {
         Parcel data, reply;
         data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeInt64(clientId);
 
-        remote()->transact(REMOVE_RESOURCE, data, &reply);
+        remote()->transact(REMOVE_CLIENT, data, &reply);
     }
 
     virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources) {
@@ -129,6 +142,7 @@
         case ADD_RESOURCE: {
             CHECK_INTERFACE(IResourceManagerService, data, reply);
             int pid = data.readInt32();
+            int uid = data.readInt32();
             int64_t clientId = data.readInt64();
             sp<IResourceManagerClient> client(
                     interface_cast<IResourceManagerClient>(data.readStrongBinder()));
@@ -137,7 +151,7 @@
             }
             Vector<MediaResource> resources;
             readFromParcel(data, &resources);
-            addResource(pid, clientId, client, resources);
+            addResource(pid, uid, clientId, client, resources);
             return NO_ERROR;
         } break;
 
@@ -145,7 +159,17 @@
             CHECK_INTERFACE(IResourceManagerService, data, reply);
             int pid = data.readInt32();
             int64_t clientId = data.readInt64();
-            removeResource(pid, clientId);
+            Vector<MediaResource> resources;
+            readFromParcel(data, &resources);
+            removeResource(pid, clientId, resources);
+            return NO_ERROR;
+        } break;
+
+        case REMOVE_CLIENT: {
+            CHECK_INTERFACE(IResourceManagerService, data, reply);
+            int pid = data.readInt32();
+            int64_t clientId = data.readInt64();
+            removeClient(pid, clientId);
             return NO_ERROR;
         } break;
 
diff --git a/media/libmedia/include/media/IDataSource.h b/media/libmedia/include/media/IDataSource.h
index 3858f78..43e2b50 100644
--- a/media/libmedia/include/media/IDataSource.h
+++ b/media/libmedia/include/media/IDataSource.h
@@ -50,8 +50,6 @@
     virtual uint32_t getFlags() = 0;
     // get a description of the source, e.g. the url or filename it is based on
     virtual String8 toString() = 0;
-    // Initialize DRM and return a DecryptHandle.
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime) = 0;
 
 private:
     DISALLOW_EVIL_CONSTRUCTORS(IDataSource);
diff --git a/media/libmedia/include/media/IResourceManagerService.h b/media/libmedia/include/media/IResourceManagerService.h
index 1e4f6de..8992f8b 100644
--- a/media/libmedia/include/media/IResourceManagerService.h
+++ b/media/libmedia/include/media/IResourceManagerService.h
@@ -39,11 +39,15 @@
 
     virtual void addResource(
             int pid,
+            int uid,
             int64_t clientId,
             const sp<IResourceManagerClient> client,
             const Vector<MediaResource> &resources) = 0;
 
-    virtual void removeResource(int pid, int64_t clientId) = 0;
+    virtual void removeResource(int pid, int64_t clientId,
+            const Vector<MediaResource> &resources) = 0;
+
+    virtual void removeClient(int pid, int64_t clientId) = 0;
 
     virtual bool reclaimResource(
             int callingPid,
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index e1fdb9b..10a07bb 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -31,12 +31,13 @@
         kNonSecureCodec,
         kGraphicMemory,
         kCpuBoost,
+        kBattery,
     };
 
     enum SubType {
         kUnspecifiedSubType = 0,
         kAudioCodec,
-        kVideoCodec
+        kVideoCodec,
     };
 
     MediaResource();
@@ -62,6 +63,8 @@
         case MediaResource::kSecureCodec:    return "secure-codec";
         case MediaResource::kNonSecureCodec: return "non-secure-codec";
         case MediaResource::kGraphicMemory:  return "graphic-memory";
+        case MediaResource::kCpuBoost:       return "cpu-boost";
+        case MediaResource::kBattery:        return "battery";
         default:                             return def;
     }
 }
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
new file mode 100644
index 0000000..72edeec
--- /dev/null
+++ b/media/libmediahelper/Android.bp
@@ -0,0 +1,29 @@
+cc_library_headers {
+    name: "libmedia_helper_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libmedia_helper",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    double_loadable: true,
+    srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
+    cflags: [
+        "-Werror",
+        "-Wextra",
+        "-Wall",
+    ],
+    shared_libs: ["libutils", "liblog"],
+    header_libs: [
+        "libmedia_helper_headers",
+        "libaudio_system_headers",
+    ],
+    export_header_lib_headers: [
+        "libmedia_helper_headers",
+    ],
+    clang: true,
+}
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmediahelper/AudioParameter.cpp
similarity index 100%
rename from media/libmedia/AudioParameter.cpp
rename to media/libmediahelper/AudioParameter.cpp
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmediahelper/TypeConverter.cpp
similarity index 100%
rename from media/libmedia/TypeConverter.cpp
rename to media/libmediahelper/TypeConverter.cpp
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libmediahelper/include/media/AudioParameter.h
similarity index 100%
rename from media/libaudioclient/include/media/AudioParameter.h
rename to media/libmediahelper/include/media/AudioParameter.h
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmediahelper/include/media/TypeConverter.h
similarity index 95%
rename from media/libmedia/include/media/TypeConverter.h
rename to media/libmediahelper/include/media/TypeConverter.h
index 2f8c209..011498a 100644
--- a/media/libmedia/include/media/TypeConverter.h
+++ b/media/libmediahelper/include/media/TypeConverter.h
@@ -17,10 +17,11 @@
 #ifndef ANDROID_TYPE_CONVERTER_H_
 #define ANDROID_TYPE_CONVERTER_H_
 
+#include <set>
 #include <string>
 #include <string.h>
-
 #include <vector>
+
 #include <system/audio.h>
 #include <utils/Log.h>
 #include <utils/Vector.h>
@@ -42,16 +43,6 @@
     }
 };
 template <typename T>
-struct VectorTraits
-{
-    typedef T Type;
-    typedef Vector<Type> Collection;
-    static void add(Collection &collection, Type value)
-    {
-        collection.add(value);
-    }
-};
-template <typename T>
 struct SortedVectorTraits
 {
     typedef T Type;
@@ -61,18 +52,28 @@
         collection.add(value);
     }
 };
+template <typename T>
+struct SetTraits
+{
+    typedef T Type;
+    typedef std::set<Type> Collection;
+    static void add(Collection &collection, Type value)
+    {
+        collection.insert(value);
+    }
+};
 
-using SampleRateTraits = SortedVectorTraits<uint32_t>;
+using SampleRateTraits = SetTraits<uint32_t>;
 using DeviceTraits = DefaultTraits<audio_devices_t>;
 struct OutputDeviceTraits : public DeviceTraits {};
 struct InputDeviceTraits : public DeviceTraits {};
-using ChannelTraits = SortedVectorTraits<audio_channel_mask_t>;
+using ChannelTraits = SetTraits<audio_channel_mask_t>;
 struct OutputChannelTraits : public ChannelTraits {};
 struct InputChannelTraits : public ChannelTraits {};
 struct ChannelIndexTraits : public ChannelTraits {};
 using InputFlagTraits = DefaultTraits<audio_input_flags_t>;
 using OutputFlagTraits = DefaultTraits<audio_output_flags_t>;
-using FormatTraits = VectorTraits<audio_format_t>;
+using FormatTraits = DefaultTraits<audio_format_t>;
 using GainModeTraits = DefaultTraits<audio_gain_mode_t>;
 using StreamTraits = DefaultTraits<audio_stream_type_t>;
 using AudioModeTraits = DefaultTraits<audio_mode_t>;
@@ -259,6 +260,7 @@
                                     || std::is_same<T, audio_source_t>::value
                                     || std::is_same<T, audio_stream_type_t>::value
                                     || std::is_same<T, audio_usage_t>::value
+                                    || std::is_same<T, audio_format_t>::value
                                     , int> = 0>
 static inline std::string toString(const T& value)
 {
@@ -291,14 +293,6 @@
     return result;
 }
 
-// TODO: Remove when FormatTraits uses DefaultTraits.
-static inline std::string toString(const audio_format_t& format)
-{
-    std::string result;
-    return TypeConverter<VectorTraits<audio_format_t>>::toString(format, result)
-            ? result : std::to_string(static_cast<int>(format));
-}
-
 static inline std::string toString(const audio_attributes_t& attributes)
 {
     std::ostringstream result;
diff --git a/media/libmedia/include/media/convert.h b/media/libmediahelper/include/media/convert.h
similarity index 100%
rename from media/libmedia/include/media/convert.h
rename to media/libmediahelper/include/media/convert.h
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
index 1580891..bb4ba75 100644
--- a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
@@ -31,6 +31,7 @@
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL){
+    (void) DrmInitialization(nullptr);
 }
 
 PlayerServiceFileSource::PlayerServiceFileSource(int fd, int64_t offset, int64_t length)
@@ -40,6 +41,7 @@
       mDrmBufOffset(0),
       mDrmBufSize(0),
       mDrmBuf(NULL) {
+    (void) DrmInitialization(nullptr);
 }
 
 PlayerServiceFileSource::~PlayerServiceFileSource() {
@@ -87,7 +89,9 @@
 }
 
 sp<DecryptHandle> PlayerServiceFileSource::DrmInitialization(const char *mime) {
-    if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
+    if (getuid() == AID_MEDIA_EX) {
+       return NULL; // no DRM in media extractor
+    }
     if (mDrmManagerClient == NULL) {
         mDrmManagerClient = new DrmManagerClient();
     }
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
index 0124720..f99a861 100644
--- a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
+++ b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
@@ -32,6 +32,7 @@
 PlayerServiceMediaHTTP::PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn)
     : MediaHTTP(conn),
       mDrmManagerClient(NULL) {
+    (void) DrmInitialization(nullptr);
 }
 
 PlayerServiceMediaHTTP::~PlayerServiceMediaHTTP() {
@@ -40,7 +41,7 @@
 
 // DRM...
 
-sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char* mime) {
+sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char *mime) {
     if (mDrmManagerClient == NULL) {
         mDrmManagerClient = new DrmManagerClient();
     }
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
index 08a013e..7ae8dda 100644
--- a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
@@ -37,8 +37,6 @@
 
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
 
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
-
     static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
 
 protected:
@@ -52,6 +50,7 @@
     ssize_t mDrmBufSize;
     unsigned char *mDrmBuf;
 
+    sp<DecryptHandle> DrmInitialization(const char *mime);
     ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
 
     PlayerServiceFileSource(const PlayerServiceFileSource &);
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
index 0032cd7..b5124dc 100644
--- a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
@@ -33,12 +33,11 @@
 protected:
     virtual ~PlayerServiceMediaHTTP();
 
-    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
-
 private:
     sp<DecryptHandle> mDecryptHandle;
     DrmManagerClient *mDrmManagerClient;
 
+    sp<DecryptHandle> DrmInitialization(const char *mime);
     void clearDRMState_l();
 
     DISALLOW_EVIL_CONSTRUCTORS(PlayerServiceMediaHTTP);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d1b96e3..cfefe11 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1826,6 +1826,23 @@
             mRepeatFrameDelayUs = -1LL;
         }
 
+        if (!msg->findDouble("time-lapse-fps", &mCaptureFps)) {
+            float captureRate;
+            if (msg->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {
+                mCaptureFps = captureRate;
+            } else {
+                mCaptureFps = -1.0;
+            }
+        }
+
+        if (!msg->findInt32(
+                KEY_CREATE_INPUT_SURFACE_SUSPENDED,
+                (int32_t*)&mCreateInputBuffersSuspended)) {
+            mCreateInputBuffersSuspended = false;
+        }
+    }
+
+    if (encoder && (mIsVideo || mIsImage)) {
         // only allow 32-bit value, since we pass it as U32 to OMX.
         if (!msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &mMaxPtsGapUs)) {
             mMaxPtsGapUs = 0LL;
@@ -1842,16 +1859,6 @@
         if (mMaxPtsGapUs < 0LL) {
             mMaxFps = -1;
         }
-
-        if (!msg->findDouble("time-lapse-fps", &mCaptureFps)) {
-            mCaptureFps = -1.0;
-        }
-
-        if (!msg->findInt32(
-                KEY_CREATE_INPUT_SURFACE_SUSPENDED,
-                (int32_t*)&mCreateInputBuffersSuspended)) {
-            mCreateInputBuffersSuspended = false;
-        }
     }
 
     // NOTE: we only use native window for video decoders
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 59cc24b..18dacb8 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -102,6 +102,10 @@
         "include",
     ],
 
+    header_libs: [
+        "libmedia_helper_headers",
+    ],
+
     cflags: [
         "-Wno-multichar",
         "-Werror",
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 92e6eb9..265f21b 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -113,10 +113,6 @@
     }
 }
 
-sp<DecryptHandle> CallbackDataSource::DrmInitialization(const char *mime) {
-    return mIDataSource->DrmInitialization(mime);
-}
-
 sp<IDataSource> CallbackDataSource::getIDataSource() const {
     return mIDataSource;
 }
@@ -190,14 +186,6 @@
     return mSource->flags();
 }
 
-sp<DecryptHandle> TinyCacheSource::DrmInitialization(const char *mime) {
-    // flush cache when DrmInitialization occurs since decrypted
-    // data may differ from what is in cache.
-    mCachedOffset = 0;
-    mCachedSize = 0;
-    return mSource->DrmInitialization(mime);
-}
-
 sp<IDataSource> TinyCacheSource::getIDataSource() const {
     return mSource->getIDataSource();
 }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 161c178..3d6ebc3 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -48,6 +48,7 @@
 #include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/ACodec.h>
+#include <media/stagefright/BatteryChecker.h>
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaCodecList.h>
@@ -57,7 +58,6 @@
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/PersistentSurface.h>
 #include <media/stagefright/SurfaceUtils.h>
-#include <mediautils/BatteryNotifier.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Singleton.h>
 
@@ -166,8 +166,9 @@
     DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
 };
 
-MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(pid_t pid)
-        : mPid(pid) {
+MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
+        pid_t pid, uid_t uid)
+        : mPid(pid), mUid(uid) {
     if (mPid == MediaCodec::kNoPid) {
         mPid = IPCThreadState::self()->getCallingPid();
     }
@@ -204,15 +205,25 @@
     if (mService == NULL) {
         return;
     }
-    mService->addResource(mPid, clientId, client, resources);
+    mService->addResource(mPid, mUid, clientId, client, resources);
 }
 
-void MediaCodec::ResourceManagerServiceProxy::removeResource(int64_t clientId) {
+void MediaCodec::ResourceManagerServiceProxy::removeResource(
+        int64_t clientId,
+        const Vector<MediaResource> &resources) {
     Mutex::Autolock _l(mLock);
     if (mService == NULL) {
         return;
     }
-    mService->removeResource(mPid, clientId);
+    mService->removeResource(mPid, clientId, resources);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::removeClient(int64_t clientId) {
+    Mutex::Autolock _l(mLock);
+    if (mService == NULL) {
+        return;
+    }
+    mService->removeClient(mPid, clientId);
 }
 
 bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
@@ -517,9 +528,6 @@
       mStickyError(OK),
       mSoftRenderer(NULL),
       mAnalyticsItem(NULL),
-      mResourceManagerClient(new ResourceManagerClient(this)),
-      mResourceManagerService(new ResourceManagerServiceProxy(pid)),
-      mBatteryStatNotified(false),
       mIsVideo(false),
       mVideoWidth(0),
       mVideoHeight(0),
@@ -537,13 +545,15 @@
     } else {
         mUid = uid;
     }
+    mResourceManagerClient = new ResourceManagerClient(this);
+    mResourceManagerService = new ResourceManagerServiceProxy(pid, mUid);
 
     initAnalyticsItem();
 }
 
 MediaCodec::~MediaCodec() {
     CHECK_EQ(mState, UNINITIALIZED);
-    mResourceManagerService->removeResource(getId(mResourceManagerClient));
+    mResourceManagerService->removeClient(getId(mResourceManagerClient));
 
     flushAnalyticsItem();
 }
@@ -742,6 +752,12 @@
         return;
     }
 
+    if (mBatteryChecker != nullptr) {
+        mBatteryChecker->onCodecActivity([this] () {
+            addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+        });
+    }
+
     const int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
     BufferFlightTiming_t startdata = { presentationUs, nowNs };
 
@@ -776,6 +792,12 @@
         return;
     }
 
+    if (mBatteryChecker != nullptr) {
+        mBatteryChecker->onCodecActivity([this] () {
+            addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+        });
+    }
+
     BufferFlightTiming_t startdata;
     bool valid = false;
     while (mBuffersInFlight.size() > 0) {
@@ -964,6 +986,10 @@
         mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
     }
 
+    if (mIsVideo) {
+        mBatteryChecker = new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this));
+    }
+
     status_t err;
     Vector<MediaResource> resources;
     MediaResource::Type type =
@@ -1221,6 +1247,13 @@
             getId(mResourceManagerClient), mResourceManagerClient, resources);
 }
 
+void MediaCodec::removeResource(
+        MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
+    Vector<MediaResource> resources;
+    resources.push_back(MediaResource(type, subtype, value));
+    mResourceManagerService->removeResource(getId(mResourceManagerClient), resources);
+}
+
 status_t MediaCodec::start() {
     sp<AMessage> msg = new AMessage(kWhatStart, this);
 
@@ -1682,6 +1715,59 @@
     }
 }
 
+BatteryChecker::BatteryChecker(const sp<AMessage> &msg, int64_t timeoutUs)
+    : mTimeoutUs(timeoutUs)
+    , mLastActivityTimeUs(-1ll)
+    , mBatteryStatNotified(false)
+    , mBatteryCheckerGeneration(0)
+    , mIsExecuting(false)
+    , mBatteryCheckerMsg(msg) {}
+
+void BatteryChecker::onCodecActivity(std::function<void()> batteryOnCb) {
+    if (!isExecuting()) {
+        // ignore if not executing
+        return;
+    }
+    if (!mBatteryStatNotified) {
+        batteryOnCb();
+        mBatteryStatNotified = true;
+        sp<AMessage> msg = mBatteryCheckerMsg->dup();
+        msg->setInt32("generation", mBatteryCheckerGeneration);
+
+        // post checker and clear last activity time
+        msg->post(mTimeoutUs);
+        mLastActivityTimeUs = -1ll;
+    } else {
+        // update last activity time
+        mLastActivityTimeUs = ALooper::GetNowUs();
+    }
+}
+
+void BatteryChecker::onCheckBatteryTimer(
+        const sp<AMessage> &msg, std::function<void()> batteryOffCb) {
+    // ignore if this checker already expired because the client resource was removed
+    int32_t generation;
+    if (!msg->findInt32("generation", &generation)
+            || generation != mBatteryCheckerGeneration) {
+        return;
+    }
+
+    if (mLastActivityTimeUs < 0ll) {
+        // timed out inactive, do not repost checker
+        batteryOffCb();
+        mBatteryStatNotified = false;
+    } else {
+        // repost checker and clear last activity time
+        msg->post(mTimeoutUs + mLastActivityTimeUs - ALooper::GetNowUs());
+        mLastActivityTimeUs = -1ll;
+    }
+}
+
+void BatteryChecker::onClientRemoved() {
+    mBatteryStatNotified = false;
+    mBatteryCheckerGeneration++;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 void MediaCodec::cancelPendingDequeueOperations() {
@@ -2318,7 +2404,12 @@
 
                     mFlags &= ~kFlagIsComponentAllocated;
 
-                    mResourceManagerService->removeResource(getId(mResourceManagerClient));
+                    // off since we're removing all resources including the battery on
+                    if (mBatteryChecker != nullptr) {
+                        mBatteryChecker->onClientRemoved();
+                    }
+
+                    mResourceManagerService->removeClient(getId(mResourceManagerClient));
 
                     (new AMessage)->postReply(mReplyID);
                     break;
@@ -3029,6 +3120,16 @@
             break;
         }
 
+        case kWhatCheckBatteryStats:
+        {
+            if (mBatteryChecker != nullptr) {
+                mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
+                    removeResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+                });
+            }
+            break;
+        }
+
         default:
             TRESPASS();
     }
@@ -3125,9 +3226,11 @@
 
     mState = newState;
 
-    cancelPendingDequeueOperations();
+    if (mBatteryChecker != nullptr) {
+        mBatteryChecker->setExecuting(isExecuting());
+    }
 
-    updateBatteryStat();
+    cancelPendingDequeueOperations();
 }
 
 void MediaCodec::returnBuffersToCodec(bool isReclaim) {
@@ -3631,20 +3734,6 @@
     return OK;
 }
 
-void MediaCodec::updateBatteryStat() {
-    if (!mIsVideo) {
-        return;
-    }
-
-    if (mState == CONFIGURED && !mBatteryStatNotified) {
-        BatteryNotifier::getInstance().noteStartVideo(mUid);
-        mBatteryStatNotified = true;
-    } else if (mState == UNINITIALIZED && mBatteryStatNotified) {
-        BatteryNotifier::getInstance().noteStopVideo(mUid);
-        mBatteryStatNotified = false;
-    }
-}
-
 std::string MediaCodec::stateString(State state) {
     const char *rval = NULL;
     char rawbuffer[16]; // room for "%d"
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 4c8be1f..120f354 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -71,9 +71,6 @@
 
     ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
 
-    // initialize source decryption if needed
-    source->DrmInitialization(nullptr /* mime */);
-
     void *meta = nullptr;
     void *creator = NULL;
     FreeMetaFunc freeMeta = nullptr;
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index 96818eb..c1b270c 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -7,6 +7,9 @@
           "include-annotation": "android.platform.test.annotations.RequiresDevice"
         }
       ]
+    },
+    {
+       "name": "BatteryChecker_test"
     }
   ]
 }
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index c20dfe2..02e8ab5 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -689,6 +689,7 @@
         { "temporal-layer-id", kKeyTemporalLayerId },
         { "thumbnail-width", kKeyThumbnailWidth },
         { "thumbnail-height", kKeyThumbnailHeight },
+        { "track-id", kKeyTrackID },
         { "valid-samples", kKeyValidSamples },
     }
 };
@@ -896,12 +897,6 @@
         msg->setInt32("is-sync-frame", 1);
     }
 
-    // this only needs to be translated from meta to message as it is an extractor key
-    int32_t trackID;
-    if (meta->findInt32(kKeyTrackID, &trackID)) {
-        msg->setInt32("track-id", trackID);
-    }
-
     const char *lang;
     if (meta->findCString(kKeyMediaLanguage, &lang)) {
         msg->setString("language", lang);
diff --git a/media/libstagefright/codecs/amrnb/common/Android.bp b/media/libstagefright/codecs/amrnb/common/Android.bp
index 772ebf9..ea8b073 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.bp
+++ b/media/libstagefright/codecs/amrnb/common/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
     name: "libstagefright_amrnb_common",
     vendor_available: true,
 
diff --git a/media/libstagefright/include/CallbackDataSource.h b/media/libstagefright/include/CallbackDataSource.h
index 9f413cd..e428494 100644
--- a/media/libstagefright/include/CallbackDataSource.h
+++ b/media/libstagefright/include/CallbackDataSource.h
@@ -41,7 +41,6 @@
     virtual String8 toString() {
         return mName;
     }
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
     virtual sp<IDataSource> getIDataSource() const;
 
 private:
@@ -70,7 +69,6 @@
     virtual String8 toString() {
         return mName;
     }
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL);
     virtual sp<IDataSource> getIDataSource() const;
 
 private:
diff --git a/media/libstagefright/include/ThrottledSource.h b/media/libstagefright/include/ThrottledSource.h
index 71e62f7..5ae0653 100644
--- a/media/libstagefright/include/ThrottledSource.h
+++ b/media/libstagefright/include/ThrottledSource.h
@@ -54,10 +54,6 @@
         return mSource->reconnectAtOffset(offset);
     }
 
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime = NULL) {
-        return mSource->DrmInitialization(mime);
-    }
-
     virtual String8 getMIMEType() const {
         return mSource->getMIMEType();
     }
diff --git a/media/libstagefright/include/media/stagefright/BatteryChecker.h b/media/libstagefright/include/media/stagefright/BatteryChecker.h
new file mode 100644
index 0000000..2ec4ac0
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/BatteryChecker.h
@@ -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.
+ */
+
+#ifndef BATTERY_CHECKER_H_
+#define BATTERY_CHECKER_H_
+
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+struct BatteryChecker : public RefBase {
+    BatteryChecker(const sp<AMessage> &msg, int64_t timeout = 3000000ll);
+
+    void setExecuting(bool executing) { mIsExecuting = executing; }
+    void onCodecActivity(std::function<void()> batteryOnCb);
+    void onCheckBatteryTimer(const sp<AMessage>& msg, std::function<void()> batteryOffCb);
+    void onClientRemoved();
+
+private:
+    const int64_t mTimeoutUs;
+    int64_t mLastActivityTimeUs;
+    bool mBatteryStatNotified;
+    int32_t mBatteryCheckerGeneration;
+    bool mIsExecuting;
+    sp<AMessage> mBatteryCheckerMsg;
+
+    bool isExecuting() { return mIsExecuting; }
+
+    DISALLOW_EVIL_CONSTRUCTORS(BatteryChecker);
+};
+
+}  // namespace android
+
+#endif // BATTERY_CHECKER_H_
diff --git a/media/libstagefright/include/media/stagefright/DataSource.h b/media/libstagefright/include/media/stagefright/DataSource.h
index 1f7a473..83d3e5d 100644
--- a/media/libstagefright/include/media/stagefright/DataSource.h
+++ b/media/libstagefright/include/media/stagefright/DataSource.h
@@ -52,11 +52,6 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    // for DRM
-    virtual sp<DecryptHandle> DrmInitialization(const char * /*mime*/ = NULL) {
-        return NULL;
-    }
-
     virtual String8 getUri() {
         return String8();
     }
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 89cca63..cd30347 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -36,6 +36,7 @@
 struct AMessage;
 struct AReplyToken;
 struct AString;
+struct BatteryChecker;
 class BufferChannelBase;
 struct CodecBase;
 class IBatteryStats;
@@ -257,6 +258,7 @@
         kWhatSetCallback                    = 'setC',
         kWhatSetNotification                = 'setN',
         kWhatDrmReleaseCrypto               = 'rDrm',
+        kWhatCheckBatteryStats              = 'chkB',
     };
 
     enum {
@@ -283,7 +285,7 @@
     };
 
     struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {
-        ResourceManagerServiceProxy(pid_t pid);
+        ResourceManagerServiceProxy(pid_t pid, uid_t uid);
         ~ResourceManagerServiceProxy();
 
         void init();
@@ -296,7 +298,11 @@
                 const sp<IResourceManagerClient> &client,
                 const Vector<MediaResource> &resources);
 
-        void removeResource(int64_t clientId);
+        void removeResource(
+                int64_t clientId,
+                const Vector<MediaResource> &resources);
+
+        void removeClient(int64_t clientId);
 
         bool reclaimResource(const Vector<MediaResource> &resources);
 
@@ -304,6 +310,7 @@
         Mutex mLock;
         sp<IResourceManagerService> mService;
         pid_t mPid;
+        uid_t mUid;
     };
 
     State mState;
@@ -335,7 +342,6 @@
     sp<IResourceManagerClient> mResourceManagerClient;
     sp<ResourceManagerServiceProxy> mResourceManagerService;
 
-    bool mBatteryStatNotified;
     bool mIsVideo;
     int32_t mVideoWidth;
     int32_t mVideoHeight;
@@ -425,11 +431,11 @@
     status_t onSetParameters(const sp<AMessage> &params);
 
     status_t amendOutputFormatWithCodecSpecificData(const sp<MediaCodecBuffer> &buffer);
-    void updateBatteryStat();
     bool isExecuting() const;
 
     uint64_t getGraphicBufferSize();
     void addResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
+    void removeResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
     void requestCpuBoostIfNeeded();
 
     bool hasPendingBuffer(int portIndex);
@@ -458,6 +464,8 @@
     Mutex mLatencyLock;
     int64_t mLatencyUnknown;    // buffers for which we couldn't calculate latency
 
+    sp<BatteryChecker> mBatteryChecker;
+
     void statsBufferSent(int64_t presentationUs);
     void statsBufferReceived(int64_t presentationUs);
 
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index e191e6a..5a69bd7 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -66,9 +66,6 @@
     virtual String8 toString()  {
         return mName;
     }
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime) {
-        return mSource->DrmInitialization(mime);
-    }
 
 private:
     enum {
diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp
index be10fdc..a7f94c1 100644
--- a/media/libstagefright/tests/Android.bp
+++ b/media/libstagefright/tests/Android.bp
@@ -27,3 +27,21 @@
         "-Wall",
     ],
 }
+
+cc_test {
+    name: "BatteryChecker_test",
+    srcs: ["BatteryChecker_test.cpp"],
+    test_suites: ["device-tests"],
+
+    shared_libs: [
+        "libstagefright",
+        "libstagefright_foundation",
+        "libutils",
+        "liblog",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
\ No newline at end of file
diff --git a/media/libstagefright/tests/BatteryChecker_test.cpp b/media/libstagefright/tests/BatteryChecker_test.cpp
new file mode 100644
index 0000000..0c5ee9b
--- /dev/null
+++ b/media/libstagefright/tests/BatteryChecker_test.cpp
@@ -0,0 +1,242 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "BatteryChecker_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/BatteryChecker.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AHandler.h>
+
+#include <vector>
+
+namespace android {
+
+static const int kBatteryTimeoutUs = 1000000ll; // 1 seconds
+static const int kTestMarginUs = 50000ll; // 50ms
+static const int kWaitStatusChangeUs = kBatteryTimeoutUs + kTestMarginUs;
+static const int kSparseFrameIntervalUs = kBatteryTimeoutUs - kTestMarginUs;
+
+class BatteryCheckerTestHandler : public AHandler {
+    enum EventType {
+        // Events simulating MediaCodec
+        kWhatStart = 0,             // codec entering executing state
+        kWhatStop,                  // codec exiting executing state
+        kWhatActivity,        // codec queue input or dequeue output
+        kWhatReleased,     // codec released
+        kWhatCheckpoint,        // test checkpoing with expected values on On/Off
+
+        // Message for battery checker monitor (not for testing through runTest())
+        kWhatBatteryChecker,
+    };
+
+    struct Operation {
+        int32_t event;
+        int64_t delay = 0;
+        uint32_t repeatCount = 0;
+        int32_t expectedOnCounter = 0;
+        int32_t expectedOffCounter = 0;
+    };
+
+    std::vector<Operation> mOps;
+    sp<BatteryChecker> mBatteryChecker;
+    int32_t mOnCounter;
+    int32_t mOffCounter;
+    Condition mDone;
+    Mutex mLock;
+
+    BatteryCheckerTestHandler() : mOnCounter(0), mOffCounter(0) {}
+
+    void runTest(const std::vector<Operation> &ops, int64_t timeoutUs) {
+        mOps = ops;
+
+        mBatteryChecker = new BatteryChecker(
+                new AMessage(kWhatBatteryChecker, this), kBatteryTimeoutUs);
+
+        (new AMessage(ops[0].event, this))->post();
+
+        // wait for done
+        AutoMutex lock(mLock);
+        EXPECT_NE(TIMED_OUT, mDone.waitRelative(mLock, timeoutUs * 1000ll));
+    }
+
+    virtual void onMessageReceived(const sp<AMessage> &msg);
+
+    friend class BatteryCheckerTest;
+};
+
+class BatteryCheckerTest : public ::testing::Test {
+public:
+    BatteryCheckerTest()
+        : mLooper(new ALooper)
+        , mHandler(new BatteryCheckerTestHandler()) {
+        mLooper->setName("BatterCheckerLooper");
+        mLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+        mLooper->registerHandler(mHandler);
+    }
+
+protected:
+    using EventType = BatteryCheckerTestHandler::EventType;
+    using Operation = BatteryCheckerTestHandler::Operation;
+
+    virtual ~BatteryCheckerTest() {
+        mLooper->stop();
+        mLooper->unregisterHandler(mHandler->id());
+    }
+
+    void runTest(const std::vector<Operation> &ops, int64_t timeoutUs) {
+        mHandler->runTest(ops, timeoutUs);
+    }
+
+    sp<ALooper> mLooper;
+    sp<BatteryCheckerTestHandler> mHandler;
+};
+
+void BatteryCheckerTestHandler::onMessageReceived(const sp<AMessage> &msg) {
+    switch(msg->what()) {
+    case kWhatStart:
+        mBatteryChecker->setExecuting(true);
+        break;
+    case kWhatStop:
+        mBatteryChecker->setExecuting(false);
+        break;
+    case kWhatActivity:
+        mBatteryChecker->onCodecActivity([this] () { mOnCounter++; });
+        break;
+    case kWhatReleased:
+        mBatteryChecker->onClientRemoved();
+        break;
+    case kWhatBatteryChecker:
+        mBatteryChecker->onCheckBatteryTimer(msg, [this] () { mOffCounter++;  });
+        break;
+    case kWhatCheckpoint:
+        // verify ON/OFF state and total events
+        EXPECT_EQ(mOnCounter, mOps[0].expectedOnCounter);
+        EXPECT_EQ(mOffCounter, mOps[0].expectedOffCounter);
+        break;
+    default:
+        TRESPASS();
+    }
+    if (msg->what() != kWhatBatteryChecker) {
+        EXPECT_EQ(msg->what(), mOps[0].event);
+        // post next message
+        if (!mOps[0].repeatCount) {
+            mOps.erase(mOps.begin());
+        } else {
+            mOps[0].repeatCount--;
+        }
+        int64_t duration = mOps[0].delay;
+        if (!mOps.empty()) {
+            (new AMessage(mOps[0].event, this))->post(duration);
+        } else {
+            AutoMutex lock(mLock);
+            mDone.signal();
+        }
+    }
+}
+
+TEST_F(BatteryCheckerTest, testNormalOperations) {
+    runTest({
+        {EventType::kWhatStart,        0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 0, 0},
+        {EventType::kWhatActivity,     33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},                 // ON
+        {EventType::kWhatActivity,     33333ll, 2*kWaitStatusChangeUs/33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},
+        {EventType::kWhatCheckpoint,   kWaitStatusChangeUs, 0, 1, 1}, // OFF
+    }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testPauseResume) {
+    runTest({
+        {EventType::kWhatStart,        0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 0, 0},
+        {EventType::kWhatActivity,     33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},                 // ON
+        {EventType::kWhatCheckpoint,   kWaitStatusChangeUs, 0, 1, 1}, // OFF
+        {EventType::kWhatActivity,     33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 2, 1},                 // ON
+        {EventType::kWhatCheckpoint,   kWaitStatusChangeUs, 0, 2, 2}, // OFF
+    }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testClientRemovedAndRestart) {
+    runTest({
+        {EventType::kWhatStart,        0ll},
+        {EventType::kWhatActivity,     33333ll, kWaitStatusChangeUs/33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},
+
+        // stop executing state itself shouldn't trigger any calls
+        {EventType::kWhatStop,         0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},
+
+        // release shouldn't trigger any calls either,
+        // client resource will be removed entirely
+        {EventType::kWhatReleased,     0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},
+        {EventType::kWhatCheckpoint,   kWaitStatusChangeUs, 0, 1, 0},
+
+        // start pushing buffers again, On should be received without any Off
+        {EventType::kWhatStart,        0ll},
+        {EventType::kWhatActivity,     33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 2, 0},
+
+        // double check that only new checker msg triggers OFF,
+        // left-over checker msg from stale generate discarded
+        {EventType::kWhatCheckpoint,   kWaitStatusChangeUs, 0, 2, 1},
+    }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testActivityWhileNotExecuting) {
+    runTest({
+        // activity before start shouldn't trigger
+        {EventType::kWhatActivity,     0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 0, 0},
+
+        {EventType::kWhatStart,        0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 0, 0},
+
+        // activity after start before stop should trigger
+        {EventType::kWhatActivity,     33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},
+
+        // stop executing state itself shouldn't trigger any calls
+        {EventType::kWhatStop,         0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},
+
+        // keep pushing another 3 seconds after stop, expected to OFF
+        {EventType::kWhatActivity,     33333ll, kWaitStatusChangeUs/33333ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 1},
+    }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testSparseActivity) {
+    runTest({
+        {EventType::kWhatStart,        0ll},
+        {EventType::kWhatCheckpoint,   0ll, 0, 0, 0},
+
+        // activity arrives sparsely with interval only slightly small than timeout
+        // should only trigger 1 ON
+        {EventType::kWhatActivity,     kSparseFrameIntervalUs, 2},
+        {EventType::kWhatCheckpoint,   0ll, 0, 1, 0},
+        {EventType::kWhatCheckpoint,   kSparseFrameIntervalUs, 0, 1, 0},
+        {EventType::kWhatCheckpoint,   kTestMarginUs, 0, 1, 1}, // OFF
+    }, 10000000ll);
+}
+} // namespace android
diff --git a/media/libstagefright/tests/writer/Android.bp b/media/libstagefright/tests/writer/Android.bp
new file mode 100644
index 0000000..7e169cb
--- /dev/null
+++ b/media/libstagefright/tests/writer/Android.bp
@@ -0,0 +1,58 @@
+/*
+ * 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: "writerTest",
+    gtest: true,
+
+    srcs: [
+        "WriterUtility.cpp",
+        "WriterTest.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libstagefright_webm",
+        "libdatasource",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libstagefright_esds",
+        "libogg",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/tests/writer/README.md b/media/libstagefright/tests/writer/README.md
new file mode 100644
index 0000000..52db6f0
--- /dev/null
+++ b/media/libstagefright/tests/writer/README.md
@@ -0,0 +1,30 @@
+## Media Testing ##
+---
+#### Writer :
+The Writer Test Suite validates the writers available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+mmm frameworks/av/media/libstagefright/tests/writer/
+```
+
+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/writerTest/writerTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+
+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.
+```
+adb push  $ANDROID_BUILD_TOP/frameworks/av/media/codec2/hidl/1.0/vts/functional/res /sdcard/
+```
+
+usage: writerTest -P \<path_to_res_folder\>
+```
+adb shell /data/local/tmp/writerTest -P /sdcard/res/
+```
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
new file mode 100644
index 0000000..d68438c
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -0,0 +1,400 @@
+/*
+ * 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 "WriterTest"
+#include <utils/Log.h>
+
+#include <fstream>
+#include <iostream>
+
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/mediarecorder.h>
+
+#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 <webm/WebmWriter.h>
+
+#include "WriterTestEnvironment.h"
+#include "WriterUtility.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/writer.out"
+
+static WriterTestEnvironment *gEnv = nullptr;
+
+struct configFormat {
+    char mime[128];
+    int32_t width;
+    int32_t height;
+    int32_t sampleRate;
+    int32_t channelCount;
+};
+
+// LookUpTable of clips and metadata for component testing
+static const struct InputData {
+    const char *mime;
+    string inputFile;
+    string info;
+    int32_t firstParam;
+    int32_t secondParam;
+    bool isAudio;
+} kInputData[] = {
+        {MEDIA_MIMETYPE_AUDIO_OPUS, "bbb_opus_stereo_128kbps_48000hz.opus",
+         "bbb_opus_stereo_128kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_AAC, "bbb_aac_stereo_128kbps_48000hz.aac",
+         "bbb_aac_stereo_128kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_AAC_ADTS, "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.adts",
+         "Mps_2_c2_fr1_Sc1_Dc2_0x03_raw.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_AMR_NB, "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+         "sine_amrnb_1ch_12kbps_8000hz.info", 8000, 1, true},
+        {MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+         "bbb_amrwb_1ch_14kbps_16000hz.info", 16000, 1, true},
+        {MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_vorbis_stereo_128kbps_48000hz.vorbis",
+         "bbb_vorbis_stereo_128kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_AUDIO_FLAC, "bbb_flac_stereo_680kbps_48000hz.flac",
+         "bbb_flac_stereo_680kbps_48000hz.info", 48000, 2, true},
+        {MEDIA_MIMETYPE_VIDEO_VP9, "bbb_vp9_176x144_285kbps_60fps.vp9",
+         "bbb_vp9_176x144_285kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_VP8, "bbb_vp8_176x144_240kbps_60fps.vp8",
+         "bbb_vp8_176x144_240kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_AVC, "bbb_avc_176x144_300kbps_60fps.h264",
+         "bbb_avc_176x144_300kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_HEVC, "bbb_hevc_176x144_176kbps_60fps.hevc",
+         "bbb_hevc_176x144_176kbps_60fps.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_AV1, "bbb_av1_176_144.av1", "bbb_av1_176_144.info", 176, 144, false},
+        {MEDIA_MIMETYPE_VIDEO_H263, "bbb_h263_352x288_300kbps_12fps.h263",
+         "bbb_h263_352x288_300kbps_12fps.info", 352, 288, false},
+        {MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_mpeg4_352x288_512kbps_30fps.m4v",
+         "bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
+};
+
+class WriterTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+  public:
+    virtual void SetUp() override {
+        mNumCsds = 0;
+        mInputFrameId = 0;
+        mWriterName = unknown_comp;
+        mDisableTest = false;
+
+        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];
+        }
+        if (mWriterName == standardWriters::unknown_comp) {
+            cout << "[   WARN   ] Test Skipped. No specific writer mentioned\n";
+            mDisableTest = true;
+        }
+    }
+
+    virtual void TearDown() override {
+        mWriter.clear();
+        mFileMeta.clear();
+        mBufferInfo.clear();
+        if (mInputStream) mInputStream.close();
+    }
+
+    void getInputBufferInfo(string inputFileName, string inputInfo);
+
+    int32_t createWriter(int32_t fd);
+
+    int32_t addWriterSource(bool isAudio, configFormat params);
+
+    enum standardWriters {
+        OGG,
+        AAC,
+        AAC_ADTS,
+        WEBM,
+        MPEG4,
+        AMR_NB,
+        AMR_WB,
+        MPEG2TS,
+        unknown_comp,
+    };
+
+    standardWriters mWriterName;
+    sp<MediaWriter> mWriter;
+    sp<MetaData> mFileMeta;
+    sp<MediaAdapter> mCurrentTrack;
+
+    bool mDisableTest;
+    int32_t mNumCsds;
+    int32_t mInputFrameId;
+    ifstream mInputStream;
+    vector<BufferInfo> mBufferInfo;
+};
+
+void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo) {
+    std::ifstream eleInfo;
+    eleInfo.open(inputInfo.c_str());
+    CHECK_EQ(eleInfo.is_open(), true);
+    int32_t bytesCount = 0;
+    uint32_t flags = 0;
+    int64_t timestamp = 0;
+    while (1) {
+        if (!(eleInfo >> bytesCount)) break;
+        eleInfo >> flags;
+        eleInfo >> timestamp;
+        mBufferInfo.push_back({bytesCount, flags, timestamp});
+        if (flags == CODEC_CONFIG_FLAG) mNumCsds++;
+    }
+    eleInfo.close();
+    mInputStream.open(inputFileName.c_str(), std::ifstream::binary);
+    CHECK_EQ(mInputStream.is_open(), true);
+}
+
+int32_t WriterTest::createWriter(int32_t fd) {
+    mFileMeta = new MetaData;
+    switch (mWriterName) {
+        case OGG:
+            mWriter = new OggWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
+            break;
+        case AAC:
+            mWriter = new AACWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
+            break;
+        case AAC_ADTS:
+            mWriter = new AACWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
+            break;
+        case WEBM:
+            mWriter = new WebmWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
+            break;
+        case MPEG4:
+            mWriter = new MPEG4Writer(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
+            break;
+        case AMR_NB:
+            mWriter = new AMRWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
+            break;
+        case AMR_WB:
+            mWriter = new AMRWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
+            break;
+        case MPEG2TS:
+            mWriter = new MPEG2TSWriter(fd);
+            mFileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
+            break;
+        default:
+            return -1;
+    }
+    if (mWriter == nullptr) return -1;
+    mFileMeta->setInt32(kKeyRealTimeRecording, false);
+    return 0;
+}
+
+int32_t WriterTest::addWriterSource(bool isAudio, configFormat params) {
+    if (mInputFrameId) return -1;
+    sp<AMessage> format = new AMessage;
+    if (mInputStream.is_open()) {
+        format->setString("mime", params.mime);
+        if (isAudio) {
+            format->setInt32("channel-count", params.channelCount);
+            format->setInt32("sample-rate", params.sampleRate);
+        } else {
+            format->setInt32("width", params.width);
+            format->setInt32("height", params.height);
+        }
+
+        int32_t status =
+                writeHeaderBuffers(mInputStream, mBufferInfo, mInputFrameId, format, mNumCsds);
+        if (status != 0) return -1;
+    }
+    sp<MetaData> trackMeta = new MetaData;
+    convertMessageToMetaData(format, trackMeta);
+    mCurrentTrack = new MediaAdapter(trackMeta);
+    status_t result = mWriter->addSource(mCurrentTrack);
+    return result;
+}
+
+void getFileDetails(string &inputFilePath, string &info, configFormat &params, bool &isAudio,
+                    int32_t streamIndex = 0) {
+    if (streamIndex >= sizeof(kInputData) / sizeof(kInputData[0])) {
+        return;
+    }
+    inputFilePath += kInputData[streamIndex].inputFile;
+    info += kInputData[streamIndex].info;
+    strcpy(params.mime, kInputData[streamIndex].mime);
+    isAudio = kInputData[streamIndex].isAudio;
+    if (isAudio) {
+        params.sampleRate = kInputData[streamIndex].firstParam;
+        params.channelCount = kInputData[streamIndex].secondParam;
+    } else {
+        params.width = kInputData[streamIndex].firstParam;
+        params.height = kInputData[streamIndex].secondParam;
+    }
+    return;
+}
+
+TEST_P(WriterTest, CreateWriterTest) {
+    if (mDisableTest) return;
+    ALOGV("Tests the creation of writers");
+
+    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;
+
+    // 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);
+    }
+}
+
+TEST_P(WriterTest, WriterTest) {
+    if (mDisableTest) return;
+    ALOGV("Checks if for a given input, a valid muxed file has been created or not");
+
+    string writerFormat = GetParam().first;
+    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;
+    int32_t status = createWriter(fd);
+    if (status) {
+        cout << "Failed to create writer for output format:" << writerFormat << "\n";
+        ASSERT_TRUE(false);
+    }
+    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;
+    }
+    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()));
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+                                 mBufferInfo.size());
+    mCurrentTrack->stop();
+    if (status) {
+        cout << writerFormat << " writer failed \n";
+        mWriter->stop();
+        ASSERT_TRUE(false);
+    }
+    CHECK_EQ((status_t)OK, mWriter->stop());
+    close(fd);
+}
+
+TEST_P(WriterTest, PauseWriterTest) {
+    if (mDisableTest) return;
+    ALOGV("Validates the pause() api of writers");
+
+    string writerFormat = GetParam().first;
+    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;
+    int32_t status = createWriter(fd);
+    if (status) {
+        cout << "Failed to create writer for output format:" << writerFormat << "\n";
+        ASSERT_TRUE(false);
+    }
+    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;
+    }
+    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()));
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+                                 mBufferInfo.size() / 4);
+    if (status) {
+        cout << writerFormat << " writer failed \n";
+        mCurrentTrack->stop();
+        mWriter->stop();
+        ASSERT_TRUE(false);
+    }
+
+    bool isPaused = false;
+    if ((mWriterName != standardWriters::MPEG2TS) && (mWriterName != standardWriters::MPEG4)) {
+        CHECK_EQ((status_t)OK, mWriter->pause());
+        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,
+                                  mInputFrameId, numFramesPaused, isPaused);
+    if (isPaused) {
+        CHECK_EQ((status_t)OK, mWriter->start(mFileMeta.get()));
+    }
+    status |= sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack,
+                                  mInputFrameId, mBufferInfo.size());
+    mCurrentTrack->stop();
+    if (status) {
+        cout << writerFormat << " writer failed \n";
+        mWriter->stop();
+        ASSERT_TRUE(false);
+    }
+    CHECK_EQ((status_t)OK, mWriter->stop());
+    close(fd);
+}
+
+// TODO: (b/144476164)
+// Add AAC_ADTS, FLAC, AV1 input
+INSTANTIATE_TEST_SUITE_P(WriterTestAll, WriterTest,
+                         ::testing::Values(make_pair("ogg", 0), make_pair("webm", 0),
+                                           make_pair("aac", 1), make_pair("mpeg4", 1),
+                                           make_pair("amrnb", 3), make_pair("amrwb", 4),
+                                           make_pair("webm", 5), make_pair("webm", 7),
+                                           make_pair("webm", 8), make_pair("mpeg4", 9),
+                                           make_pair("mpeg4", 10), make_pair("mpeg4", 12),
+                                           make_pair("mpeg4", 13), make_pair("mpeg2Ts", 1),
+                                           make_pair("mpeg2Ts", 9)));
+
+int main(int argc, char **argv) {
+    gEnv = new WriterTestEnvironment();
+    ::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/tests/writer/WriterTestEnvironment.h b/media/libstagefright/tests/writer/WriterTestEnvironment.h
new file mode 100644
index 0000000..34c2baa
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterTestEnvironment.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 __WRITER_TEST_ENVIRONMENT_H__
+#define __WRITER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class WriterTestEnvironment : public ::testing::Environment {
+  public:
+    WriterTestEnvironment() : res("/sdcard/media/") {}
+
+    // 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 WriterTestEnvironment::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  // __WRITER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/tests/writer/WriterUtility.cpp b/media/libstagefright/tests/writer/WriterUtility.cpp
new file mode 100644
index 0000000..2ba90a0
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "WriterUtility"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBuffer.h>
+
+#include "WriterUtility.h"
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                            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;
+        int32_t size = bufferInfo[inputFrameId].size;
+        char *data = (char *)malloc(size);
+        if (!data) {
+            ALOGE("Insufficient memeory to read input");
+            return -1;
+        }
+
+        inputStream.read(data, size);
+        CHECK_EQ(inputStream.gcount(), size);
+
+        sp<ABuffer> buffer = new ABuffer((void *)data, size);
+        if (buffer.get() == nullptr) {
+            ALOGE("sendBuffersToWriter() got a nullptr buffer.");
+            return -1;
+        }
+        MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
+        // Released in MediaAdapter::signalBufferReturned().
+        mediaBuffer->add_ref();
+        mediaBuffer->set_range(buffer->offset(), buffer->size());
+
+        MetaDataBase &sampleMetaData = mediaBuffer->meta_data();
+        sampleMetaData.setInt64(kKeyTime, bufferInfo[inputFrameId].timeUs);
+        // Just set the kKeyDecodingTime as the presentation time for now.
+        sampleMetaData.setInt64(kKeyDecodingTime, bufferInfo[inputFrameId].timeUs);
+
+        if (bufferInfo[inputFrameId].flags == 1) {
+            sampleMetaData.setInt32(kKeyIsSyncFrame, true);
+        }
+
+        // This pushBuffer will wait until the mediaBuffer is consumed.
+        int status = currentTrack->pushBuffer(mediaBuffer);
+        free(data);
+        inputFrameId++;
+
+        if (OK != status) {
+            if (!isPaused) return status;
+            else {
+                ALOGD("Writer is in paused state. Input buffers won't get consumed");
+                return 0;
+            }
+        }
+    }
+    return 0;
+}
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                           int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds) {
+    char csdName[kMaxCSDStrlen];
+    for (int csdId = 0; csdId < numCsds; csdId++) {
+        int32_t flags = bufferInfo[inputFrameId].flags;
+        if (flags == CODEC_CONFIG_FLAG) {
+            int32_t size = bufferInfo[inputFrameId].size;
+            char *data = (char *)malloc(size);
+            if (!data) {
+                ALOGE("Insufficient memeory to read input");
+                return -1;
+            }
+            inputStream.read(data, size);
+            CHECK_EQ(inputStream.gcount(), size);
+
+            sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy((void *)data, size);
+            if (csdBuffer.get() == nullptr || csdBuffer->base() == nullptr) {
+                return -1;
+            }
+            snprintf(csdName, sizeof(csdName), "csd-%d", csdId);
+            format->setBuffer(csdName, csdBuffer);
+            inputFrameId++;
+            free(data);
+        }
+    }
+    return 0;
+}
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
new file mode 100644
index 0000000..d402798
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -0,0 +1,50 @@
+/*
+ * 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 WRITER_UTILITY_H_
+#define WRITER_UTILITY_H_
+
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/MediaAdapter.h>
+
+using namespace android;
+using namespace std;
+
+#define CODEC_CONFIG_FLAG 32
+
+constexpr uint32_t kMaxCSDStrlen = 16;
+
+struct BufferInfo {
+    int32_t size;
+    uint32_t flags;
+    int64_t timeUs;
+};
+
+int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                            int32_t &inputFrameId, sp<MediaAdapter> &currentTrack, int32_t offset,
+                            int32_t range, bool isPaused = false);
+
+int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
+                           int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds);
+
+#endif  // WRITER_UTILITY_H_
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index 9d7c57d..16c8af8 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -138,7 +138,12 @@
 
   public class Variant {
     ctor public Variant();
+    method public java.util.List<media.codecs.Alias> getAlias_optional();
+    method public java.util.List<media.codecs.Quirk> getAttribute_optional();
+    method public java.util.List<media.codecs.Feature> getFeature_optional();
+    method public java.util.List<media.codecs.Limit> getLimit_optional();
     method public String getName();
+    method public java.util.List<media.codecs.Quirk> getQuirk_optional();
     method public void setName(String);
   }
 
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
index 63ec5d0..3b5681f 100644
--- a/media/libstagefright/xmlparser/media_codecs.xsd
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -107,6 +107,13 @@
         <xs:attribute name="value" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="Variant">
+        <xs:choice minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="Quirk" type="Quirk"/>
+            <xs:element name="Attribute" type="Quirk"/>
+            <xs:element name="Alias" type="Alias"/>
+            <xs:element name="Limit" type="Limit"/>
+            <xs:element name="Feature" type="Feature"/>
+        </xs:choice>
         <xs:attribute name="name" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="Setting">
diff --git a/media/mtp/IMtpHandle.h b/media/mtp/IMtpHandle.h
index fd14b18..0435e82 100644
--- a/media/mtp/IMtpHandle.h
+++ b/media/mtp/IMtpHandle.h
@@ -16,7 +16,7 @@
 #ifndef _IMTP_HANDLE_H
 #define _IMTP_HANDLE_H
 
-#include <linux/usb/f_mtp.h>
+#include "f_mtp.h"
 
 namespace android {
 
diff --git a/media/mtp/f_mtp.h b/media/mtp/f_mtp.h
new file mode 100644
index 0000000..22ec771
--- /dev/null
+++ b/media/mtp/f_mtp.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   To edit the content of this header, modify the corresponding
+ ***   source file (e.g. under external/kernel-headers/original/) then
+ ***   run bionic/libc/kernel/tools/update_all.py
+ ***
+ ***   Any manual change here will be lost the next time this script will
+ ***   be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_USB_F_MTP_H
+#define _UAPI_LINUX_USB_F_MTP_H
+#include <linux/ioctl.h>
+#include <linux/types.h>
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+struct mtp_file_range {
+  int fd;
+  loff_t offset;
+  int64_t length;
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  uint16_t command;
+  uint32_t transaction_id;
+};
+struct mtp_event {
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+  size_t length;
+  void * data;
+};
+#define MTP_SEND_FILE _IOW('M', 0, struct mtp_file_range)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define MTP_RECEIVE_FILE _IOW('M', 1, struct mtp_file_range)
+#define MTP_SEND_EVENT _IOW('M', 3, struct mtp_event)
+#define MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, struct mtp_file_range)
+#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 51b516a..af21a99 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -221,7 +221,13 @@
                          break;
                      }
 
-                     AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&format);
+                     // Here format is MediaCodec's internal copy of output format.
+                     // Make a copy since the client might modify it.
+                     sp<AMessage> copy;
+                     if (format != nullptr) {
+                         copy = format->dup();
+                     }
+                     AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&copy);
 
                      Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
                      if (mCodec->mAsyncCallbackUserData != NULL
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 60f3e8e..842216c 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -89,7 +89,7 @@
 };
 
 void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
-    if (!mEventListener && !mExpirationUpdateListener && !mKeysChangeListener) {
+    if (!mEventListener || !mExpirationUpdateListener || !mKeysChangeListener) {
         ALOGE("No listeners are specified");
         return;
     }
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index 1823fbc..8fb6a87 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -268,6 +268,9 @@
         int64_t timeoutUs) __INTRODUCED_IN(21);
 
 /**
+ * Returns the format of the codec's output.
+ * The caller must free the returned format.
+ *
  * Available since API level 21.
  */
 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*) __INTRODUCED_IN(21);
@@ -397,6 +400,7 @@
 /**
  * Get format of the buffer. The specified buffer index must have been previously obtained from
  * dequeueOutputBuffer.
+ * The caller must free the returned format.
  *
  * Available since API level 28.
  */
@@ -455,6 +459,7 @@
  * Call this after AMediaCodec_configure() returns successfully to get the input
  * format accepted by the codec. Do this to determine what optional configuration
  * parameters were supported by the codec.
+ * The caller must free the returned format.
  *
  * Available since API level 28.
  */
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index f666ad0..7531578 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -4,7 +4,7 @@
     AImageReader_acquireLatestImageAsync; # introduced=26
     AImageReader_acquireNextImage; # introduced=24
     AImageReader_acquireNextImageAsync; # introduced=26
-    AImageReader_getWindowNativeHandle; #vndk
+    AImageReader_getWindowNativeHandle; # llndk
     AImageReader_delete; # introduced=24
     AImageReader_getFormat; # introduced=24
     AImageReader_getHeight; # introduced=24
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 487ddb8..6627462 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -14,11 +14,11 @@
 
 To run the test suite for measuring performance of the native layer, follow the following steps:
 
-The binaries will be created in the following path : ${OUT}/data/nativetest64/
+The binaries will be created in the following path : $OUT/data/nativetest64/
 
-adb push $(OUT)/data/nativetest64/* /data/local/tmp/
+adb push $OUT/data/nativetest64/* /data/local/tmp/
 
-Eg. adb push $(OUT)/data/nativetest64/extractorTest/extractorTest /data/local/tmp/
+Eg. adb push $OUT/data/nativetest64/extractorTest/extractorTest /data/local/tmp/
 
 To run the binary, follow the commands mentioned below under each module.
 
@@ -78,13 +78,13 @@
 To run the test suite for measuring performance of the SDK APIs, follow the following steps:
 
 The apk will be created at the following path:
-${OUT}/testcases/MediaBenchmarkApp/arm64/
+$OUT/testcases/MediaBenchmarkTest/arm64/
 
 To get the resorce files for the test follow instructions given in [NDK](#NDK)
 
 For installing the apk, run the command:
 ```
-adb install -f -r ${OUT}/testcases/MediaBenchmarkApp/arm64/MediaBenchmarkApp.apk
+adb install -f -r $OUT/testcases/MediaBenchmarkTest/arm64/MediaBenchmarkTest.apk
 ```
 
 For running all the tests, run the command:
@@ -118,5 +118,30 @@
 The test encodes input stream and benchmarks the encoders available in SDK.
 ```
 adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.EncoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
 
+# Codec2
+To run the test suite for measuring performance of the codec2 layer, follow the following steps:
+
+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/* /data/local/tmp/
+Eg. adb push $(OUT)/data/nativetest64/C2DecoderTest/C2DecoderTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+adb push $(OUT)/data/nativetest/* /data/local/tmp/
+Eg. adb push $(OUT)/data/nativetest/C2DecoderTest/C2DecoderTest /data/local/tmp/
+
+To get the resource files for the test follow instructions given in [NDK](#NDK)
+
+## C2 Decoder
+
+The test decodes input stream and benchmarks the codec2 decoders available in device.
+
+Setup steps are same as [extractor](#extractor).
+
+```
+adb shell /data/local/tmp/C2DecoderTest -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 1da0102..babc329 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -24,6 +24,7 @@
     srcs: [
         "BenchmarkCommon.cpp",
         "Stats.cpp",
+        "utils/Timers.cpp",
     ],
 
     export_include_dirs: ["."],
@@ -49,7 +50,6 @@
     shared_libs: [
         "libmediandk",
         "liblog",
-        "libutils",
     ],
 
     cflags: [
@@ -58,6 +58,39 @@
     ]
 }
 
+cc_library_static {
+    name: "libmediabenchmark_codec2_common",
+    defaults: [
+        "libmediabenchmark_codec2_common-defaults",
+    ],
+
+    srcs: [
+        "BenchmarkC2Common.cpp",
+    ],
+
+    export_include_dirs: ["."],
+
+    ldflags: ["-Wl,-Bsymbolic"]
+}
+
+cc_defaults {
+    name: "libmediabenchmark_codec2_common-defaults",
+
+    defaults: [
+        "libmediabenchmark_common-defaults",
+        "libcodec2-hidl-client-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/codec2/hidl/client/include",
+    ],
+
+    shared_libs: [
+        "libcodec2_client",
+    ]
+}
+
 // public dependency for native implementation
 // to be used by code under media/benchmark/* only
 cc_defaults {
diff --git a/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp b/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp
new file mode 100644
index 0000000..622a0e1
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/BenchmarkC2Common.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "BenchmarkC2Common"
+
+#include "BenchmarkC2Common.h"
+
+int32_t BenchmarkC2Common::setupCodec2() {
+    ALOGV("In %s", __func__);
+    mClient = android::Codec2Client::CreateFromService("default");
+    if (!mClient) return -1;
+
+    std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+    if (!store) return -1;
+
+    c2_status_t status = store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator);
+    if (status != C2_OK) return status;
+
+    mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
+    if (!mLinearPool) return -1;
+
+    status = store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mGraphicAllocator);
+    if (status != C2_OK) return status;
+
+    mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++);
+    if (!mGraphicPool) return -1;
+
+    for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
+        mWorkQueue.emplace_back(new C2Work);
+    }
+    if (!mStats) mStats = new Stats();
+
+    return status;
+}
+
+vector<string> BenchmarkC2Common::getSupportedComponentList(bool isEncoder) {
+    // Get List of components from all known services
+    vector<string> codecList;
+    const std::vector<C2Component::Traits> listTraits = mClient->ListComponents();
+    if (listTraits.size() == 0)
+        ALOGE("ComponentInfo list empty.");
+    else {
+        for (size_t i = 0; i < listTraits.size(); i++) {
+            if (isEncoder && C2Component::KIND_ENCODER == listTraits[i].kind) {
+                codecList.push_back(listTraits[i].name);
+            } else if (!isEncoder && C2Component::KIND_DECODER == listTraits[i].kind) {
+                codecList.push_back(listTraits[i].name);
+            }
+        }
+    }
+    return codecList;
+}
+
+void BenchmarkC2Common::waitOnInputConsumption() {
+    typedef std::unique_lock<std::mutex> ULock;
+    uint32_t queueSize;
+    uint32_t maxRetry = 0;
+    {
+        ULock l(mQueueLock);
+        queueSize = mWorkQueue.size();
+    }
+    while ((maxRetry < MAX_RETRY) && (queueSize < MAX_INPUT_BUFFERS)) {
+        ULock l(mQueueLock);
+        if (queueSize != mWorkQueue.size()) {
+            queueSize = mWorkQueue.size();
+            maxRetry = 0;
+        } else {
+            mQueueCondition.wait_for(l, TIME_OUT);
+            maxRetry++;
+        }
+    }
+}
+
+void BenchmarkC2Common::handleWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
+    ALOGV("In %s", __func__);
+    mStats->addOutputTime();
+    for (std::unique_ptr<C2Work> &work : workItems) {
+        if (!work->worklets.empty()) {
+            if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
+                mEos = (work->worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM) !=
+                       0;
+                ALOGV("WorkDone: frameID received %d , mEos : %d",
+                      (int)work->worklets.front()->output.ordinal.frameIndex.peeku(), mEos);
+                work->input.buffers.clear();
+                work->worklets.clear();
+                {
+                    typedef std::unique_lock<std::mutex> ULock;
+                    ULock l(mQueueLock);
+                    mWorkQueue.push_back(std::move(work));
+                    mQueueCondition.notify_all();
+                }
+            }
+        }
+    }
+}
+
diff --git a/media/tests/benchmark/src/native/common/BenchmarkC2Common.h b/media/tests/benchmark/src/native/common/BenchmarkC2Common.h
new file mode 100644
index 0000000..d67758a
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/BenchmarkC2Common.h
@@ -0,0 +1,141 @@
+/*
+ * 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 __BENCHMARK_C2_COMMON_H__
+#define __BENCHMARK_C2_COMMON_H__
+
+#include "codec2/hidl/client.h"
+
+#include <C2Component.h>
+#include <C2Config.h>
+
+#include <hidl/HidlSupport.h>
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2BufferPriv.h>
+
+#include "BenchmarkCommon.h"
+
+#define MAX_RETRY 20
+#define TIME_OUT 400ms
+#define MAX_INPUT_BUFFERS 8
+
+using android::C2AllocatorIon;
+
+class LinearBuffer : public C2Buffer {
+  public:
+    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock> &block)
+        : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
+
+    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock> &block, size_t size)
+        : C2Buffer({block->share(block->offset(), size, ::C2Fence())}) {}
+};
+
+class GraphicBuffer : public C2Buffer {
+  public:
+    explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock> &block)
+        : C2Buffer({block->share(C2Rect(block->width(), block->height()), ::C2Fence())}) {}
+};
+
+/**
+ * Handle Callback functions onWorkDone(), onTripped(),
+ * onError(), onDeath(), onFramesRendered() for C2 Components
+ */
+struct CodecListener : public android::Codec2Client::Listener {
+  public:
+    CodecListener(
+            const std::function<void(std::list<std::unique_ptr<C2Work>> &workItems)> fn = nullptr)
+        : callBack(fn) {}
+    virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component> &comp,
+                            std::list<std::unique_ptr<C2Work>> &workItems) override {
+        ALOGV("onWorkDone called");
+        (void)comp;
+        if (callBack) callBack(workItems);
+    }
+
+    virtual void onTripped(
+            const std::weak_ptr<android::Codec2Client::Component> &comp,
+            const std::vector<std::shared_ptr<C2SettingResult>> &settingResults) override {
+        (void)comp;
+        (void)settingResults;
+    }
+
+    virtual void onError(const std::weak_ptr<android::Codec2Client::Component> &comp,
+                         uint32_t errorCode) override {
+        (void)comp;
+        ALOGV("onError called");
+        if (errorCode != 0) ALOGE("Error : %u", errorCode);
+    }
+
+    virtual void onDeath(const std::weak_ptr<android::Codec2Client::Component> &comp) override {
+        (void)comp;
+    }
+
+    virtual void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) override {
+        (void)frameIndex;
+        (void)arrayIndex;
+    }
+
+    virtual void onFrameRendered(uint64_t bufferQueueId, int32_t slotId,
+                                 int64_t timestampNs) override {
+        (void)bufferQueueId;
+        (void)slotId;
+        (void)timestampNs;
+    }
+
+    std::function<void(std::list<std::unique_ptr<C2Work>> &workItems)> callBack;
+};
+
+class BenchmarkC2Common {
+  public:
+    BenchmarkC2Common()
+        : mEos(false),
+          mStats(nullptr),
+          mClient(nullptr),
+          mBlockPoolId(0),
+          mLinearPool(nullptr),
+          mGraphicPool(nullptr),
+          mLinearAllocator(nullptr),
+          mGraphicAllocator(nullptr) {}
+
+    int32_t setupCodec2();
+
+    vector<string> getSupportedComponentList(bool isEncoder);
+
+    void waitOnInputConsumption();
+
+    // callback function to process onWorkDone received by Listener
+    void handleWorkDone(std::list<std::unique_ptr<C2Work>> &workItems);
+
+    bool mEos;
+  protected:
+    Stats *mStats;
+
+    std::shared_ptr<android::Codec2Client> mClient;
+
+    C2BlockPool::local_id_t mBlockPoolId;
+    std::shared_ptr<C2BlockPool> mLinearPool;
+    std::shared_ptr<C2BlockPool> mGraphicPool;
+    std::shared_ptr<C2Allocator> mLinearAllocator;
+    std::shared_ptr<C2Allocator> mGraphicAllocator;
+
+    std::mutex mQueueLock;
+    std::condition_variable mQueueCondition;
+    std::list<std::unique_ptr<C2Work>> mWorkQueue;
+};
+
+#endif  // __BENCHMARK_C2_COMMON_H__
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
index 5bdb48a..ab74508 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.cpp
@@ -56,10 +56,10 @@
 
 void OnErrorCB(AMediaCodec *codec, void *userdata, media_status_t err, int32_t actionCode,
                const char *detail) {
-    (void)codec;
-    ALOGV("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
+    ALOGE("OnErrorCB: err(%d), actionCode(%d), detail(%s)", err, actionCode, detail);
     CallBackHandle *self = (CallBackHandle *)userdata;
     self->mSawError = true;
+    self->mIOQueue.push([self, codec, err]() { self->onError(codec, err); });
 }
 
 AMediaCodec *createMediaCodec(AMediaFormat *format, const char *mime, string codecName,
diff --git a/media/tests/benchmark/src/native/common/BenchmarkCommon.h b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
index df16baf..8153a86 100644
--- a/media/tests/benchmark/src/native/common/BenchmarkCommon.h
+++ b/media/tests/benchmark/src/native/common/BenchmarkCommon.h
@@ -17,8 +17,6 @@
 #ifndef __BENCHMARK_COMMON_H__
 #define __BENCHMARK_COMMON_H__
 
-#include <utils/Log.h>
-
 #include <inttypes.h>
 #include <mutex>
 #include <queue>
@@ -89,6 +87,10 @@
         (void)codec;
         (void)format;
     }
+    virtual void onError(AMediaCodec *codec, media_status_t err) {
+        (void)codec;
+        (void)err;
+    }
     virtual void onOutputAvailable(AMediaCodec *codec, int32_t index,
                                    AMediaCodecBufferInfo *bufferInfo) {
         (void)codec;
diff --git a/media/tests/benchmark/src/native/common/Stats.cpp b/media/tests/benchmark/src/native/common/Stats.cpp
index 6bcd3ce..2d9bb31 100644
--- a/media/tests/benchmark/src/native/common/Stats.cpp
+++ b/media/tests/benchmark/src/native/common/Stats.cpp
@@ -19,7 +19,6 @@
 
 #include <iostream>
 #include <stdint.h>
-#include <utils/Log.h>
 
 #include "Stats.h"
 
diff --git a/media/tests/benchmark/src/native/common/Stats.h b/media/tests/benchmark/src/native/common/Stats.h
index 024319a..2f556ee 100644
--- a/media/tests/benchmark/src/native/common/Stats.h
+++ b/media/tests/benchmark/src/native/common/Stats.h
@@ -17,11 +17,28 @@
 #ifndef __STATS_H__
 #define __STATS_H__
 
+#include <android/log.h>
+
+#ifndef ALOG
+#define ALOG(priority, tag, ...) ((void)__android_log_print(ANDROID_##priority, tag, __VA_ARGS__))
+
+#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__)
+#if LOG_NDEBUG
+#define ALOGV(cond, ...)   ((void)0)
+#else
+#define ALOGV(...) ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#endif
+#endif  // ALOG
+
 #include <sys/time.h>
 #include <algorithm>
 #include <numeric>
 #include <vector>
-#include <utils/Timers.h>
+
+// Include local copy of Timers taken from system/core/libutils
+#include "utils/Timers.h"
 
 using namespace std;
 
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.cpp b/media/tests/benchmark/src/native/common/utils/Timers.cpp
new file mode 100644
index 0000000..1acbdb3
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+
+#define LOG_TAG "Timers"
+
+#include <limits.h>
+#include <time.h>
+
+#include "Timers.h"
+
+#if defined(__ANDROID__)
+nsecs_t systemTime(int clock) {
+    static const clockid_t clocks[] = {CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
+                                       CLOCK_THREAD_CPUTIME_ID, CLOCK_BOOTTIME};
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(clocks[clock], &t);
+    return nsecs_t(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
+#else
+nsecs_t systemTime(int /*clock*/) {
+    // Clock support varies widely across hosts. Mac OS doesn't support
+    // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
+    // is windows.
+    struct timeval t;
+    t.tv_sec = t.tv_usec = 0;
+    gettimeofday(&t, NULL);
+    return nsecs_t(t.tv_sec) * 1000000000LL + nsecs_t(t.tv_usec) * 1000LL;
+}
+#endif
+
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) {
+    nsecs_t timeoutDelayMillis;
+    if (timeoutTime > referenceTime) {
+        uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+        if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
+            timeoutDelayMillis = -1;
+        } else {
+            timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
+        }
+    } else {
+        timeoutDelayMillis = 0;
+    }
+    return (int)timeoutDelayMillis;
+}
diff --git a/media/tests/benchmark/src/native/common/utils/Timers.h b/media/tests/benchmark/src/native/common/utils/Timers.h
new file mode 100644
index 0000000..d643dcd
--- /dev/null
+++ b/media/tests/benchmark/src/native/common/utils/Timers.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005 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.
+ */
+
+//
+// Timer functions.
+//
+
+#ifndef _LIBS_UTILS_TIMERS_H
+#define _LIBS_UTILS_TIMERS_H
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+// ------------------------------------------------------------------
+// C API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int64_t nsecs_t;  // nano-seconds
+
+static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) {
+    return secs * 1000000000;
+}
+
+static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) {
+    return secs * 1000000;
+}
+
+static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) {
+    return secs * 1000;
+}
+
+static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) {
+    return secs / 1000000000;
+}
+
+static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) {
+    return secs / 1000000;
+}
+
+static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) {
+    return secs / 1000;
+}
+
+static inline nsecs_t s2ns(nsecs_t v) {
+    return seconds_to_nanoseconds(v);
+}
+static inline nsecs_t ms2ns(nsecs_t v) {
+    return milliseconds_to_nanoseconds(v);
+}
+static inline nsecs_t us2ns(nsecs_t v) {
+    return microseconds_to_nanoseconds(v);
+}
+static inline nsecs_t ns2s(nsecs_t v) {
+    return nanoseconds_to_seconds(v);
+}
+static inline nsecs_t ns2ms(nsecs_t v) {
+    return nanoseconds_to_milliseconds(v);
+}
+static inline nsecs_t ns2us(nsecs_t v) {
+    return nanoseconds_to_microseconds(v);
+}
+
+static inline nsecs_t seconds(nsecs_t v) {
+    return s2ns(v);
+}
+static inline nsecs_t milliseconds(nsecs_t v) {
+    return ms2ns(v);
+}
+static inline nsecs_t microseconds(nsecs_t v) {
+    return us2ns(v);
+}
+
+enum {
+    SYSTEM_TIME_REALTIME = 0,   // system-wide realtime clock
+    SYSTEM_TIME_MONOTONIC = 1,  // monotonic time since unspecified starting point
+    SYSTEM_TIME_PROCESS = 2,    // high-resolution per-process clock
+    SYSTEM_TIME_THREAD = 3,     // high-resolution per-thread clock
+    SYSTEM_TIME_BOOTTIME = 4    // same as SYSTEM_TIME_MONOTONIC, but including CPU suspend time
+};
+
+// return the system-time according to the specified clock
+#ifdef __cplusplus
+nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC);
+#else
+nsecs_t systemTime(int clock);
+#endif  // def __cplusplus
+
+/**
+ * Returns the number of milliseconds to wait between the reference time and the timeout time.
+ * If the timeout is in the past relative to the reference time, returns 0.
+ * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time,
+ * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay.
+ * Otherwise, returns the difference between the reference time and timeout time
+ * rounded up to the next millisecond.
+ */
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // _LIBS_UTILS_TIMERS_H
diff --git a/media/tests/benchmark/src/native/decoder/Android.bp b/media/tests/benchmark/src/native/decoder/Android.bp
index b6286d4..b5072ab 100644
--- a/media/tests/benchmark/src/native/decoder/Android.bp
+++ b/media/tests/benchmark/src/native/decoder/Android.bp
@@ -29,3 +29,22 @@
 
     ldflags: ["-Wl,-Bsymbolic"]
 }
+
+cc_library_static {
+    name: "libmediabenchmark_codec2_decoder",
+    defaults: [
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_codec2_common-defaults",
+    ],
+
+    srcs: ["C2Decoder.cpp"],
+
+    static_libs: [
+        "libmediabenchmark_codec2_common",
+        "libmediabenchmark_extractor",
+    ],
+
+    export_include_dirs: ["."],
+
+    ldflags: ["-Wl,-Bsymbolic"]
+}
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.cpp b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
new file mode 100644
index 0000000..e88d011
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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 "C2Decoder"
+
+#include "C2Decoder.h"
+
+int32_t C2Decoder::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)) {
+        int32_t sampleRate, numChannels;
+        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &sampleRate);
+        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &numChannels);
+        C2StreamSampleRateInfo::output sampleRateInfo(0u, sampleRate);
+        C2StreamChannelCountInfo::output channelCountInfo(0u, numChannels);
+        configParam.push_back(&sampleRateInfo);
+        configParam.push_back(&channelCountInfo);
+
+    } else {
+        int32_t width, height;
+        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
+        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
+        C2StreamPictureSizeInfo::input inputSize(0u, width, height);
+        configParam.push_back(&inputSize);
+    }
+
+    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;
+}
+
+int32_t C2Decoder::decodeFrames(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo) {
+    ALOGV("In %s", __func__);
+    typedef std::unique_lock<std::mutex> ULock;
+    c2_status_t status = C2_OK;
+    mStats->setStartTime();
+    while (1) {
+        if (mNumInputFrame == frameInfo.size()) break;
+        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;
+            }
+        }
+
+        uint32_t flags = frameInfo[mNumInputFrame].flags;
+        if (flags == AMEDIACODEC_BUFFER_FLAG_CODEC_CONFIG) {
+            flags = C2FrameData::FLAG_CODEC_CONFIG;
+        }
+        if (mNumInputFrame == (frameInfo.size() - 1)) {
+            flags |= C2FrameData::FLAG_END_OF_STREAM;
+        }
+        work->input.flags = (C2FrameData::flags_t)flags;
+        work->input.ordinal.timestamp = frameInfo[mNumInputFrame].presentationTimeUs;
+        work->input.ordinal.frameIndex = mNumInputFrame;
+        work->input.buffers.clear();
+        int size = frameInfo[mNumInputFrame].size;
+        int alignedSize = ALIGN(size, PAGE_SIZE);
+        if (size) {
+            std::shared_ptr<C2LinearBlock> block;
+            status = mLinearPool->fetchLinearBlock(
+                    alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+            if (status != C2_OK || block == nullptr) {
+                cout << "C2LinearBlock::map() 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(), inputBuffer + mOffset, size);
+            work->input.buffers.emplace_back(new LinearBuffer(block, size));
+            mStats->addFrameSize(size);
+        }
+        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, size);
+        mNumInputFrame++;
+        mOffset += size;
+    }
+    return status;
+}
+
+void C2Decoder::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 C2Decoder::dumpStatistics(string inputReference, int64_t durationUs) {
+    string operation = "c2decode";
+    mStats->dumpStatistics(operation, inputReference, durationUs);
+}
+
+void C2Decoder::resetDecoder() {
+    mOffset = 0;
+    mNumInputFrame = 0;
+    if (mStats) mStats->reset();
+}
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.h b/media/tests/benchmark/src/native/decoder/C2Decoder.h
new file mode 100644
index 0000000..0e79d51
--- /dev/null
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.h
@@ -0,0 +1,51 @@
+/*
+ * 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_DECODER_H__
+#define __C2_DECODER_H__
+
+#include <stdio.h>
+#include <algorithm>
+#include <fstream>
+
+#include "BenchmarkC2Common.h"
+
+#define ALIGN(_sz, _align) (((_sz) + ((_align) - 1)) & ~((_align) - 1))
+
+class C2Decoder : public BenchmarkC2Common {
+  public:
+    C2Decoder() : mOffset(0), mNumInputFrame(0), mComponent(nullptr) {}
+
+    int32_t createCodec2Component(string codecName, AMediaFormat *format);
+
+    int32_t decodeFrames(uint8_t *inputBuffer, vector<AMediaCodecBufferInfo> &frameInfo);
+
+    void deInitCodec();
+
+    void dumpStatistics(string inputReference, int64_t durationUs);
+
+    void resetDecoder();
+
+  private:
+    int32_t mOffset;
+    int32_t mNumInputFrame;
+    vector<AMediaCodecBufferInfo> mFrameMetaData;
+
+    std::shared_ptr<android::Codec2Client::Listener> mListener;
+    std::shared_ptr<android::Codec2Client::Component> mComponent;
+};
+
+#endif  // __C2_DECODER_H__
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.cpp b/media/tests/benchmark/src/native/decoder/Decoder.cpp
index ef84537..ac0d525 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.cpp
+++ b/media/tests/benchmark/src/native/decoder/Decoder.cpp
@@ -32,8 +32,8 @@
     int64_t timestamp = frameInfo[frameID].presentationTimeUs;
     ssize_t bytesCount = frameInfo[frameID].size;
     if (bufSize < bytesCount) {
-        ALOGE("Error : insufficient resource");
-        return make_tuple(0, AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE, 0);
+        ALOGE("Error : Buffer size is insufficient to read sample");
+        return make_tuple(0, AMEDIA_ERROR_MALFORMED, 0);
     }
 
     memcpy(buf, inputBuffer + offset, bytesCount);
@@ -54,6 +54,7 @@
         size_t bufSize;
         uint8_t *buf = AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
         if (!buf) {
+            mErrorCode = AMEDIA_ERROR_IO;
             mSignalledError = true;
             mDecoderDoneCondition.notify_one();
             return;
@@ -64,7 +65,8 @@
         int64_t presentationTimeUs = 0;
         tie(bytesRead, flag, presentationTimeUs) = readSampleData(
                 mInputBuffer, mOffset, mFrameMetaData, buf, mNumInputFrame, bufSize);
-        if (flag == AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE) {
+        if (flag == AMEDIA_ERROR_MALFORMED) {
+            mErrorCode = (media_status_t)flag;
             mSignalledError = true;
             mDecoderDoneCondition.notify_one();
             return;
@@ -74,9 +76,10 @@
         ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRId64 " mSawInputEOS : %s", __FUNCTION__,
               bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
 
-        int status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */, bytesRead,
-                                                  presentationTimeUs, flag);
+        media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+                                                             bytesRead, presentationTimeUs, flag);
         if (AMEDIA_OK != status) {
+            mErrorCode = status;
             mSignalledError = true;
             mDecoderDoneCondition.notify_one();
             return;
@@ -127,6 +130,16 @@
     }
 }
 
+void Decoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+    ALOGV("In %s", __func__);
+    if (mediaCodec == mCodec && mediaCodec) {
+        ALOGE("Received Error %d", err);
+        mErrorCode = err;
+        mSignalledError = true;
+        mDecoderDoneCondition.notify_one();
+    }
+}
+
 void Decoder::setupDecoder() {
     if (!mFormat) mFormat = mExtractor->getFormat();
 }
@@ -168,7 +181,8 @@
                 ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
                 if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
                     ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
-                    return AMEDIA_ERROR_IO;
+                    mErrorCode = (media_status_t)inIdx;
+                    return mErrorCode;
                 } else if (inIdx >= 0) {
                     mStats->addInputTime();
                     onInputAvailable(mCodec, inIdx);
@@ -188,13 +202,18 @@
             } else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
                          outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
                 ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
-                return AMEDIA_ERROR_IO;
+                mErrorCode = (media_status_t)outIdx;
+                return mErrorCode;
             }
         }
     } else {
         unique_lock<mutex> lock(mMutex);
         mDecoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
     }
+    if (mSignalledError) {
+        ALOGE("Received Error while Decoding");
+        return mErrorCode;
+    }
 
     if (codecName.empty()) {
         char *decName;
diff --git a/media/tests/benchmark/src/native/decoder/Decoder.h b/media/tests/benchmark/src/native/decoder/Decoder.h
index 7630e7b..aeda080 100644
--- a/media/tests/benchmark/src/native/decoder/Decoder.h
+++ b/media/tests/benchmark/src/native/decoder/Decoder.h
@@ -38,6 +38,7 @@
           mSawInputEOS(false),
           mSawOutputEOS(false),
           mSignalledError(false),
+          mErrorCode(AMEDIA_OK),
           mInputBuffer(nullptr),
           mOutFp(nullptr) {
         mExtractor = new Extractor();
@@ -61,6 +62,8 @@
 
     void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
 
+    void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
     void onOutputAvailable(AMediaCodec *codec, int32_t index,
                            AMediaCodecBufferInfo *bufferInfo) override;
 
@@ -82,6 +85,7 @@
     bool mSawInputEOS;
     bool mSawOutputEOS;
     bool mSignalledError;
+    media_status_t mErrorCode;
 
     int32_t mOffset;
     uint8_t *mInputBuffer;
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.cpp b/media/tests/benchmark/src/native/encoder/Encoder.cpp
index 5fdf9e3..a5605de 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.cpp
+++ b/media/tests/benchmark/src/native/encoder/Encoder.cpp
@@ -34,6 +34,7 @@
         size_t bufSize = 0;
         char *buf = (char *)AMediaCodec_getInputBuffer(mCodec, bufIdx, &bufSize);
         if (!buf) {
+            mErrorCode = AMEDIA_ERROR_IO;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -41,6 +42,7 @@
 
         if (mInputBufferSize < mOffset) {
             ALOGE("Out of bound access of input buffer\n");
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -51,6 +53,7 @@
         }
         if (bufSize < bytesRead) {
             ALOGE("bytes to read %zu bufSize %zu \n", bytesRead, bufSize);
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -58,6 +61,7 @@
         if (bytesRead < mParams.frameSize && mNumInputFrame < mParams.numFrames - 1) {
             ALOGE("Partial frame at frameID %d bytesRead %zu frameSize %d total numFrames %d\n",
                   mNumInputFrame, bytesRead, mParams.frameSize, mParams.numFrames);
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -66,6 +70,7 @@
         size_t bytesgcount = mEleStream->gcount();
         if (bytesgcount != bytesRead) {
             ALOGE("bytes to read %zu actual bytes read %zu \n", bytesRead, bytesgcount);
+            mErrorCode = AMEDIA_ERROR_MALFORMED;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -89,9 +94,10 @@
         ALOGV("%s bytesRead : %zd presentationTimeUs : %" PRIu64 " mSawInputEOS : %s", __FUNCTION__,
               bytesRead, presentationTimeUs, mSawInputEOS ? "TRUE" : "FALSE");
 
-        int status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */, bytesRead,
-                                                  presentationTimeUs, flag);
+        media_status_t status = AMediaCodec_queueInputBuffer(mCodec, bufIdx, 0 /* offset */,
+                                                             bytesRead, presentationTimeUs, flag);
         if (AMEDIA_OK != status) {
+            mErrorCode = status;
             mSignalledError = true;
             mEncoderDoneCondition.notify_one();
             return;
@@ -133,6 +139,16 @@
     }
 }
 
+void Encoder::onError(AMediaCodec *mediaCodec, media_status_t err) {
+    ALOGV("In %s", __func__);
+    if (mediaCodec == mCodec && mediaCodec) {
+        ALOGE("Received Error %d", err);
+        mErrorCode = err;
+        mSignalledError = true;
+        mEncoderDoneCondition.notify_one();
+    }
+}
+
 void Encoder::setupEncoder() {
     if (!mFormat) mFormat = AMediaFormat_new();
 }
@@ -235,7 +251,8 @@
                 ssize_t inIdx = AMediaCodec_dequeueInputBuffer(mCodec, kQueueDequeueTimeoutUs);
                 if (inIdx < 0 && inIdx != AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
                     ALOGE("AMediaCodec_dequeueInputBuffer returned invalid index %zd\n", inIdx);
-                    return AMEDIA_ERROR_IO;
+                    mErrorCode = (media_status_t)inIdx;
+                    return mErrorCode;
                 } else if (inIdx >= 0) {
                     mStats->addInputTime();
                     onInputAvailable(mCodec, inIdx);
@@ -255,13 +272,18 @@
             } else if (!(outIdx == AMEDIACODEC_INFO_TRY_AGAIN_LATER ||
                          outIdx == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)) {
                 ALOGE("AMediaCodec_dequeueOutputBuffer returned invalid index %zd\n", outIdx);
-                return AMEDIA_ERROR_IO;
+                mErrorCode = (media_status_t)outIdx;
+                return mErrorCode;
             }
         }
     } else {
         unique_lock<mutex> lock(mMutex);
         mEncoderDoneCondition.wait(lock, [this]() { return (mSawOutputEOS || mSignalledError); });
     }
+    if (mSignalledError) {
+        ALOGE("Received Error while Encoding");
+        return mErrorCode;
+    }
 
     if (codecName.empty()) {
         char *encName;
diff --git a/media/tests/benchmark/src/native/encoder/Encoder.h b/media/tests/benchmark/src/native/encoder/Encoder.h
index 75d9941..6059c4a 100644
--- a/media/tests/benchmark/src/native/encoder/Encoder.h
+++ b/media/tests/benchmark/src/native/encoder/Encoder.h
@@ -49,7 +49,8 @@
           mNumOutputFrame(0),
           mSawInputEOS(false),
           mSawOutputEOS(false),
-          mSignalledError(false) {}
+          mSignalledError(false),
+          mErrorCode(AMEDIA_OK) {}
 
     virtual ~Encoder() {}
 
@@ -65,6 +66,8 @@
 
     void onFormatChanged(AMediaCodec *codec, AMediaFormat *format) override;
 
+    void onError(AMediaCodec *mediaCodec, media_status_t err) override;
+
     void onOutputAvailable(AMediaCodec *codec, int32_t index,
                            AMediaCodecBufferInfo *bufferInfo) override;
 
@@ -83,6 +86,7 @@
     bool mSawInputEOS;
     bool mSawOutputEOS;
     bool mSignalledError;
+    media_status_t mErrorCode;
 
     char *mMime;
     int32_t mOffset;
diff --git a/media/tests/benchmark/tests/Android.bp b/media/tests/benchmark/tests/Android.bp
index 24fd68c..128d055 100644
--- a/media/tests/benchmark/tests/Android.bp
+++ b/media/tests/benchmark/tests/Android.bp
@@ -75,3 +75,20 @@
         "libmediabenchmark_encoder",
     ],
 }
+
+cc_test {
+    name: "C2DecoderTest",
+    gtest: true,
+    defaults: [
+        "libmediabenchmark_codec2_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
+    ],
+
+    srcs: ["C2DecoderTest.cpp"],
+
+    static_libs: [
+        "libmediabenchmark_extractor",
+        "libmediabenchmark_codec2_common",
+        "libmediabenchmark_codec2_decoder",
+    ],
+}
diff --git a/media/tests/benchmark/tests/C2DecoderTest.cpp b/media/tests/benchmark/tests/C2DecoderTest.cpp
new file mode 100644
index 0000000..3531d8a
--- /dev/null
+++ b/media/tests/benchmark/tests/C2DecoderTest.cpp
@@ -0,0 +1,213 @@
+/*
+ * 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 "C2DecoderTest"
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+
+#include "BenchmarkTestEnvironment.h"
+#include "C2Decoder.h"
+#include "Extractor.h"
+
+static BenchmarkTestEnvironment *gEnv = nullptr;
+
+class C2DecoderTest : public ::testing::TestWithParam<pair<string, string>> {
+  public:
+    C2DecoderTest() : mDecoder(nullptr), disableTest(false) { 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;
+    }
+    int32_t status = mDecoder->setupCodec2();
+    if (status != 0) {
+        cout << "[   WARN   ] Test Skipped. Codec2 setup failed \n";
+        disableTest = true;
+        return;
+    }
+    mCodecList = mDecoder->getSupportedComponentList(false /* isEncoder*/);
+    if (!mCodecList.size()) {
+        cout << "[   WARN   ] Test Skipped. Codec2 client didn't recognise any component \n";
+        disableTest = true;
+        return;
+    }
+}
+
+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;
+    }
+
+    Extractor *extractor = new Extractor();
+    if (!extractor) {
+        cout << "[   WARN   ] Test Skipped. Extractor creation failed \n";
+        return;
+    }
+
+    // Read file properties
+    fseek(inputFp, 0, SEEK_END);
+    size_t fileSize = ftell(inputFp);
+    fseek(inputFp, 0, SEEK_SET);
+    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";
+    }
+
+    int32_t trackCount = extractor->initExtractor(fd, fileSize);
+    if (trackCount <= 0) {
+        cout << "[   WARN   ] Test Skipped. initExtractor failed\n";
+        return;
+    }
+    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;
+        }
+
+        uint8_t *inputBuffer = (uint8_t *)malloc(fileSize);
+        if (!inputBuffer) {
+            cout << "[   WARN   ] Test Skipped. Insufficient memory \n";
+            return;
+        }
+
+        vector<AMediaCodecBufferInfo> frameInfo;
+        AMediaCodecBufferInfo info;
+        uint32_t inputBufferOffset = 0;
+        int32_t idx = 0;
+
+        // Get CSD data
+        while (1) {
+            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;
+            }
+            memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
+            frameInfo.push_back(info);
+            inputBufferOffset += info.size;
+            idx++;
+        }
+
+        // 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 > fileSize) {
+                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
+                free(inputBuffer);
+                return;
+            }
+            memcpy(inputBuffer + inputBufferOffset, extractor->getFrameBuf(), info.size);
+            frameInfo.push_back(info);
+            inputBufferOffset += info.size;
+        }
+
+        AMediaFormat *format = extractor->getFormat();
+        // Decode the given input stream for all C2 codecs supported by device
+        for (string codecName : mCodecList) {
+            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;
+                }
+
+                // Send the inputs to C2 Decoder and wait till all buffers are returned.
+                mDecoder->decodeFrames(inputBuffer, frameInfo);
+                mDecoder->waitOnInputConsumption();
+                if (!mDecoder->mEos) {
+                    cout << "[   WARN   ] Test Failed. Didn't receive EOS \n";
+                }
+                mDecoder->deInitCodec();
+                int64_t durationUs = extractor->getClipDuration();
+                cout << "codec: " << codecName << endl;
+                mDecoder->dumpStatistics(GetParam().first, durationUs);
+                mDecoder->resetDecoder();
+            }
+        }
+        free(inputBuffer);
+        fclose(inputFp);
+        extractor->deInitExtractor();
+        delete extractor;
+        delete mDecoder;
+    }
+}
+
+// TODO: (b/140549596)
+// 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")));
+
+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")));
+
+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 Decoder Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 242178f..fa37435 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -93,7 +93,7 @@
         decoder->setupDecoder();
         status = decoder->decode(inputBuffer, frameInfo, codecName, asyncMode);
         if (status != AMEDIA_OK) {
-            cout << "[   WARN   ] Test Skipped. Decode returned error \n";
+            cout << "[   WARN   ] Test Failed. Decode returned error " << status << endl;
             free(inputBuffer);
             return;
         }
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index 9f42c64..c3963f8 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -143,7 +143,11 @@
         string codecName = get<1>(params);
         bool asyncMode = get<2>(params);
         status = encoder->encode(codecName, eleStream, eleSize, asyncMode, encParams, (char *)mime);
-        ASSERT_EQ(status, 0);
+        if (status != AMEDIA_OK) {
+            cout << "[   WARN   ] Test Failed. Encode returned error " << status << endl;
+            free(inputBuffer);
+            return;
+        }
         encoder->deInitCodec();
         cout << "codec : " << codecName << endl;
         string inputReference = get<0>(params);
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 63437da..5047b19 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -30,6 +30,7 @@
     ],
     shared_libs: [
         "libbinder",
+        "libcutils",
         "liblog",
         "libutils",
         "libhidlbase",
@@ -50,6 +51,10 @@
         "libmedia_headers",
     ],
 
+    include_dirs: [
+        // For DEBUGGER_SIGNAL
+        "system/core/debuggerd/include",
+    ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 }
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index db13903..02141a8 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -63,7 +63,10 @@
         uid_t uid, bool start) {
     // Okay to not track in app ops as audio server is us and if
     // device is rooted security model is considered compromised.
-    if (isAudioServerOrRootUid(uid)) return true;
+    // system_server loses its RECORD_AUDIO permission when a secondary
+    // user is active, but it is a core system service so let it through.
+    // TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0
+    if (isAudioServerOrSystemServerOrRootUid(uid)) return true;
 
     // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
     // may open a record track on behalf of a client.  Note that pid may be a tid.
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 265a232..4a3e470 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -14,13 +14,50 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "TimeCheck"
 
 #include <utils/Log.h>
 #include <mediautils/TimeCheck.h>
 #include <mediautils/EventLog.h>
+#include "debuggerd/handler.h"
 
 namespace android {
 
+// Audio HAL server pids vector used to generate audio HAL processes tombstone
+// when audioserver watchdog triggers.
+// We use a lockless storage to avoid potential deadlocks in the context of watchdog
+// trigger.
+// Protection again simultaneous writes is not needed given one update takes place
+// during AudioFlinger construction and other comes necessarily later once the IAudioFlinger
+// interface is available.
+// The use of an atomic index just guaranties that current vector is fully initialized
+// when read.
+/* static */
+void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) {
+    static constexpr int kNumAudioHalPidsVectors = 3;
+    static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors];
+    static std::atomic<int> curAudioHalPids = 0;
+
+    if (update) {
+        audioHalPids[(curAudioHalPids + 1) % kNumAudioHalPidsVectors] = *pids;
+        curAudioHalPids++;
+    } else {
+        *pids = audioHalPids[curAudioHalPids];
+    }
+}
+
+/* static */
+void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) {
+    accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true);
+}
+
+/* static */
+std::vector<pid_t> TimeCheck::getAudioHalPids() {
+    std::vector<pid_t> pids;
+    accessAudioHalPids(&pids, false);
+    return pids;
+}
+
 /* static */
 sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
 {
@@ -82,10 +119,22 @@
         if (waitTimeNs > 0) {
             status = mCond.waitRelative(mMutex, waitTimeNs);
         }
-    }
-    if (status != NO_ERROR) {
-        LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
-        LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
+        if (status != NO_ERROR) {
+            // Generate audio HAL processes tombstones and allow time to complete
+            // before forcing restart
+            std::vector<pid_t> pids = getAudioHalPids();
+            if (pids.size() != 0) {
+                for (const auto& pid : pids) {
+                    ALOGI("requesting tombstone for pid: %d", pid);
+                    sigqueue(pid, DEBUGGER_SIGNAL, {.sival_int = 0});
+                }
+                sleep(1);
+            } else {
+                ALOGI("No HAL process pid available, skipping tombstones");
+            }
+            LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
+            LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
+        }
     }
     return true;
 }
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 2a6e609..e1089d5 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -58,6 +58,12 @@
     return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
 }
 
+// used for calls that should come from system_server or audio_server and
+// include AID_ROOT for command-line tests.
+static inline bool isAudioServerOrSystemServerOrRootUid(uid_t uid) {
+    return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER || uid == AID_ROOT;
+}
+
 // Mediaserver may forward the client PID and UID as part of a binder interface call;
 // otherwise the calling UID must be equal to the client UID.
 static inline bool isAudioServerOrMediaServerUid(uid_t uid) {
diff --git a/media/utils/include/mediautils/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
index 6c5f656..5ba6d7c 100644
--- a/media/utils/include/mediautils/TimeCheck.h
+++ b/media/utils/include/mediautils/TimeCheck.h
@@ -20,7 +20,7 @@
 
 #include <utils/KeyedVector.h>
 #include <utils/Thread.h>
-
+#include <vector>
 
 namespace android {
 
@@ -35,6 +35,8 @@
 
             TimeCheck(const char *tag, uint32_t timeoutMs = kDefaultTimeOutMs);
             ~TimeCheck();
+    static  void setAudioHalPids(const std::vector<pid_t>& pids);
+    static  std::vector<pid_t> getAudioHalPids();
 
 private:
 
@@ -63,6 +65,7 @@
     };
 
     static sp<TimeCheckThread> getTimeCheckThread();
+    static void accessAudioHalPids(std::vector<pid_t>* pids, bool update);
 
     const           nsecs_t mEndTimeNs;
 };
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 96ad54b..de8c7e7 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -34,6 +34,7 @@
     ],
 
     shared_libs: [
+        "libaudiofoundation",
         "libaudiohal",
         "libaudioprocessing",
         "libaudiospdif",
@@ -60,6 +61,10 @@
         "libsndfile",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     cflags: [
         "-DSTATE_QUEUE_INSTANTIATIONS=\"StateQueueInstantiations.cpp\"",
         "-fvisibility=hidden",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9497416..525ac68 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -19,6 +19,9 @@
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
 
+// Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
+#define AUDIO_ARRAYS_STATIC_CHECK 1
+
 #include "Configuration.h"
 #include <dirent.h>
 #include <math.h>
@@ -67,6 +70,7 @@
 #include <media/nbaio/PipeReader.h>
 #include <mediautils/BatteryNotifier.h>
 #include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
 #include <private/android_filesystem_config.h>
 
 //#define BUFLOG_NDEBUG 0
@@ -190,6 +194,9 @@
     mEffectsFactoryHal = EffectsFactoryHalInterface::create();
 
     mMediaLogNotifier->run("MediaLogNotifier");
+    std::vector<pid_t> halPids;
+    mDevicesFactoryHal->getHalPids(&halPids);
+    TimeCheck::setAudioHalPids(halPids);
 }
 
 void AudioFlinger::onFirstRef()
@@ -215,6 +222,11 @@
     gAudioFlinger = this;
 }
 
+status_t AudioFlinger::setAudioHalPids(const std::vector<pid_t>& pids) {
+  TimeCheck::setAudioHalPids(pids);
+  return NO_ERROR;
+}
+
 AudioFlinger::~AudioFlinger()
 {
     while (!mRecordThreads.isEmpty()) {
@@ -378,7 +390,7 @@
 
 AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
         audio_module_handle_t module,
-        audio_devices_t devices)
+        audio_devices_t deviceType)
 {
     // if module is 0, the request comes from an old policy manager and we should load
     // well known modules
@@ -393,7 +405,7 @@
             sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
             uint32_t supportedDevices;
             if (dev->getSupportedDevices(&supportedDevices) == OK &&
-                    (supportedDevices & devices) == devices) {
+                    (supportedDevices & deviceType) == deviceType) {
                 return audioHwDevice;
             }
         }
@@ -1354,6 +1366,13 @@
     }
 }
 
+void AudioFlinger::updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices)
+{
+    for (size_t i = 0; i < mRecordThreads.size(); i++) {
+        mRecordThreads.valueAt(i)->updateOutDevices(devices);
+    }
+}
+
 // forwardAudioHwSyncToDownstreamPatches_l() must be called with AudioFlinger::mLock held
 void AudioFlinger::forwardParametersToDownstreamPatches_l(
         audio_io_handle_t upStream, const String8& keyValuePairs,
@@ -1960,7 +1979,8 @@
                                                   &output.notificationFrameCount,
                                                   callingPid, clientUid, &output.flags,
                                                   input.clientInfo.clientTid,
-                                                  &lStatus, portId);
+                                                  &lStatus, portId,
+                                                  input.opPackageName);
         LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
 
         // lStatus == BAD_TYPE means FAST flag was rejected: request a new input from
@@ -2300,13 +2320,13 @@
 
 
 sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
-                                                            audio_io_handle_t *output,
-                                                            audio_config_t *config,
-                                                            audio_devices_t devices,
-                                                            const String8& address,
-                                                            audio_output_flags_t flags)
+                                                        audio_io_handle_t *output,
+                                                        audio_config_t *config,
+                                                        audio_devices_t deviceType,
+                                                        const String8& address,
+                                                        audio_output_flags_t flags)
 {
-    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
+    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
     if (outHwDev == NULL) {
         return 0;
     }
@@ -2347,7 +2367,7 @@
     status_t status = outHwDev->openOutputStream(
             &outputStream,
             *output,
-            devices,
+            deviceType,
             flags,
             config,
             address.string());
@@ -2357,8 +2377,7 @@
     if (status == NO_ERROR) {
         if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
             sp<MmapPlaybackThread> thread =
-                    new MmapPlaybackThread(this, *output, outHwDev, outputStream,
-                                          devices, AUDIO_DEVICE_NONE, mSystemReady);
+                    new MmapPlaybackThread(this, *output, outHwDev, outputStream, mSystemReady);
             mMmapThreads.add(*output, thread);
             ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
                   *output, thread.get());
@@ -2366,17 +2385,17 @@
         } else {
             sp<PlaybackThread> thread;
             if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-                thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
+                thread = new OffloadThread(this, outputStream, *output, mSystemReady);
                 ALOGV("openOutput_l() created offload output: ID %d thread %p",
                       *output, thread.get());
             } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                     || !isValidPcmSinkFormat(config->format)
                     || !isValidPcmSinkChannelMask(config->channel_mask)) {
-                thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
+                thread = new DirectOutputThread(this, outputStream, *output, mSystemReady);
                 ALOGV("openOutput_l() created direct output: ID %d thread %p",
                       *output, thread.get());
             } else {
-                thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
+                thread = new MixerThread(this, outputStream, *output, mSystemReady);
                 ALOGV("openOutput_l() created mixer output: ID %d thread %p",
                       *output, thread.get());
             }
@@ -2392,27 +2411,29 @@
 status_t AudioFlinger::openOutput(audio_module_handle_t module,
                                   audio_io_handle_t *output,
                                   audio_config_t *config,
-                                  audio_devices_t *devices,
-                                  const String8& address,
+                                  const sp<DeviceDescriptorBase>& device,
                                   uint32_t *latencyMs,
                                   audio_output_flags_t flags)
 {
-    ALOGI("openOutput() this %p, module %d Device %#x, SamplingRate %d, Format %#08x, "
+    ALOGI("openOutput() this %p, module %d Device %s, SamplingRate %d, Format %#08x, "
               "Channels %#x, flags %#x",
               this, module,
-              (devices != NULL) ? *devices : 0,
+              device->toString().c_str(),
               config->sample_rate,
               config->format,
               config->channel_mask,
               flags);
 
-    if (devices == NULL || *devices == AUDIO_DEVICE_NONE) {
+    audio_devices_t deviceType = device->type();
+    const String8 address = String8(device->address().c_str());
+
+    if (deviceType == AUDIO_DEVICE_NONE) {
         return BAD_VALUE;
     }
 
     Mutex::Autolock _l(mLock);
 
-    sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags);
+    sp<ThreadBase> thread = openOutput_l(module, output, config, deviceType, address, flags);
     if (thread != 0) {
         if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
             PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
@@ -2682,9 +2703,7 @@
         AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream, flags);
         if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
             sp<MmapCaptureThread> thread =
-                    new MmapCaptureThread(this, *input,
-                                          inHwDev, inputStream,
-                                          primaryOutputDevice_l(), devices, mSystemReady);
+                    new MmapCaptureThread(this, *input, inHwDev, inputStream, mSystemReady);
             mMmapThreads.add(*input, thread);
             ALOGV("openInput_l() created mmap capture thread: ID %d thread %p", *input,
                     thread.get());
@@ -2693,13 +2712,7 @@
             // Start record thread
             // RecordThread requires both input and output device indication to forward to audio
             // pre processing modules
-            sp<RecordThread> thread = new RecordThread(this,
-                                      inputStream,
-                                      *input,
-                                      primaryOutputDevice_l(),
-                                      devices,
-                                      mSystemReady
-                                      );
+            sp<RecordThread> thread = new RecordThread(this, inputStream, *input, mSystemReady);
             mRecordThreads.add(*input, thread);
             ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
             return thread;
@@ -3115,15 +3128,15 @@
     return NULL;
 }
 
-audio_devices_t AudioFlinger::primaryOutputDevice_l() const
+DeviceTypeSet AudioFlinger::primaryOutputDevice_l() const
 {
     PlaybackThread *thread = primaryPlaybackThread_l();
 
     if (thread == NULL) {
-        return 0;
+        return DeviceTypeSet();
     }
 
-    return thread->outDevice();
+    return thread->outDeviceTypes();
 }
 
 AudioFlinger::PlaybackThread *AudioFlinger::fastPlaybackThread_l() const
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d639f26..9e3ec92 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -65,7 +65,10 @@
 #include <media/audiohal/EffectBufferHalInterface.h>
 #include <media/audiohal/StreamHalInterface.h>
 #include <media/AudioBufferProvider.h>
+#include <media/AudioContainers.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioMixer.h>
+#include <media/DeviceDescriptorBase.h>
 #include <media/ExtendedAudioBufferProvider.h>
 #include <media/LinearMap.h>
 #include <media/VolumeShaper.h>
@@ -175,8 +178,7 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags);
 
@@ -279,6 +281,8 @@
 
     virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
+    virtual status_t setAudioHalPids(const std::vector<pid_t>& pids);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -372,7 +376,7 @@
     virtual     void        onFirstRef();
 
     AudioHwDevice*          findSuitableHwDev_l(audio_module_handle_t module,
-                                                audio_devices_t devices);
+                                                audio_devices_t deviceType);
 
     // Set kEnableExtendedChannels to true to enable greater than stereo output
     // for the MixerThread and device sink.  Number of channels allowed is
@@ -678,11 +682,11 @@
                                            audio_devices_t outputDevice,
                                            const String8& outputDeviceAddress);
               sp<ThreadBase> openOutput_l(audio_module_handle_t module,
-                                              audio_io_handle_t *output,
-                                              audio_config_t *config,
-                                              audio_devices_t devices,
-                                              const String8& address,
-                                              audio_output_flags_t flags);
+                                          audio_io_handle_t *output,
+                                          audio_config_t *config,
+                                          audio_devices_t deviceType,
+                                          const String8& address,
+                                          audio_output_flags_t flags);
 
               void closeOutputFinish(const sp<PlaybackThread>& thread);
               void closeInputFinish(const sp<RecordThread>& thread);
@@ -717,7 +721,7 @@
 
               // return thread associated with primary hardware device, or NULL
               PlaybackThread *primaryPlaybackThread_l() const;
-              audio_devices_t primaryOutputDevice_l() const;
+              DeviceTypeSet primaryOutputDevice_l() const;
 
               // return the playback thread with smallest HAL buffer size, and prefer fast
               PlaybackThread *fastPlaybackThread_l() const;
@@ -751,6 +755,7 @@
                 std::vector< sp<EffectModule> > purgeStaleEffects_l();
 
                 void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
+                void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices);
                 void forwardParametersToDownstreamPatches_l(
                         audio_io_handle_t upStream, const String8& keyValuePairs,
                         std::function<bool(const sp<PlaybackThread>&)> useThread = nullptr);
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index b109d06..dda164c 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -34,7 +34,7 @@
 status_t AudioHwDevice::openOutputStream(
         AudioStreamOut **ppStreamOut,
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address)
@@ -50,7 +50,7 @@
             config->sample_rate,
             config->format,
             config->channel_mask);
-    status_t status = outputStream->open(handle, devices, config, address);
+    status_t status = outputStream->open(handle, deviceType, config, address);
 
     if (status != NO_ERROR) {
         delete outputStream;
@@ -75,7 +75,7 @@
         if (wrapperNeeded) {
             if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
                 outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
-                status = outputStream->open(handle, devices, &originalConfig, address);
+                status = outputStream->open(handle, deviceType, &originalConfig, address);
                 if (status != NO_ERROR) {
                     ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
                         status);
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index d4299b0..6709d17 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -76,7 +76,7 @@
     status_t openOutputStream(
             AudioStreamOut **ppStreamOut,
             audio_io_handle_t handle,
-            audio_devices_t devices,
+            audio_devices_t deviceType,
             audio_output_flags_t flags,
             struct audio_config *config,
             const char *address);
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index a60a5f2..d13cb8f 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -118,7 +118,7 @@
 
 status_t AudioStreamOut::open(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         struct audio_config *config,
         const char *address)
 {
@@ -130,7 +130,7 @@
 
     int status = hwDev()->openOutputStream(
             handle,
-            devices,
+            deviceType,
             customFlags,
             config,
             address,
@@ -152,7 +152,7 @@
 
         status = hwDev()->openOutputStream(
                 handle,
-                devices,
+                deviceType,
                 customFlags,
                 &customConfig,
                 address,
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index b16b1af..16fbcf2 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -47,7 +47,7 @@
 
     virtual status_t open(
             audio_io_handle_t handle,
-            audio_devices_t devices,
+            audio_devices_t deviceType,
             struct audio_config *config,
             const char *address);
 
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 13152d0..ee7a6d6 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -29,7 +29,9 @@
 #include <system/audio_effects/effect_visualizer.h>
 #include <audio_utils/channels.h>
 #include <audio_utils/primitives.h>
+#include <media/AudioContainers.h>
 #include <media/AudioEffect.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 #include <mediautils/ServiceUtilities.h>
@@ -1229,9 +1231,11 @@
     }
 }
 
-status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
+status_t AudioFlinger::EffectModule::sendSetAudioDevicesCommand(
+        const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode)
 {
-    if (device == AUDIO_DEVICE_NONE) {
+    audio_devices_t deviceType = deviceTypesToBitMask(getAudioDeviceTypes(devices));
+    if (deviceType == AUDIO_DEVICE_NONE) {
         return NO_ERROR;
     }
 
@@ -1243,17 +1247,26 @@
     if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
         status_t cmdStatus;
         uint32_t size = sizeof(status_t);
-        uint32_t cmd = audio_is_output_devices(device) ? EFFECT_CMD_SET_DEVICE :
-                            EFFECT_CMD_SET_INPUT_DEVICE;
-        status = mEffectInterface->command(cmd,
+        // FIXME: use audio device types and addresses when the hal interface is ready.
+        status = mEffectInterface->command(cmdCode,
                                            sizeof(uint32_t),
-                                           &device,
+                                           &deviceType,
                                            &size,
                                            &cmdStatus);
     }
     return status;
 }
 
+status_t AudioFlinger::EffectModule::setDevices(const AudioDeviceTypeAddrVector &devices)
+{
+    return sendSetAudioDevicesCommand(devices, EFFECT_CMD_SET_DEVICE);
+}
+
+status_t AudioFlinger::EffectModule::setInputDevice(const AudioDeviceTypeAddr &device)
+{
+    return sendSetAudioDevicesCommand({device}, EFFECT_CMD_SET_INPUT_DEVICE);
+}
+
 status_t AudioFlinger::EffectModule::setMode(audio_mode_t mode)
 {
     Mutex::Autolock _l(mLock);
@@ -2288,12 +2301,21 @@
     return mEffects.size();
 }
 
-// setDevice_l() must be called with ThreadBase::mLock held
-void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device)
+// setDevices_l() must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setDevices_l(const AudioDeviceTypeAddrVector &devices)
 {
     size_t size = mEffects.size();
     for (size_t i = 0; i < size; i++) {
-        mEffects[i]->setDevice(device);
+        mEffects[i]->setDevices(devices);
+    }
+}
+
+// setInputDevice_l() must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setInputDevice_l(const AudioDeviceTypeAddr &device)
+{
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->setInputDevice(device);
     }
 }
 
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 220874d..dbf63c8 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -109,7 +109,8 @@
     const effect_descriptor_t& desc() const { return mDescriptor; }
     wp<EffectChain>&     chain() { return mChain; }
 
-    status_t         setDevice(audio_devices_t device);
+    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);
@@ -158,6 +159,7 @@
     status_t start_l();
     status_t stop_l();
     status_t remove_effect_from_hal_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
@@ -350,7 +352,8 @@
     // FIXME use float to improve the dynamic range
     bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
     void resetVolume_l();
-    void setDevice_l(audio_devices_t device);
+    void setDevices_l(const AudioDeviceTypeAddrVector &devices);
+    void setInputDevice_l(const AudioDeviceTypeAddr &device);
     void setMode_l(audio_mode_t mode);
     void setAudioSource_l(audio_source_t source);
 
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 18cb53b..cb1ef7f 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -25,6 +25,7 @@
 
 #include "AudioFlinger.h"
 #include <media/AudioParameter.h>
+#include <media/DeviceDescriptorBase.h>
 #include <media/PatchBuilder.h>
 #include <mediautils/ServiceUtilities.h>
 
@@ -351,7 +352,7 @@
                 goto exit;
             }
             // limit to connections between devices and output streams
-            audio_devices_t type = AUDIO_DEVICE_NONE;
+            DeviceDescriptorBaseVector devices;
             for (unsigned int i = 0; i < patch->num_sinks; i++) {
                 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
                     ALOGW("%s() invalid sink type %d for mix source",
@@ -364,7 +365,11 @@
                     status = BAD_VALUE;
                     goto exit;
                 }
-                type |= patch->sinks[i].ext.device.type;
+                sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(
+                        patch->sinks[i].ext.device.type);
+                device->setAddress(patch->sinks[i].ext.device.address);
+                device->applyAudioPortConfig(&patch->sinks[i]);
+                devices.push_back(device);
             }
             sp<ThreadBase> thread =
                             mAudioFlinger.checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
@@ -378,10 +383,7 @@
                 }
             }
             if (thread == mAudioFlinger.primaryPlaybackThread_l()) {
-                AudioParameter param = AudioParameter();
-                param.addInt(String8(AudioParameter::keyRouting), (int)type);
-
-                mAudioFlinger.broacastParametersToRecordThreads_l(param.toString());
+                mAudioFlinger.updateOutDevicesForRecordThreads_l(devices);
             }
 
             status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index da05dac..d5257bd 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -19,6 +19,39 @@
     #error This header file should only be included from AudioFlinger.h
 #endif
 
+// Checks and monitors OP_RECORD_AUDIO
+class OpRecordAudioMonitor : public RefBase {
+public:
+    ~OpRecordAudioMonitor() override;
+    bool hasOpRecordAudio() const;
+
+    static sp<OpRecordAudioMonitor> createIfNeeded(uid_t uid, const String16& opPackageName);
+
+private:
+    OpRecordAudioMonitor(uid_t uid, const String16& opPackageName);
+    void onFirstRef() override;
+
+    AppOpsManager mAppOpsManager;
+
+    class RecordAudioOpCallback : public BnAppOpsCallback {
+    public:
+        explicit RecordAudioOpCallback(const wp<OpRecordAudioMonitor>& monitor);
+        void opChanged(int32_t op, const String16& packageName) override;
+
+    private:
+        const wp<OpRecordAudioMonitor> mMonitor;
+    };
+
+    sp<RecordAudioOpCallback> mOpCallback;
+    // called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
+    // and in onFirstRef()
+    void checkRecordAudio();
+
+    std::atomic_bool mHasOpRecordAudio;
+    const uid_t mUid;
+    const String16 mPackage;
+};
+
 // record track
 class RecordTrack : public TrackBase {
 public:
@@ -36,6 +69,7 @@
                                 uid_t uid,
                                 audio_input_flags_t flags,
                                 track_type type,
+                                const String16& opPackageName,
                                 audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
     virtual             ~RecordTrack();
     virtual status_t    initCheck() const;
@@ -68,7 +102,7 @@
                                 { return (mFlags & AUDIO_INPUT_FLAG_DIRECT) != 0; }
 
             void        setSilenced(bool silenced) { if (!isPatchTrack()) mSilenced = silenced; }
-            bool        isSilenced() const { return mSilenced; }
+            bool        isSilenced() const;
 
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
@@ -111,6 +145,11 @@
             audio_input_flags_t                mFlags;
 
             bool                               mSilenced;
+
+            // used to enforce OP_RECORD_AUDIO
+            uid_t                              mUid;
+            String16                           mOpPackageName;
+            sp<OpRecordAudioMonitor>           mOpRecordAudioMonitor;
 };
 
 // playback track, used by PatchPanel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 73292d3..b5592e3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -29,6 +29,8 @@
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <cutils/properties.h>
+#include <media/AudioContainers.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioParameter.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/RecordBufferConverter.h>
@@ -460,7 +462,7 @@
 }
 
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        audio_devices_t outDevice, audio_devices_t inDevice, type_t type, bool systemReady)
+        type_t type, bool systemReady)
     :   Thread(false /*canCallJava*/),
         mType(type),
         mAudioFlinger(audioFlinger),
@@ -468,8 +470,7 @@
         // are set by PlaybackThread::readOutputParameters_l() or
         // RecordThread::readInputParameters_l()
         //FIXME: mStandby should be true here. Is this some kind of hack?
-        mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
-        mPrevOutDevice(AUDIO_DEVICE_NONE), mPrevInDevice(AUDIO_DEVICE_NONE),
+        mStandby(false),
         mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this)),
@@ -646,6 +647,18 @@
     return sendConfigEvent_l(configEvent);
 }
 
+status_t AudioFlinger::ThreadBase::sendUpdateOutDeviceConfigEvent(
+        const DeviceDescriptorBaseVector& outDevices)
+{
+    if (type() != RECORD) {
+        // The update out device operation is only for record thread.
+        return INVALID_OPERATION;
+    }
+    Mutex::Autolock _l(mLock);
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new UpdateOutDevicesConfigEvent(outDevices);
+    return sendConfigEvent_l(configEvent);
+}
+
 
 // post condition: mConfigEvents.isEmpty()
 void AudioFlinger::ThreadBase::processConfigEvents_l()
@@ -680,24 +693,29 @@
             }
         } break;
         case CFG_EVENT_CREATE_AUDIO_PATCH: {
-            const audio_devices_t oldDevice = getDevice();
+            const DeviceTypeSet oldDevices = getDeviceTypes();
             CreateAudioPatchConfigEventData *data =
                                             (CreateAudioPatchConfigEventData *)event->mData.get();
             event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
-            const audio_devices_t newDevice = getDevice();
-            mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
-                    (unsigned)oldDevice, toString(oldDevice).c_str(),
-                    (unsigned)newDevice, toString(newDevice).c_str());
+            const DeviceTypeSet newDevices = getDeviceTypes();
+            mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
+                    dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
+                    dumpDeviceTypes(newDevices).c_str(), toString(newDevices).c_str());
         } break;
         case CFG_EVENT_RELEASE_AUDIO_PATCH: {
-            const audio_devices_t oldDevice = getDevice();
+            const DeviceTypeSet oldDevices = getDeviceTypes();
             ReleaseAudioPatchConfigEventData *data =
                                             (ReleaseAudioPatchConfigEventData *)event->mData.get();
             event->mStatus = releaseAudioPatch_l(data->mHandle);
-            const audio_devices_t newDevice = getDevice();
-            mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
-                    (unsigned)oldDevice, toString(oldDevice).c_str(),
-                    (unsigned)newDevice, toString(newDevice).c_str());
+            const DeviceTypeSet newDevices = getDeviceTypes();
+            mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
+                    dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
+                    dumpDeviceTypes(newDevices).c_str(), toString(newDevices).c_str());
+        } break;
+        case CFG_EVENT_UPDATE_OUT_DEVICE: {
+            UpdateOutDevicesConfigEventData *data =
+                    (UpdateOutDevicesConfigEventData *)event->mData.get();
+            updateOutDevices(data->mOutDevices);
         } break;
         default:
             ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
@@ -840,8 +858,10 @@
         dprintf(fd, " none\n");
     }
     // Note: output device may be used by capture threads for effects such as AEC.
-    dprintf(fd, "  Output device: %#x (%s)\n", mOutDevice, toString(mOutDevice).c_str());
-    dprintf(fd, "  Input device: %#x (%s)\n", mInDevice, toString(mInDevice).c_str());
+    dprintf(fd, "  Output devices: %s (%s)\n",
+            dumpDeviceTypes(outDeviceTypes()).c_str(), toString(outDeviceTypes()).c_str());
+    dprintf(fd, "  Input device: %#x (%s)\n",
+            inDeviceType(), toString(inDeviceType()).c_str());
     dprintf(fd, "  Audio source: %d (%s)\n", mAudioSource, toString(mAudioSource).c_str());
 
     // Dump timestamp statistics for the Thread types that support it.
@@ -1011,6 +1031,12 @@
     mPowerManager.clear();
 }
 
+void AudioFlinger::ThreadBase::updateOutDevices(
+        const DeviceDescriptorBaseVector& outDevices __unused)
+{
+    ALOGE("%s should only be called in RecordThread", __func__);
+}
+
 void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who __unused)
 {
     sp<ThreadBase> thread = mThread.promote();
@@ -1351,8 +1377,9 @@
             }
             effectCreated = true;
 
-            effect->setDevice(mOutDevice);
-            effect->setDevice(mInDevice);
+            // FIXME: use vector of device and address when effect interface is ready.
+            effect->setDevices(outDeviceTypeAddrs());
+            effect->setInputDevice(inDeviceTypeAddr());
             effect->setMode(mAudioFlinger->getMode());
             effect->setAudioSource(mAudioSource);
         }
@@ -1468,8 +1495,8 @@
         return status;
     }
 
-    effect->setDevice(mOutDevice);
-    effect->setDevice(mInDevice);
+    effect->setDevices(outDeviceTypeAddrs());
+    effect->setInputDevice(inDeviceTypeAddr());
     effect->setMode(mAudioFlinger->getMode());
     effect->setAudioSource(mAudioSource);
 
@@ -1702,8 +1729,8 @@
     item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
     item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
     item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
-    item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
-    item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
+    item->setCString(MM_PREFIX "outDevice", toString(outDeviceTypes()).c_str());
+    item->setCString(MM_PREFIX "inDevice", toString(inDeviceType()).c_str());
 
     // thread statistics
     if (mIoJitterMs.getN() > 0) {
@@ -1734,10 +1761,9 @@
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
                                              AudioStreamOut* output,
                                              audio_io_handle_t id,
-                                             audio_devices_t device,
                                              type_t type,
                                              bool systemReady)
-    :   ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady),
+    :   ThreadBase(audioFlinger, id, type, systemReady),
         mNormalFrameCount(0), mSinkBuffer(NULL),
         mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
         mMixerBuffer(NULL),
@@ -1799,9 +1825,10 @@
 
     // TODO: We may also match on address as well as device type for
     // AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
-    if (type == MIXER || type == DIRECT) {
-        mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
-                "audio.timestamp.corrected_output_devices",
+    if (type == MIXER || type == DIRECT || type == OFFLOAD) {
+        // TODO: This property should be ensure that only contains one single device type.
+        mTimestampCorrectedDevice = (audio_devices_t)property_get_int64(
+                "audio.timestamp.corrected_output_device",
                 (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_OUT_BUS // turn on by default for MSD
                                        : AUDIO_DEVICE_NONE));
     }
@@ -2891,7 +2918,7 @@
 {
     if (!mMasterMute) {
         char value[PROPERTY_VALUE_MAX];
-        if (mOutDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+        if (isSingleDeviceType(outDeviceTypes(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
             ALOGD("ro.audio.silent will be ignored for threads on AUDIO_DEVICE_OUT_REMOTE_SUBMIX");
             return;
         }
@@ -3035,7 +3062,7 @@
     // make sure standby delay is not too short when connected to an A2DP sink to avoid
     // truncating audio when going to standby.
     mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs;
-    if ((mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) {
+    if (!Intersection(outDeviceTypes(),  getAudioDeviceOutAllA2dpSet()).empty()) {
         if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) {
             mStandbyDelayNs = kDefaultStandbyTimeInNsecs;
         }
@@ -3283,8 +3310,8 @@
 
         // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
         //
-        // Note: we access outDevice() outside of mLock.
-        if (isMsdDevice() && (outDevice() & AUDIO_DEVICE_OUT_BUS) != 0) {
+        // Note: we access outDeviceTypes() outside of mLock.
+        if (isMsdDevice() && outDeviceTypes().count(AUDIO_DEVICE_OUT_BUS) != 0) {
             // Here, we try for the AF lock, but do not block on it as the latency
             // is more informational.
             if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
@@ -3820,8 +3847,10 @@
                             if (diff > 0) {
                                 // notify of throttle end on debug log
                                 // but prevent spamming for bluetooth
-                                ALOGD_IF(!audio_is_a2dp_out_device(outDevice()) &&
-                                         !audio_is_hearing_aid_out_device(outDevice()),
+                                ALOGD_IF(!isSingleDeviceType(
+                                                 outDeviceTypes(), audio_is_a2dp_out_device) &&
+                                         !isSingleDeviceType(
+                                                 outDeviceTypes(), audio_is_hearing_aid_out_device),
                                         "mixer(%p) throttle end: throttle time(%u)", this, diff);
                                 mThreadThrottleEndMs = mThreadThrottleTimeMs;
                             }
@@ -4006,25 +4035,31 @@
 
     // store new device and send to effects
     audio_devices_t type = AUDIO_DEVICE_NONE;
+    AudioDeviceTypeAddrVector deviceTypeAddrs;
     for (unsigned int i = 0; i < patch->num_sinks; i++) {
+        LOG_ALWAYS_FATAL_IF(popcount(patch->sinks[i].ext.device.type) > 1
+                            && !mOutput->audioHwDev->supportsAudioPatches(),
+                            "Enumerated device type(%#x) must not be used "
+                            "as it does not support audio patches",
+                            patch->sinks[i].ext.device.type);
         type |= patch->sinks[i].ext.device.type;
+        deviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
+                patch->sinks[i].ext.device.address));
     }
 
     audio_port_handle_t sinkPortId = patch->sinks[0].id;
 #ifdef ADD_BATTERY_DATA
     // when changing the audio output device, call addBatteryData to notify
     // the change
-    if (mOutDevice != type) {
+    if (outDeviceTypes() != deviceTypes) {
         uint32_t params = 0;
         // check whether speaker is on
-        if (type & AUDIO_DEVICE_OUT_SPEAKER) {
+        if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) > 0) {
             params |= IMediaPlayerService::kBatteryDataSpeakerOn;
         }
 
-        audio_devices_t deviceWithoutSpeaker
-            = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
         // check if any other device (except speaker) is on
-        if (type & deviceWithoutSpeaker) {
+        if (!isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_SPEAKER)) {
             params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
         }
 
@@ -4035,14 +4070,15 @@
 #endif
 
     for (size_t i = 0; i < mEffectChains.size(); i++) {
-        mEffectChains[i]->setDevice_l(type);
+        mEffectChains[i]->setDevices_l(deviceTypeAddrs);
     }
 
-    // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when
-    // the thread is created so that the first patch creation triggers an ioConfigChanged callback
-    bool configChanged = (mPrevOutDevice != type) || (mDeviceId != sinkPortId);
-    mOutDevice = type;
+    // mPatch.num_sinks is not set when the thread is created so that
+    // the first patch creation triggers an ioConfigChanged callback
+    bool configChanged = (mPatch.num_sinks == 0) ||
+                         (mPatch.sinks[0].id != sinkPortId);
     mPatch = *patch;
+    mOutDeviceTypeAddrs = deviceTypeAddrs;
 
     if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -4068,8 +4104,6 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
     if (configChanged) {
-        mPrevOutDevice = type;
-        mDeviceId = sinkPortId;
         sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
     }
     return status;
@@ -4093,7 +4127,8 @@
 {
     status_t status = NO_ERROR;
 
-    mOutDevice = AUDIO_DEVICE_NONE;
+    mPatch = audio_patch{};
+    mOutDeviceTypeAddrs.clear();
 
     if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -4133,8 +4168,8 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-        audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
-    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady),
+        audio_io_handle_t id, bool systemReady, type_t type)
+    :   PlaybackThread(audioFlinger, output, id, type, systemReady),
         // mAudioMixer below
         // mFastMixer below
         mFastMixerFutex(0),
@@ -4144,7 +4179,7 @@
         // mNormalSink below
 {
     setMasterBalance(audioFlinger->getMasterBalance_l());
-    ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
+    ALOGV("MixerThread() id=%d type=%d", id, type);
     ALOGV("mSampleRate=%u, mChannelMask=%#x, mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
             "mFrameCount=%zu, mNormalFrameCount=%zu",
             mSampleRate, mChannelMask, mChannelCount, mFormat, mFrameSize, mFrameCount,
@@ -4186,7 +4221,7 @@
         // scheduled reliably with CFS. However, the BT A2DP HAL is
         // bursty (does not pull at a regular rate) and so cannot operate with FastMixer.
         initFastMixer = mFrameCount < mNormalFrameCount
-                && (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) == 0;
+                && Intersection(outDeviceTypes(), getAudioDeviceOutAllA2dpSet()).empty();
         break;
     }
     ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
@@ -5357,39 +5392,7 @@
         }
     }
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-#ifdef ADD_BATTERY_DATA
-        // when changing the audio output device, call addBatteryData to notify
-        // the change
-        if (mOutDevice != value) {
-            uint32_t params = 0;
-            // check whether speaker is on
-            if (value & AUDIO_DEVICE_OUT_SPEAKER) {
-                params |= IMediaPlayerService::kBatteryDataSpeakerOn;
-            }
-
-            audio_devices_t deviceWithoutSpeaker
-                = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
-            // check if any other device (except speaker) is on
-            if (value & deviceWithoutSpeaker) {
-                params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
-            }
-
-            if (params != 0) {
-                addBatteryData(params);
-            }
-        }
-#endif
-
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        if (value != AUDIO_DEVICE_NONE) {
-            a2dpDeviceChanged =
-                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
-            mOutDevice = value;
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(mOutDevice);
-            }
-        }
+        LOG_FATAL("Should not set routing device in MixerThread");
     }
 
     if (status == NO_ERROR) {
@@ -5490,9 +5493,8 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device,
-        ThreadBase::type_t type, bool systemReady)
-    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
+        AudioStreamOut* output, audio_io_handle_t id, ThreadBase::type_t type, bool systemReady)
+    :   PlaybackThread(audioFlinger, output, id, type, systemReady)
 {
     setMasterBalance(audioFlinger->getMasterBalance_l());
 }
@@ -5733,7 +5735,7 @@
                 int64_t framesWritten = mBytesWritten / mFrameSize;
                 if (mStandby || !last ||
                         track->presentationComplete(framesWritten, audioHALFrames) ||
-                        track->isPaused()) {
+                        track->isPaused() || mHwPaused) {
                     if (track->isStopping_2()) {
                         track->mState = TrackBase::STOPPED;
                     }
@@ -5894,16 +5896,7 @@
     AudioParameter param = AudioParameter(keyValuePair);
     int value;
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        if (value != AUDIO_DEVICE_NONE) {
-            a2dpDeviceChanged =
-                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
-            mOutDevice = value;
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(mOutDevice);
-            }
-        }
+        LOG_FATAL("Should not set routing device in DirectOutputThread");
     }
     if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
         // do not accept frame count changes if tracks are open as the track buffer
@@ -6115,8 +6108,8 @@
 
 // ----------------------------------------------------------------------------
 AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
-    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
+        AudioStreamOut* output, audio_io_handle_t id, bool systemReady)
+    :   DirectOutputThread(audioFlinger, output, id, OFFLOAD, systemReady),
         mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
         mOffloadUnderrunPosition(~0LL)
 {
@@ -6441,7 +6434,7 @@
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
         AudioFlinger::MixerThread* mainThread, audio_io_handle_t id, bool systemReady)
-    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->outDevice(),
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id,
                     systemReady, DUPLICATING),
         mWaitTimeMs(UINT_MAX)
 {
@@ -6673,11 +6666,9 @@
 AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
                                          AudioStreamIn *input,
                                          audio_io_handle_t id,
-                                         audio_devices_t outDevice,
-                                         audio_devices_t inDevice,
                                          bool systemReady
                                          ) :
-    ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
+    ThreadBase(audioFlinger, id, RECORD, systemReady),
     mInput(input),
     mSource(mInput),
     mActiveTracks(&this->mLocalLog),
@@ -6709,8 +6700,9 @@
 
     // TODO: We may also match on address as well as device type for
     // AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_DEVICE_IN_REMOTE_SUBMIX
-    mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
-            "audio.timestamp.corrected_input_devices",
+    // TODO: This property should be ensure that only contains one single device type.
+    mTimestampCorrectedDevice = (audio_devices_t)property_get_int64(
+            "audio.timestamp.corrected_input_device",
             (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_IN_BUS // turn on by default for MSD
                                    : AUDIO_DEVICE_NONE));
 
@@ -7303,7 +7295,7 @@
                         // Sanitize before releasing if the track has no access to the source data
                         // An idle UID receives silence from non virtual devices until active
                         if (activeTrack->isSilenced()) {
-                            memset(activeTrack->mSink.raw, 0, framesOut * mFrameSize);
+                            memset(activeTrack->mSink.raw, 0, framesOut * activeTrack->frameSize());
                         }
                         activeTrack->releaseBuffer(&activeTrack->mSink);
                     }
@@ -7464,7 +7456,8 @@
         audio_input_flags_t *flags,
         pid_t tid,
         status_t *status,
-        audio_port_handle_t portId)
+        audio_port_handle_t portId,
+        const String16& opPackageName)
 {
     size_t frameCount = *pFrameCount;
     size_t notificationFrameCount = *pNotificationFrameCount;
@@ -7598,7 +7591,7 @@
         track = new RecordTrack(this, client, attr, sampleRate,
                       format, channelMask, frameCount,
                       nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid, uid,
-                      *flags, TrackBase::TYPE_DEFAULT, portId);
+                      *flags, TrackBase::TYPE_DEFAULT, opPackageName, portId);
 
         lStatus = track->initCheck();
         if (lStatus != NO_ERROR) {
@@ -8053,7 +8046,7 @@
 {
     // disable AEC and NS if the device is a BT SCO headset supporting those
     // pre processings
-    bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+    bool suspend = audio_is_bluetooth_sco_device(inDeviceType()) &&
                         mAudioFlinger->btNrecIsOff();
     if (mBtNrecSuspended.exchange(suspend) != suspend) {
         for (size_t i = 0; i < mEffectChains.size(); i++) {
@@ -8118,34 +8111,11 @@
         }
     }
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        for (size_t i = 0; i < mEffectChains.size(); i++) {
-            mEffectChains[i]->setDevice_l(value);
-        }
-
-        // store input device and output device but do not forward output device to audio HAL.
-        // Note that status is ignored by the caller for output device
-        // (see AudioFlinger::setParameters()
-        if (audio_is_output_devices(value)) {
-            mOutDevice = value;
-            status = BAD_VALUE;
-        } else {
-            mInDevice = value;
-            if (value != AUDIO_DEVICE_NONE) {
-                mPrevInDevice = value;
-            }
-            checkBtNrec_l();
-        }
+        LOG_FATAL("Should not set routing device in RecordThread");
     }
     if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
             mAudioSource != (audio_source_t)value) {
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        for (size_t i = 0; i < mEffectChains.size(); i++) {
-            mEffectChains[i]->setAudioSource_l((audio_source_t)value);
-        }
-        mAudioSource = (audio_source_t)value;
+        LOG_FATAL("Should not set audio source in RecordThread");
     }
 
     if (status == NO_ERROR) {
@@ -8347,11 +8317,11 @@
     status_t status = NO_ERROR;
 
     // store new device and send to effects
-    mInDevice = patch->sources[0].ext.device.type;
+    mInDeviceTypeAddr.mType = patch->sources[0].ext.device.type;
+    mInDeviceTypeAddr.mAddress = patch->sources[0].ext.device.address;
     audio_port_handle_t deviceId = patch->sources[0].id;
-    mPatch = *patch;
     for (size_t i = 0; i < mEffectChains.size(); i++) {
-        mEffectChains[i]->setDevice_l(mInDevice);
+        mEffectChains[i]->setInputDevice_l(inDeviceTypeAddr());
     }
 
     checkBtNrec_l();
@@ -8390,10 +8360,9 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    if ((mInDevice != mPrevInDevice) || (mDeviceId != deviceId)) {
+    if ((mPatch.num_sources == 0) || (mPatch.sources[0].id != deviceId)) {
         sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
-        mPrevInDevice = mInDevice;
-        mDeviceId = deviceId;
+        mPatch = *patch;
     }
 
     return status;
@@ -8403,7 +8372,8 @@
 {
     status_t status = NO_ERROR;
 
-    mInDevice = AUDIO_DEVICE_NONE;
+    mPatch = audio_patch{};
+    mInDeviceTypeAddr.reset();
 
     if (mInput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
@@ -8416,6 +8386,15 @@
     return status;
 }
 
+void AudioFlinger::RecordThread::updateOutDevices(const DeviceDescriptorBaseVector& outDevices)
+{
+    mOutDevices = outDevices;
+    mOutDeviceTypeAddrs = deviceTypeAddrsFromDescriptors(mOutDevices);
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->setDevices_l(outDeviceTypeAddrs());
+    }
+}
+
 void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
 {
     Mutex::Autolock _l(mLock);
@@ -8492,9 +8471,8 @@
 
 AudioFlinger::MmapThread::MmapThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
-        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
-    : ThreadBase(audioFlinger, id, outDevice, inDevice, MMAP, systemReady),
+        AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady)
+    : ThreadBase(audioFlinger, id, MMAP, systemReady),
       mSessionId(AUDIO_SESSION_NONE),
       mPortId(AUDIO_PORT_HANDLE_NONE),
       mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
@@ -8860,26 +8838,7 @@
     int value;
     bool sendToHal = true;
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-        audio_devices_t device = (audio_devices_t)value;
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        if (device != AUDIO_DEVICE_NONE) {
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(device);
-            }
-        }
-        if (audio_is_output_devices(device)) {
-            mOutDevice = device;
-            if (!isOutput()) {
-                sendToHal = false;
-            }
-        } else {
-            mInDevice = device;
-            if (device != AUDIO_DEVICE_NONE) {
-                mPrevInDevice = value;
-            }
-            // TODO: implement and call checkBtNrec_l();
-        }
+        LOG_FATAL("Should not happen set routing device in MmapThread");
     }
     if (sendToHal) {
         status = mHalStream->setParameters(keyValuePair);
@@ -8938,24 +8897,39 @@
     // store new device and send to effects
     audio_devices_t type = AUDIO_DEVICE_NONE;
     audio_port_handle_t deviceId;
+    AudioDeviceTypeAddrVector sinkDeviceTypeAddrs;
+    AudioDeviceTypeAddr sourceDeviceTypeAddr;
+    uint32_t numDevices = 0;
     if (isOutput()) {
         for (unsigned int i = 0; i < patch->num_sinks; i++) {
+            LOG_ALWAYS_FATAL_IF(popcount(patch->sinks[i].ext.device.type) > 1
+                                && !mAudioHwDev->supportsAudioPatches(),
+                                "Enumerated device type(%#x) must not be used "
+                                "as it does not support audio patches",
+                                patch->sinks[i].ext.device.type);
             type |= patch->sinks[i].ext.device.type;
+            sinkDeviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
+                    patch->sinks[i].ext.device.address));
         }
         deviceId = patch->sinks[0].id;
+        numDevices = mPatch.num_sinks;
     } else {
         type = patch->sources[0].ext.device.type;
         deviceId = patch->sources[0].id;
+        numDevices = mPatch.num_sources;
+        sourceDeviceTypeAddr.mType = patch->sources[0].ext.device.type;
+        sourceDeviceTypeAddr.mAddress = patch->sources[0].ext.device.address;
     }
 
     for (size_t i = 0; i < mEffectChains.size(); i++) {
-        mEffectChains[i]->setDevice_l(type);
+        if (isOutput()) {
+            mEffectChains[i]->setDevices_l(sinkDeviceTypeAddrs);
+        } else {
+            mEffectChains[i]->setInputDevice_l(sourceDeviceTypeAddr);
+        }
     }
 
-    if (isOutput()) {
-        mOutDevice = type;
-    } else {
-        mInDevice = type;
+    if (!isOutput()) {
         // store new source and send to effects
         if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
             mAudioSource = patch->sinks[0].ext.mix.usecase.source;
@@ -8992,26 +8966,21 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    if (isOutput() && (mPrevOutDevice != mOutDevice || mDeviceId != deviceId)) {
-        mPrevOutDevice = type;
-        sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+    if (numDevices == 0 || mDeviceId != deviceId) {
+        if (isOutput()) {
+            sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+            mOutDeviceTypeAddrs = sinkDeviceTypeAddrs;
+        } else {
+            sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+            mInDeviceTypeAddr = sourceDeviceTypeAddr;
+        }
         sp<MmapStreamCallback> callback = mCallback.promote();
         if (mDeviceId != deviceId && callback != 0) {
             mLock.unlock();
             callback->onRoutingChanged(deviceId);
             mLock.lock();
         }
-        mDeviceId = deviceId;
-    }
-    if (!isOutput() && (mPrevInDevice != mInDevice || mDeviceId != deviceId)) {
-        mPrevInDevice = type;
-        sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
-        sp<MmapStreamCallback> callback = mCallback.promote();
-        if (mDeviceId != deviceId && callback != 0) {
-            mLock.unlock();
-            callback->onRoutingChanged(deviceId);
-            mLock.lock();
-        }
+        mPatch = *patch;
         mDeviceId = deviceId;
     }
     return status;
@@ -9021,7 +8990,9 @@
 {
     status_t status = NO_ERROR;
 
-    mInDevice = AUDIO_DEVICE_NONE;
+    mPatch = audio_patch{};
+    mOutDeviceTypeAddrs.clear();
+    mInDeviceTypeAddr.reset();
 
     bool supportsAudioPatches = mHalDevice->supportsAudioPatches(&supportsAudioPatches) == OK ?
                                         supportsAudioPatches : false;
@@ -9197,9 +9168,8 @@
 
 AudioFlinger::MmapPlaybackThread::MmapPlaybackThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        AudioHwDevice *hwDev,  AudioStreamOut *output,
-        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
-    : MmapThread(audioFlinger, id, hwDev, output->stream, outDevice, inDevice, systemReady),
+        AudioHwDevice *hwDev,  AudioStreamOut *output, bool systemReady)
+    : MmapThread(audioFlinger, id, hwDev, output->stream, systemReady),
       mStreamType(AUDIO_STREAM_MUSIC),
       mStreamVolume(1.0),
       mStreamMute(false),
@@ -9409,9 +9379,8 @@
 
 AudioFlinger::MmapCaptureThread::MmapCaptureThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        AudioHwDevice *hwDev,  AudioStreamIn *input,
-        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
-    : MmapThread(audioFlinger, id, hwDev, input->stream, outDevice, inDevice, systemReady),
+        AudioHwDevice *hwDev,  AudioStreamIn *input, bool systemReady)
+    : MmapThread(audioFlinger, id, hwDev, input->stream, systemReady),
       mInput(input)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index acb1370..8de7632 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -37,8 +37,7 @@
     static const char *threadTypeToString(type_t type);
 
     ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                audio_devices_t outDevice, audio_devices_t inDevice, type_t type,
-                bool systemReady);
+               type_t type, bool systemReady);
     virtual             ~ThreadBase();
 
     virtual status_t    readyToRun();
@@ -52,6 +51,7 @@
         CFG_EVENT_SET_PARAMETER,
         CFG_EVENT_CREATE_AUDIO_PATCH,
         CFG_EVENT_RELEASE_AUDIO_PATCH,
+        CFG_EVENT_UPDATE_OUT_DEVICE,
     };
 
     class ConfigEventData: public RefBase {
@@ -219,6 +219,28 @@
         virtual ~ReleaseAudioPatchConfigEvent() {}
     };
 
+    class UpdateOutDevicesConfigEventData : public ConfigEventData {
+    public:
+        explicit UpdateOutDevicesConfigEventData(const DeviceDescriptorBaseVector& outDevices) :
+            mOutDevices(outDevices) {}
+
+        virtual void dump(char *buffer, size_t size) {
+            snprintf(buffer, size, "Devices: %s", android::toString(mOutDevices).c_str());
+        }
+
+        DeviceDescriptorBaseVector mOutDevices;
+    };
+
+    class UpdateOutDevicesConfigEvent : public ConfigEvent {
+    public:
+        explicit UpdateOutDevicesConfigEvent(const DeviceDescriptorBaseVector& outDevices) :
+            ConfigEvent(CFG_EVENT_UPDATE_OUT_DEVICE) {
+            mData = new UpdateOutDevicesConfigEventData(outDevices);
+        }
+
+        virtual ~UpdateOutDevicesConfigEvent();
+    };
+
     class PMDeathRecipient : public IBinder::DeathRecipient {
     public:
         explicit    PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
@@ -278,19 +300,33 @@
                 status_t    sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
                                                             audio_patch_handle_t *handle);
                 status_t    sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle);
+                status_t    sendUpdateOutDeviceConfigEvent(
+                                    const DeviceDescriptorBaseVector& outDevices);
                 void        processConfigEvents_l();
     virtual     void        cacheParameters_l() = 0;
     virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
                                                audio_patch_handle_t *handle) = 0;
     virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
+    virtual     void        updateOutDevices(const DeviceDescriptorBaseVector& outDevices);
     virtual     void        toAudioPortConfig(struct audio_port_config *config) = 0;
 
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
                 bool        standby() const { return mStandby; }
-                audio_devices_t outDevice() const { return mOutDevice; }
-                audio_devices_t inDevice() const { return mInDevice; }
-                audio_devices_t getDevice() const { return isOutput() ? mOutDevice : mInDevice; }
+                const DeviceTypeSet outDeviceTypes() const {
+                    return getAudioDeviceTypes(mOutDeviceTypeAddrs);
+                }
+                audio_devices_t inDeviceType() const { return mInDeviceTypeAddr.mType; }
+                DeviceTypeSet getDeviceTypes() const {
+                    return isOutput() ? outDeviceTypes() : DeviceTypeSet({inDeviceType()});
+                }
+
+                const AudioDeviceTypeAddrVector& outDeviceTypeAddrs() const {
+                    return mOutDeviceTypeAddrs;
+                }
+                const AudioDeviceTypeAddr& inDeviceTypeAddr() const {
+                    return mInDeviceTypeAddr;
+                }
 
     virtual     bool        isOutput() const = 0;
 
@@ -502,26 +538,21 @@
                                                            // HAL format if Fastmixer is used.
                 audio_format_t          mHALFormat;
                 size_t                  mBufferSize;       // HAL buffer size for read() or write()
-
+                AudioDeviceTypeAddrVector mOutDeviceTypeAddrs; // output device types and addresses
+                AudioDeviceTypeAddr       mInDeviceTypeAddr;   // input device type and address
                 Vector< sp<ConfigEvent> >     mConfigEvents;
                 Vector< sp<ConfigEvent> >     mPendingConfigEvents; // events awaiting system ready
 
                 // These fields are written and read by thread itself without lock or barrier,
-                // and read by other threads without lock or barrier via standby(), outDevice()
-                // and inDevice().
+                // and read by other threads without lock or barrier via standby(), outDeviceTypes()
+                // and inDeviceType().
                 // Because of the absence of a lock or barrier, any other thread that reads
                 // these fields must use the information in isolation, or be prepared to deal
                 // with possibility that it might be inconsistent with other information.
                 bool                    mStandby;     // Whether thread is currently in standby.
-                audio_devices_t         mOutDevice;   // output device
-                audio_devices_t         mInDevice;    // input device
-                audio_devices_t         mPrevOutDevice;   // previous output device
-                audio_devices_t         mPrevInDevice;    // previous input device
+
                 struct audio_patch      mPatch;
-                /**
-                 * @brief mDeviceId  current device port unique identifier
-                 */
-                audio_port_handle_t     mDeviceId = AUDIO_PORT_HANDLE_NONE;
+
                 audio_source_t          mAudioSource;
 
                 const audio_io_handle_t mId;
@@ -544,7 +575,8 @@
                 ExtendedTimestamp       mTimestamp;
                 TimestampVerifier< // For timestamp statistics.
                         int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
-                audio_devices_t         mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+                // Timestamp corrected device should be a single device.
+                audio_devices_t         mTimestampCorrectedDevice = AUDIO_DEVICE_NONE;
 
                 // ThreadLoop statistics per iteration.
                 int64_t                 mLastIoBeginNs = -1;
@@ -719,7 +751,7 @@
     static const nsecs_t kMaxNextBufferDelayNs = 100000000;
 
     PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                   audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
+                   audio_io_handle_t id, type_t type, bool systemReady);
     virtual             ~PlaybackThread();
 
     // Thread virtuals
@@ -886,10 +918,10 @@
                             }
 
                 bool        isTimestampCorrectionEnabled() const override {
-                                const audio_devices_t device =
-                                        mOutDevice & mTimestampCorrectedDevices;
-                                return audio_is_output_devices(device) && popcount(device) > 0;
+                                return audio_is_output_devices(mTimestampCorrectedDevice)
+                                        && outDeviceTypes().count(mTimestampCorrectedDevice) != 0;
                             }
+
 protected:
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -1171,7 +1203,6 @@
     MixerThread(const sp<AudioFlinger>& audioFlinger,
                 AudioStreamOut* output,
                 audio_io_handle_t id,
-                audio_devices_t device,
                 bool systemReady,
                 type_t type = MIXER);
     virtual             ~MixerThread();
@@ -1269,8 +1300,8 @@
 public:
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                       audio_io_handle_t id, audio_devices_t device, bool systemReady)
-        : DirectOutputThread(audioFlinger, output, id, device, DIRECT, systemReady) { }
+                       audio_io_handle_t id, bool systemReady)
+        : DirectOutputThread(audioFlinger, output, id, DIRECT, systemReady) { }
 
     virtual                 ~DirectOutputThread();
 
@@ -1305,8 +1336,7 @@
     bool mVolumeShaperActive = false;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, audio_devices_t device, ThreadBase::type_t type,
-                        bool systemReady);
+                       audio_io_handle_t id, ThreadBase::type_t type, bool systemReady);
     void processVolume_l(Track *track, bool lastTrack);
 
     // prepareTracks_l() tells threadLoop_mix() the name of the single active track
@@ -1345,7 +1375,7 @@
 public:
 
     OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, uint32_t device, bool systemReady);
+                  audio_io_handle_t id, bool systemReady);
     virtual                 ~OffloadThread() {};
     virtual     void        flushHw_l();
 
@@ -1516,8 +1546,6 @@
             RecordThread(const sp<AudioFlinger>& audioFlinger,
                     AudioStreamIn *input,
                     audio_io_handle_t id,
-                    audio_devices_t outDevice,
-                    audio_devices_t inDevice,
                     bool systemReady
                     );
             virtual     ~RecordThread();
@@ -1553,7 +1581,8 @@
                     audio_input_flags_t *flags,
                     pid_t tid,
                     status_t *status /*non-NULL*/,
-                    audio_port_handle_t portId);
+                    audio_port_handle_t portId,
+                    const String16& opPackageName);
 
             status_t    start(RecordTrack* recordTrack,
                               AudioSystem::sync_event_t event,
@@ -1576,6 +1605,7 @@
     virtual status_t    createAudioPatch_l(const struct audio_patch *patch,
                                            audio_patch_handle_t *handle);
     virtual status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
+            void        updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override;
 
             void        addPatchTrack(const sp<PatchRecord>& record);
             void        deletePatchTrack(const sp<PatchRecord>& record);
@@ -1628,8 +1658,8 @@
 
             bool        isTimestampCorrectionEnabled() const override {
                             // checks popcount for exactly one device.
-                            return audio_is_input_device(
-                                    mInDevice & mTimestampCorrectedDevices);
+                            return audio_is_input_device(mTimestampCorrectedDevice)
+                                    && inDeviceType() == mTimestampCorrectedDevice;
                         }
 
 protected:
@@ -1708,6 +1738,8 @@
             std::atomic_bool                    mBtNrecSuspended;
 
             int64_t                             mFramesRead = 0;    // continuous running counter.
+
+            DeviceDescriptorBaseVector          mOutDevices;
 };
 
 class MmapThread : public ThreadBase
@@ -1717,8 +1749,7 @@
 #include "MmapTracks.h"
 
     MmapThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                      AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
-                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+               AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady);
     virtual     ~MmapThread();
 
     virtual     void        configure(const audio_attributes_t *attr,
@@ -1791,6 +1822,11 @@
                 void        dumpInternals_l(int fd, const Vector<String16>& args) override;
                 void        dumpTracks_l(int fd, const Vector<String16>& args) override;
 
+                /**
+                 * @brief mDeviceId  current device port unique identifier
+                 */
+                audio_port_handle_t     mDeviceId = AUDIO_PORT_HANDLE_NONE;
+
                 audio_attributes_t      mAttr;
                 audio_session_t         mSessionId;
                 audio_port_handle_t     mPortId;
@@ -1811,8 +1847,7 @@
 
 public:
     MmapPlaybackThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                      AudioHwDevice *hwDev, AudioStreamOut *output,
-                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+                       AudioHwDevice *hwDev, AudioStreamOut *output, bool systemReady);
     virtual     ~MmapPlaybackThread() {}
 
     virtual     void        configure(const audio_attributes_t *attr,
@@ -1861,8 +1896,7 @@
 
 public:
     MmapCaptureThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                      AudioHwDevice *hwDev, AudioStreamIn *input,
-                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+                      AudioHwDevice *hwDev, AudioStreamIn *input, bool systemReady);
     virtual     ~MmapCaptureThread() {}
 
                 AudioStreamIn* clearInput();
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 7a3bb0d..52e7d59 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -215,6 +215,8 @@
 
     uint32_t channelCount() const { return mChannelCount; }
 
+    size_t frameSize() const { return mFrameSize; }
+
     audio_channel_mask_t channelMask() const { return mChannelMask; }
 
     virtual uint32_t sampleRate() const { return mSampleRate; }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 16a8a84..e4402bd 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -444,7 +444,7 @@
     return mHasOpPlayAudio.load();
 }
 
-// Note this method is never called (and never to be) for audio server / root track
+// Note this method is never called (and never to be) for audio server / patch record track
 // - not called from constructor due to check on UID,
 // - not called from PlayAudioOpCallback because the callback is not installed in this case
 void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::checkPlayAudioForUsage()
@@ -1885,6 +1885,105 @@
 // ----------------------------------------------------------------------------
 //      Record
 // ----------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------
+//      AppOp for audio recording
+// -------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AF::OpRecordAudioMonitor"
+
+// static
+sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
+AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded(
+            uid_t uid, const String16& opPackageName)
+{
+    if (isServiceUid(uid)) {
+        ALOGV("not silencing record for service uid:%d pack:%s",
+                uid, String8(opPackageName).string());
+        return nullptr;
+    }
+
+    if (opPackageName.size() == 0) {
+        Vector<String16> packages;
+        // no package name, happens with SL ES clients
+        // query package manager to find one
+        PermissionController permissionController;
+        permissionController.getPackagesForUid(uid, packages);
+        if (packages.isEmpty()) {
+            return nullptr;
+        } else {
+            ALOGV("using pack:%s for uid:%d", String8(packages[0]).string(), uid);
+            return new OpRecordAudioMonitor(uid, packages[0]);
+        }
+    }
+
+    return new OpRecordAudioMonitor(uid, opPackageName);
+}
+
+AudioFlinger::RecordThread::OpRecordAudioMonitor::OpRecordAudioMonitor(
+        uid_t uid, const String16& opPackageName)
+        : mHasOpRecordAudio(true), mUid(uid), mPackage(opPackageName)
+{
+}
+
+AudioFlinger::RecordThread::OpRecordAudioMonitor::~OpRecordAudioMonitor()
+{
+    if (mOpCallback != 0) {
+        mAppOpsManager.stopWatchingMode(mOpCallback);
+    }
+    mOpCallback.clear();
+}
+
+void AudioFlinger::RecordThread::OpRecordAudioMonitor::onFirstRef()
+{
+    checkRecordAudio();
+    mOpCallback = new RecordAudioOpCallback(this);
+    ALOGV("start watching OP_RECORD_AUDIO for pack:%s", String8(mPackage).string());
+    mAppOpsManager.startWatchingMode(AppOpsManager::OP_RECORD_AUDIO, mPackage, mOpCallback);
+}
+
+bool AudioFlinger::RecordThread::OpRecordAudioMonitor::hasOpRecordAudio() const {
+    return mHasOpRecordAudio.load();
+}
+
+// Called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
+// and in onFirstRef()
+// Note this method is never called (and never to be) for audio server / root track
+// due to the UID in createIfNeeded(). As a result for those record track, it's:
+// - not called from constructor,
+// - not called from RecordAudioOpCallback because the callback is not installed in this case
+void AudioFlinger::RecordThread::OpRecordAudioMonitor::checkRecordAudio()
+{
+    const int32_t mode = mAppOpsManager.checkOp(AppOpsManager::OP_RECORD_AUDIO,
+            mUid, mPackage);
+    const bool hasIt =  (mode == AppOpsManager::MODE_ALLOWED);
+    // verbose logging only log when appOp changed
+    ALOGI_IF(hasIt != mHasOpRecordAudio.load(),
+            "OP_RECORD_AUDIO missing, %ssilencing record uid%d pack:%s",
+            hasIt ? "un" : "", mUid, String8(mPackage).string());
+    mHasOpRecordAudio.store(hasIt);
+}
+
+AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback(
+        const wp<OpRecordAudioMonitor>& monitor) : mMonitor(monitor)
+{ }
+
+void AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
+            const String16& packageName) {
+    UNUSED(packageName);
+    if (op != AppOpsManager::OP_RECORD_AUDIO) {
+        return;
+    }
+    sp<OpRecordAudioMonitor> monitor = mMonitor.promote();
+    if (monitor != NULL) {
+        monitor->checkRecordAudio();
+    }
+}
+
+
+
 #undef LOG_TAG
 #define LOG_TAG "AF::RecordHandle"
 
@@ -1956,6 +2055,7 @@
             uid_t uid,
             audio_input_flags_t flags,
             track_type type,
+            const String16& opPackageName,
             audio_port_handle_t portId)
     :   TrackBase(thread, client, attr, sampleRate, format,
                   channelMask, frameCount, buffer, bufferSize, sessionId,
@@ -1969,7 +2069,8 @@
         mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
         mRecordBufferConverter(NULL),
         mFlags(flags),
-        mSilenced(false)
+        mSilenced(false),
+        mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, opPackageName))
 {
     if (mCblk == NULL) {
         return;
@@ -2220,6 +2321,14 @@
     mServerLatencyMs.store(latencyMs);
 }
 
+bool AudioFlinger::RecordThread::RecordTrack::isSilenced() const {
+    if (mSilenced) {
+        return true;
+    }
+    // The monitor is only created for record tracks that can be silenced.
+    return mOpRecordAudioMonitor ? !mOpRecordAudioMonitor->hasOpRecordAudio() : false;
+}
+
 status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones(
         std::vector<media::MicrophoneInfo>* activeMicrophones)
 {
@@ -2270,7 +2379,7 @@
                 audio_attributes_t{} /* currently unused for patch track */,
                 sampleRate, format, channelMask, frameCount,
                 buffer, bufferSize, AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER,
-                flags, TYPE_PATCH),
+                flags, TYPE_PATCH, String16()),
         PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true),
                        *recordThread, timeout)
 {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 30f29d6..1fe60d4 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_AUDIOPOLICY_INTERFACE_H
 #define ANDROID_AUDIOPOLICY_INTERFACE_H
 
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
+#include <media/DeviceDescriptorBase.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -269,6 +271,14 @@
 
     virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
                                                        volume_group_t &volumeGroup) = 0;
+
+    virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   const AudioDeviceTypeAddr &device) = 0;
+
+    virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0;
+
+    virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   AudioDeviceTypeAddr &device) = 0;
 };
 
 
@@ -296,8 +306,7 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags) = 0;
     // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
index a94fd87..eb6c19e 100644
--- a/services/audiopolicy/TEST_MAPPING
+++ b/services/audiopolicy/TEST_MAPPING
@@ -2,9 +2,6 @@
   "presubmit": [
     {
        "name": "audiopolicy_tests"
-    },
-    {
-       "name": "systemaudio_tests"
     }
   ]
 }
diff --git a/services/audiopolicy/common/Android.bp b/services/audiopolicy/common/Android.bp
index a925b9a..6e0d2f6 100644
--- a/services/audiopolicy/common/Android.bp
+++ b/services/audiopolicy/common/Android.bp
@@ -1,4 +1,7 @@
 cc_library_headers {
     name: "libaudiopolicycommon",
+    header_libs: [
+        "libaudiofoundation_headers",
+    ],
     export_include_dirs: ["include"],
 }
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 1dbd1eb..7c8ce83 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -17,10 +17,13 @@
 #pragma once
 
 #include <media/AudioCommonTypes.h>
+#include <media/AudioContainers.h>
 #include <system/audio.h>
 #include <utils/Log.h>
 #include <math.h>
 
+#include "policy.h"
+
 namespace android {
 
 /**
@@ -82,43 +85,26 @@
      *
      * @return subset of device required to limit the number of volume category per device
      */
-    static audio_devices_t getDeviceForVolume(audio_devices_t device)
+    static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
     {
-        if (device == AUDIO_DEVICE_NONE) {
+        if (deviceTypes.empty()) {
             // this happens when forcing a route update and no track is active on an output.
             // In this case the returned category is not important.
-            device =  AUDIO_DEVICE_OUT_SPEAKER;
-        } else if (popcount(device) > 1) {
-            // Multiple device selection is either:
-            //  - speaker + one other device: give priority to speaker in this case.
-            //  - one A2DP device + another device: happens with duplicated output. In this case
-            // retain the device on the A2DP output as the other must not correspond to an active
-            // selection if not the speaker.
-            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
-            if (device & AUDIO_DEVICE_OUT_SPEAKER) {
-                device = AUDIO_DEVICE_OUT_SPEAKER;
-            } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
-                device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-            } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
-                device = AUDIO_DEVICE_OUT_HDMI_ARC;
-            } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
-                device = AUDIO_DEVICE_OUT_AUX_LINE;
-            } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
-                device = AUDIO_DEVICE_OUT_SPDIF;
-            } else {
-                device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
-            }
+            return AUDIO_DEVICE_OUT_SPEAKER;
         }
 
+        audio_devices_t deviceType = apm_extract_one_audio_device(deviceTypes);
+
         /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
-        if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
-            device = AUDIO_DEVICE_OUT_SPEAKER;
+        if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+            deviceType = AUDIO_DEVICE_OUT_SPEAKER;
+        }
 
-        ALOGW_IF(popcount(device) != 1,
-                 "getDeviceForVolume() invalid device combination: %08x",
-                 device);
+        ALOGW_IF(deviceType == AUDIO_DEVICE_NONE,
+                 "getDeviceForVolume() invalid device combination: %s, returning AUDIO_DEVICE_NONE",
+                 android::dumpDeviceTypes(deviceTypes).c_str());
 
-        return device;
+        return deviceType;
     }
 
     /**
@@ -128,9 +114,9 @@
      *
      * @return device category.
      */
-    static device_category getDeviceCategory(audio_devices_t device)
+    static device_category getDeviceCategory(const android::DeviceTypeSet& deviceTypes)
     {
-        switch(getDeviceForVolume(device)) {
+        switch(getDeviceForVolume(deviceTypes)) {
         case AUDIO_DEVICE_OUT_EARPIECE:
             return DEVICE_CATEGORY_EARPIECE;
         case AUDIO_DEVICE_OUT_WIRED_HEADSET:
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 605fc1c..0537365 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -19,6 +19,8 @@
 #include <system/audio.h>
 #include <vector>
 
+#include <media/AudioContainers.h>
+
 namespace android {
 
 using StreamTypeVector = std::vector<audio_stream_type_t>;
@@ -43,14 +45,6 @@
 #define MAX_MIXER_CHANNEL_COUNT FCC_8
 
 /**
- * A device mask for all audio input and output devices where matching inputs/outputs on device
- * type alone is not enough: the address must match too
- */
-#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX|AUDIO_DEVICE_OUT_BUS)
-
-#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_BUS)
-
-/**
  * Alias to AUDIO_DEVICE_OUT_DEFAULT defined for clarification when this value is used by volume
  * control APIs (e.g setStreamVolumeIndex().
  */
@@ -71,6 +65,34 @@
 }
 
 /**
+ * Check whether the output device type is one
+ * where addresses are used to distinguish between one connected device and another
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device needs distinguish on address, false otherwise..
+ */
+static inline bool apm_audio_out_device_distinguishes_on_address(audio_devices_t device)
+{
+    return device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+           device == AUDIO_DEVICE_OUT_BUS;
+}
+
+/**
+ * Check whether the input device type is one
+ * where addresses are used to distinguish between one connected device and another
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device needs distinguish on address, false otherwise..
+ */
+static inline bool apm_audio_in_device_distinguishes_on_address(audio_devices_t device)
+{
+    return device == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
+           device == AUDIO_DEVICE_IN_BUS;
+}
+
+/**
  * Check whether the device type is one
  * where addresses are used to distinguish between one connected device and another
  *
@@ -80,10 +102,8 @@
  */
 static inline bool device_distinguishes_on_address(audio_devices_t device)
 {
-    return (((device & AUDIO_DEVICE_BIT_IN) != 0) &&
-            ((~AUDIO_DEVICE_BIT_IN & device & APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL) != 0)) ||
-           (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
-            ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
+    return apm_audio_in_device_distinguishes_on_address(device) ||
+           apm_audio_out_device_distinguishes_on_address(device);
 }
 
 /**
@@ -95,10 +115,7 @@
  */
 static inline bool device_has_encoding_capability(audio_devices_t device)
 {
-    if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        return true;
-    }
-    return false;
+    return audio_is_a2dp_out_device(device);
 }
 
 /**
@@ -184,3 +201,43 @@
 {
     return hasStream(streams, AUDIO_STREAM_VOICE_CALL);
 }
+
+/**
+ * @brief extract one device relevant from multiple device selection
+ * @param deviceTypes collection of audio device type
+ * @return the device type that is selected
+ */
+static inline audio_devices_t apm_extract_one_audio_device(
+        const android::DeviceTypeSet& deviceTypes) {
+    if (deviceTypes.empty()) {
+        return AUDIO_DEVICE_NONE;
+    } else if (deviceTypes.size() == 1) {
+        return *(deviceTypes.begin());
+    } else {
+        // Multiple device selection is either:
+        //  - speaker + one other device: give priority to speaker in this case.
+        //  - one A2DP device + another device: happens with duplicated output. In this case
+        // retain the device on the A2DP output as the other must not correspond to an active
+        // selection if not the speaker.
+        //  - HDMI-CEC system audio mode only output: give priority to available item in order.
+        if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
+            return AUDIO_DEVICE_OUT_SPEAKER;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
+            return AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
+            return AUDIO_DEVICE_OUT_HDMI_ARC;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
+            return AUDIO_DEVICE_OUT_AUX_LINE;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
+            return AUDIO_DEVICE_OUT_SPDIF;
+        } else {
+            std::vector<audio_devices_t> a2dpDevices = android::Intersection(
+                    deviceTypes, android::getAudioDeviceOutAllA2dpSet());
+            if (a2dpDevices.empty() || a2dpDevices.size() > 1) {
+                ALOGW("%s invalid device combination: %s",
+                      __func__, android::dumpDeviceTypes(deviceTypes).c_str());
+            }
+            return a2dpDevices.empty() ? AUDIO_DEVICE_NONE : a2dpDevices[0];
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index f02f3cf..fad3c5b 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -3,24 +3,24 @@
 
     srcs: [
         "src/AudioCollections.cpp",
-        "src/AudioGain.cpp",
         "src/AudioInputDescriptor.cpp",
         "src/AudioOutputDescriptor.cpp",
         "src/AudioPatch.cpp",
         "src/AudioPolicyMix.cpp",
-        "src/AudioPort.cpp",
-        "src/AudioProfile.cpp",
+        "src/AudioProfileVectorHelper.cpp",
         "src/AudioRoute.cpp",
         "src/ClientDescriptor.cpp",
         "src/DeviceDescriptor.cpp",
         "src/EffectDescriptor.cpp",
         "src/HwModule.cpp",
         "src/IOProfile.cpp",
+        "src/PolicyAudioPort.cpp",
         "src/Serializer.cpp",
         "src/SoundTriggerSession.cpp",
         "src/TypeConverter.cpp",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "libcutils",
         "libhidlbase",
         "liblog",
@@ -28,7 +28,10 @@
         "libutils",
         "libxml2",
     ],
-    export_shared_lib_headers: ["libmedia"],
+    export_shared_lib_headers: [
+        "libaudiofoundation",
+        "libmedia",
+    ],
     static_libs: [
         "libaudioutils",
     ],
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
index a948ea9..b692592 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -25,20 +25,15 @@
 
 namespace android {
 
-class AudioPort;
+class PolicyAudioPort;
 class AudioRoute;
 
-class AudioPortVector : public Vector<sp<AudioPort> >
-{
-public:
-    sp<AudioPort> findByTagName(const String8 &tagName) const;
-};
+using PolicyAudioPortVector = Vector<sp<PolicyAudioPort>>;
+using AudioRouteVector = Vector<sp<AudioRoute>>;
 
+sp<PolicyAudioPort> findByTagName(const PolicyAudioPortVector& policyAudioPortVector,
+                                  const std::string &tagName);
 
-class AudioRouteVector : public Vector<sp<AudioRoute> >
-{
-public:
-    void dump(String8 *dst, int spaces) const;
-};
+void dumpAudioRouteVector(const AudioRouteVector& audioRouteVector, String8 *dst, int spaces);
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 37f9d14..ec82873 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -21,11 +21,11 @@
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
 #include "AudioIODescriptorInterface.h"
-#include "AudioPort.h"
 #include "ClientDescriptor.h"
 #include "DeviceDescriptor.h"
 #include "EffectDescriptor.h"
 #include "IOProfile.h"
+#include "PolicyAudioPort.h"
 
 namespace android {
 
@@ -34,13 +34,17 @@
 
 // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
 // and keep track of the usage of this input.
-class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
-    , public ClientMapHandler<RecordClientDescriptor>
+class AudioInputDescriptor: public AudioPortConfig,
+        public PolicyAudioPortConfig,
+        public AudioIODescriptorInterface,
+        public ClientMapHandler<RecordClientDescriptor>
 {
 public:
-    explicit AudioInputDescriptor(const sp<IOProfile>& profile,
-                                  AudioPolicyClientInterface *clientInterface);
-    audio_port_handle_t getId() const;
+    AudioInputDescriptor(const sp<IOProfile>& profile,
+                         AudioPolicyClientInterface *clientInterface);
+
+    virtual ~AudioInputDescriptor() = default;
+
     audio_module_handle_t getModuleHandle() const;
 
     audio_devices_t getDeviceType() const { return (mDevice != nullptr) ?
@@ -56,9 +60,18 @@
     wp<AudioPolicyMix>  mPolicyMix;                   // non NULL when used by a dynamic policy
     const sp<IOProfile> mProfile;                     // I/O profile this output derives from
 
+    // PolicyAudioPortConfig
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const {
+        return mProfile;
+    }
+
+    // AudioPortConfig
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
             const struct audio_port_config *srcConfig = NULL) const;
     virtual sp<AudioPort> getAudioPort() const { return mProfile; }
+
     void toAudioPort(struct audio_port *port) const;
     void setPreemptedSessions(const SortedVector<audio_session_t>& sessions);
     SortedVector<audio_session_t> getPreemptedSessions() const;
@@ -111,7 +124,6 @@
     void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
 
     audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    audio_port_handle_t  mId = AUDIO_PORT_HANDLE_NONE;
     sp<DeviceDescriptor> mDevice = nullptr; /**< current device this input is routed to */
 
     // Because a preemptible capture session can preempt another one, we end up in an endless loop
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index cd54085..41f7dfc 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -21,14 +21,15 @@
 
 #include <sys/types.h>
 
+#include <media/AudioContainers.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
 #include "AudioIODescriptorInterface.h"
-#include "AudioPort.h"
 #include "ClientDescriptor.h"
 #include "DeviceDescriptor.h"
+#include "PolicyAudioPort.h"
 #include <vector>
 
 namespace android {
@@ -138,27 +139,28 @@
 
 // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
 // and keep track of the usage of this output by each audio stream type.
-class AudioOutputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
-    , public ClientMapHandler<TrackClientDescriptor>
+class AudioOutputDescriptor: public AudioPortConfig,
+        public PolicyAudioPortConfig,
+        public AudioIODescriptorInterface,
+        public ClientMapHandler<TrackClientDescriptor>
 {
 public:
-    AudioOutputDescriptor(const sp<AudioPort>& port,
+    AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
                           AudioPolicyClientInterface *clientInterface);
     virtual ~AudioOutputDescriptor() {}
 
     void dump(String8 *dst) const override;
     void        log(const char* indent);
 
-    audio_port_handle_t getId() const;
     virtual DeviceVector devices() const { return mDevices; }
     bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
     virtual DeviceVector supportedDevices() const  { return mDevices; }
     virtual bool isDuplicated() const { return false; }
     virtual uint32_t latency() { return 0; }
-    virtual bool isFixedVolume(audio_devices_t device);
+    virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
     virtual bool setVolume(float volumeDb,
                            VolumeSource volumeSource, const StreamTypeVector &streams,
-                           audio_devices_t device,
+                           const DeviceTypeSet& deviceTypes,
                            uint32_t delayMs,
                            bool force);
 
@@ -245,9 +247,19 @@
         mRoutingActivities[ps].setMutedByDevice(isMuted);
     }
 
+    // PolicyAudioPortConfig
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const
+    {
+        return mPolicyAudioPort;
+    }
+
+    // AudioPortConfig
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                            const struct audio_port_config *srcConfig = NULL) const;
-    virtual sp<AudioPort> getAudioPort() const { return mPort; }
+    virtual sp<AudioPort> getAudioPort() const { return mPolicyAudioPort->asAudioPort(); }
+
     virtual void toAudioPort(struct audio_port *port) const;
 
     audio_module_handle_t getModuleHandle() const;
@@ -289,11 +301,10 @@
     wp<AudioPolicyMix> mPolicyMix;  // non NULL when used by a dynamic policy
 
 protected:
-    const sp<AudioPort> mPort;
+    const sp<PolicyAudioPort> mPolicyAudioPort;
     AudioPolicyClientInterface * const mClientInterface;
     uint32_t mGlobalActiveCount = 0;  // non-client-specific active count
     audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
 
     // The ActiveClients shows the clients that contribute to the @VolumeSource counts
     // and may include upstream clients from a duplicating thread.
@@ -319,10 +330,10 @@
     void setDevices(const DeviceVector &devices) { mDevices = devices; }
     bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc);
     virtual DeviceVector supportedDevices() const;
-    virtual bool deviceSupportsEncodedFormats(audio_devices_t device);
+    virtual bool devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes);
     virtual uint32_t latency();
     virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
-    virtual bool isFixedVolume(audio_devices_t device);
+    virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
     sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; }
     sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; }
     void setClientActive(const sp<TrackClientDescriptor>& client, bool active) override;
@@ -334,7 +345,7 @@
     }
     virtual bool setVolume(float volumeDb,
                            VolumeSource volumeSource, const StreamTypeVector &streams,
-                           audio_devices_t device,
+                           const DeviceTypeSet& device,
                            uint32_t delayMs,
                            bool force);
 
@@ -408,7 +419,7 @@
 
     virtual bool setVolume(float volumeDb,
                            VolumeSource volumeSource, const StreamTypeVector &streams,
-                           audio_devices_t device,
+                           const DeviceTypeSet& deviceTypes,
                            uint32_t delayMs,
                            bool force);
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 0776a8d..56596f5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -19,17 +19,17 @@
 #include <unordered_map>
 #include <unordered_set>
 
-#include <AudioGain.h>
-#include <AudioPort.h>
 #include <AudioPatch.h>
 #include <DeviceDescriptor.h>
 #include <IOProfile.h>
 #include <HwModule.h>
+#include <PolicyAudioPort.h>
 #include <AudioInputDescriptor.h>
 #include <AudioOutputDescriptor.h>
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
+#include <media/AudioProfile.h>
 
 namespace android {
 
@@ -119,9 +119,9 @@
         mSource = "AudioPolicyConfig::setDefault";
         mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
         mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
-        mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic());
+        mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
         sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
-        defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic());
+        defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
         sp<AudioProfile> micProfile = new AudioProfile(
                 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
         defaultInputDevice->addAudioProfile(micProfile);
@@ -133,14 +133,14 @@
         mDefaultOutputDevice->attach(module);
         defaultInputDevice->attach(module);
 
-        sp<OutputProfile> outProfile = new OutputProfile(String8("primary"));
+        sp<OutputProfile> outProfile = new OutputProfile("primary");
         outProfile->addAudioProfile(
                 new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
         outProfile->addSupportedDevice(mDefaultOutputDevice);
         outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
         module->addOutputProfile(outProfile);
 
-        sp<InputProfile> inProfile = new InputProfile(String8("primary"));
+        sp<InputProfile> inProfile = new InputProfile("primary");
         inProfile->addAudioProfile(micProfile);
         inProfile->addSupportedDevice(defaultInputDevice);
         module->addInputProfile(inProfile);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 094f506..fc79ab1 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -18,6 +18,7 @@
 
 #include "DeviceDescriptor.h"
 #include <utils/RefBase.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioPolicy.h>
 #include <utils/Vector.h>
 #include <system/audio.h>
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
deleted file mode 100644
index d906f11..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include "AudioCollections.h"
-#include "AudioProfile.h"
-#include "AudioGain.h"
-#include "HandleGenerator.h"
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <system/audio.h>
-#include <cutils/config_utils.h>
-
-namespace android {
-
-class HwModule;
-class AudioRoute;
-
-class AudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
-{
-public:
-    AudioPort(const String8& name, audio_port_type_t type,  audio_port_role_t role) :
-        mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
-
-    virtual ~AudioPort() {}
-
-    void setName(const String8 &name) { mName = name; }
-    const String8 &getName() const { return mName; }
-
-    audio_port_type_t getType() const { return mType; }
-    audio_port_role_t getRole() const { return mRole; }
-
-    virtual const String8 getTagName() const = 0;
-
-    void setGains(const AudioGains &gains) { mGains = gains; }
-    const AudioGains &getGains() const { return mGains; }
-
-    virtual void setFlags(uint32_t flags)
-    {
-        //force direct flag if offload flag is set: offloading implies a direct output stream
-        // and all common behaviors are driven by checking only the direct flag
-        // this should normally be set appropriately in the policy configuration file
-        if (mRole == AUDIO_PORT_ROLE_SOURCE && (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
-            flags |= AUDIO_OUTPUT_FLAG_DIRECT;
-        }
-        mFlags = flags;
-    }
-    uint32_t getFlags() const { return mFlags; }
-
-    virtual void attach(const sp<HwModule>& module);
-    virtual void detach();
-    bool isAttached() { return mModule != 0; }
-
-    // Audio port IDs are in a different namespace than AudioFlinger unique IDs
-    static audio_port_handle_t getNextUniqueId();
-
-    virtual void toAudioPort(struct audio_port *port) const;
-
-    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
-
-    void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
-
-    void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
-    AudioProfileVector &getAudioProfiles() { return mProfiles; }
-
-    bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
-
-    bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
-
-    // searches for an exact match
-    virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
-
-    // searches for a compatible match, currently implemented for input
-    // parameters are input|output, returned value is the best match.
-    status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
-                                         audio_channel_mask_t &channelMask,
-                                         audio_format_t &format) const
-    {
-        return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
-    }
-
-    void clearAudioProfiles() { return mProfiles.clearProfiles(); }
-
-    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
-
-    void pickAudioProfile(uint32_t &samplingRate,
-                          audio_channel_mask_t &channelMask,
-                          audio_format_t &format) const;
-
-    static const audio_format_t sPcmFormatCompareTable[];
-
-    static int compareFormats(audio_format_t format1, audio_format_t format2);
-
-    // Used to select an audio HAL output stream with a sample format providing the
-    // less degradation for a given AudioTrack sample format.
-    static bool isBetterFormatMatch(audio_format_t newFormat,
-                                        audio_format_t currentFormat,
-                                        audio_format_t targetFormat);
-    static uint32_t formatDistance(audio_format_t format1,
-                                   audio_format_t format2);
-    static const uint32_t kFormatDistanceMax = 4;
-
-    audio_module_handle_t getModuleHandle() const;
-    uint32_t getModuleVersionMajor() const;
-    const char *getModuleName() const;
-    sp<HwModule> getModule() const { return mModule; }
-
-    bool useInputChannelMask() const
-    {
-        return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
-                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
-    }
-
-    inline bool isDirectOutput() const
-    {
-        return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
-                (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
-    }
-
-    void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
-    const AudioRouteVector &getRoutes() const { return mRoutes; }
-
-    void dump(String8 *dst, int spaces, bool verbose = true) const;
-
-    void log(const char* indent) const;
-
-    AudioGains mGains; // gain controllers
-
-private:
-    void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
-    void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
-
-    sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
-    String8  mName;
-    audio_port_type_t mType;
-    audio_port_role_t mRole;
-    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
-    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
-    AudioRouteVector mRoutes; // Routes involving this port
-};
-
-class AudioPortConfig : public virtual RefBase
-{
-public:
-    status_t applyAudioPortConfig(const struct audio_port_config *config,
-                                  struct audio_port_config *backupConfig = NULL);
-    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
-                                   const struct audio_port_config *srcConfig = NULL) const = 0;
-    virtual sp<AudioPort> getAudioPort() const = 0;
-    virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
-        return (other != 0) && (other->getAudioPort() != 0) && (getAudioPort() != 0) &&
-                (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
-    }
-    bool hasGainController(bool canUseForVolume = false) const;
-
-    unsigned int mSamplingRate = 0u;
-    audio_format_t mFormat = AUDIO_FORMAT_INVALID;
-    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
-    struct audio_gain_config mGain = { .index = -1 };
-    union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
deleted file mode 100644
index b588d57..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#pragma once
-
-#include <vector>
-
-#include <system/audio.h>
-#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
-#include "policy.h"
-
-namespace android {
-
-typedef SortedVector<uint32_t> SampleRateVector;
-typedef Vector<audio_format_t> FormatVector;
-
-template <typename T>
-bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
-{
-    if (left.size() != right.size()) {
-        return false;
-    }
-    for (size_t index = 0; index < right.size(); index++) {
-        if (left[index] != right[index]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-template <typename T>
-bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
-{
-    return !(left == right);
-}
-
-class ChannelsVector : public SortedVector<audio_channel_mask_t>
-{
-public:
-    ChannelsVector() = default;
-    ChannelsVector(const ChannelsVector&) = default;
-    ChannelsVector(const SortedVector<audio_channel_mask_t>& sv) :
-            SortedVector<audio_channel_mask_t>(sv) {}
-    ChannelsVector& operator=(const ChannelsVector&) = default;
-
-    // Applies audio_channel_mask_out_to_in to all elements and returns the result.
-    ChannelsVector asInMask() const;
-    // Applies audio_channel_mask_in_to_out to all elements and returns the result.
-    ChannelsVector asOutMask() const;
-};
-
-class AudioProfile : public virtual RefBase
-{
-public:
-    static sp<AudioProfile> createFullDynamic();
-
-    AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
-    AudioProfile(audio_format_t format,
-                 const ChannelsVector &channelMasks,
-                 const SampleRateVector &samplingRateCollection);
-
-    audio_format_t getFormat() const { return mFormat; }
-    const ChannelsVector &getChannels() const { return mChannelMasks; }
-    const SampleRateVector &getSampleRates() const { return mSamplingRates; }
-    void setChannels(const ChannelsVector &channelMasks);
-    void setSampleRates(const SampleRateVector &sampleRates);
-
-    void clear();
-    bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
-    bool supportsChannels(audio_channel_mask_t channels) const
-    {
-        return mChannelMasks.indexOf(channels) >= 0;
-    }
-    bool supportsRate(uint32_t rate) const { return mSamplingRates.indexOf(rate) >= 0; }
-
-    status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
-    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-                                        audio_channel_mask_t &updatedChannelMask,
-                                        audio_port_type_t portType,
-                                        audio_port_role_t portRole) const;
-    status_t checkCompatibleSamplingRate(uint32_t samplingRate,
-                                         uint32_t &updatedSamplingRate) const;
-
-    bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
-    bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
-    bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }
-
-    void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
-    bool isDynamicChannels() const { return mIsDynamicChannels; }
-
-    void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
-    bool isDynamicRate() const { return mIsDynamicRate; }
-
-    void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
-    bool isDynamicFormat() const { return mIsDynamicFormat; }
-
-    bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
-
-    void dump(String8 *dst, int spaces) const;
-
-private:
-    String8  mName;
-    audio_format_t mFormat;
-    ChannelsVector mChannelMasks;
-    SampleRateVector mSamplingRates;
-
-    bool mIsDynamicFormat = false;
-    bool mIsDynamicChannels = false;
-    bool mIsDynamicRate = false;
-};
-
-
-class AudioProfileVector : public Vector<sp<AudioProfile> >
-{
-public:
-    ssize_t add(const sp<AudioProfile> &profile);
-    // This API is intended to be used by the policy manager once retrieving capabilities
-    // for a profile with dynamic format, rate and channels attributes
-    ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd);
-
-    status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
-                               audio_format_t format) const;
-    status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
-                                    audio_format_t &format,
-                                    audio_port_type_t portType,
-                                    audio_port_role_t portRole) const;
-    void clearProfiles();
-    // Assuming that this profile vector contains input profiles,
-    // find the best matching config from 'outputProfiles', according to
-    // the given preferences for audio formats and channel masks.
-    // Note: std::vectors are used because specialized containers for formats
-    //       and channels can be sorted and use their own ordering.
-    status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
-            const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
-            const std::vector<audio_channel_mask_t>& preferredOutputChannels,
-            bool preferHigherSamplingRates,
-            audio_config_base *bestOutputConfig) const;
-
-    sp<AudioProfile> getFirstValidProfile() const;
-    sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
-    bool hasValidProfile() const { return getFirstValidProfile() != 0; }
-
-    FormatVector getSupportedFormats() const;
-    bool hasDynamicChannelsFor(audio_format_t format) const;
-    bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
-    bool hasDynamicProfile() const;
-    bool hasDynamicRateFor(audio_format_t format) const;
-
-    // One audio profile will be added for each format supported by Audio HAL
-    void setFormats(const FormatVector &formats);
-
-    void dump(String8 *dst, int spaces) const;
-
-private:
-    sp<AudioProfile> getProfileFor(audio_format_t format) const;
-    void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format);
-    void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format);
-
-    static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
-};
-
-bool operator == (const AudioProfile &left, const AudioProfile &right);
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
new file mode 100644
index 0000000..f84bda7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include <media/AudioProfile.h>
+#include <system/audio.h>
+
+namespace android {
+
+void sortAudioProfiles(AudioProfileVector &audioProfileVector);
+
+ssize_t addAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                               const sp<AudioProfile> &profile);
+
+// One audio profile will be added for each format supported by Audio HAL
+void addProfilesForFormats(AudioProfileVector &audioProfileVector,
+                           const FormatVector &formatVector);
+
+// This API is intended to be used by the policy manager once retrieving capabilities
+// for a profile with dynamic format, rate and channels attributes
+void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                                   const sp<AudioProfile> &profileToAdd);
+
+void appendAudioProfiles(AudioProfileVector &audioProfileVector,
+                         const AudioProfileVector &audioProfileVectorToAppend);
+
+status_t checkExactProfile(const AudioProfileVector &audioProfileVector,
+                           const uint32_t samplingRate,
+                           audio_channel_mask_t channelMask,
+                           audio_format_t format);
+
+status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
+                                uint32_t &samplingRate,
+                                audio_channel_mask_t &channelMask,
+                                audio_format_t &format,
+                                audio_port_type_t portType,
+                                audio_port_role_t portRole);
+
+// Assuming that this profile vector contains input profiles,
+// find the best matching config from 'outputProfiles', according to
+// the given preferences for audio formats and channel masks.
+// Note: std::vectors are used because specialized containers for formats
+//       and channels can be sorted and use their own ordering.
+status_t findBestMatchingOutputConfig(
+        const AudioProfileVector &audioProfileVector,
+        const AudioProfileVector &outputProfileVector,
+        const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
+        const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
+        bool preferHigherSamplingRates,
+        audio_config_base &bestOutputConfig);
+
+
+} // namespace android
\ No newline at end of file
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
index 0357ff4..a7def3e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -25,7 +25,7 @@
 namespace android
 {
 
-class AudioPort;
+class PolicyAudioPort;
 class DeviceDescriptor;
 
 typedef enum {
@@ -38,11 +38,11 @@
 public:
     explicit AudioRoute(audio_route_type_t type) : mType(type) {}
 
-    void setSources(const AudioPortVector &sources) { mSources = sources; }
-    const AudioPortVector &getSources() const { return mSources; }
+    void setSources(const PolicyAudioPortVector &sources) { mSources = sources; }
+    const PolicyAudioPortVector &getSources() const { return mSources; }
 
-    void setSink(const sp<AudioPort> &sink) { mSink = sink; }
-    const sp<AudioPort> &getSink() const { return mSink; }
+    void setSink(const sp<PolicyAudioPort> &sink) { mSink = sink; }
+    const sp<PolicyAudioPort> &getSink() const { return mSink; }
 
     audio_route_type_t getType() const { return mType; }
 
@@ -57,13 +57,14 @@
      * @return true if the audio route supports the connection between the sink and the source,
      * false otherwise
      */
-    bool supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const;
+    bool supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                       const sp<PolicyAudioPort> &dstPort) const;
 
     void dump(String8 *dst, int spaces) const;
 
 private:
-    AudioPortVector mSources;
-    sp<AudioPort> mSink;
+    PolicyAudioPortVector mSources;
+    sp<PolicyAudioPort> mSink;
     audio_route_type_t mType;
 
 };
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 33e506f..a6562d7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -16,7 +16,9 @@
 
 #pragma once
 
-#include "AudioPort.h"
+#include "PolicyAudioPort.h"
+#include <media/AudioContainers.h>
+#include <media/DeviceDescriptorBase.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/SortedVector.h>
@@ -26,21 +28,26 @@
 
 namespace android {
 
-class DeviceDescriptor : public AudioPort, public AudioPortConfig
+class DeviceDescriptor : public DeviceDescriptorBase,
+                         public PolicyAudioPort, public PolicyAudioPortConfig
 {
 public:
      // Note that empty name refers by convention to a generic device.
-    explicit DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
-    DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
-            const String8 &tagName = String8(""));
+    explicit DeviceDescriptor(audio_devices_t type);
+    DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+            const FormatVector &encodedFormats = FormatVector{});
+    DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+            const std::string &address, const FormatVector &encodedFormats = FormatVector{});
+    DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr, const std::string &tagName = "",
+            const FormatVector &encodedFormats = FormatVector{});
 
     virtual ~DeviceDescriptor() {}
 
-    virtual const String8 getTagName() const { return mTagName; }
+    virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+        addAudioProfileAndSort(mProfiles, profile);
+    }
 
-    audio_devices_t type() const { return mDeviceType; }
-    String8 address() const { return mAddress; }
-    void setAddress(const String8 &address) { mAddress = address; }
+    virtual const std::string getTagName() const { return mTagName; }
 
     const FormatVector& encodedFormats() const { return mEncodedFormats; }
 
@@ -56,36 +63,42 @@
 
     bool supportsFormat(audio_format_t format);
 
+    // PolicyAudioPortConfig
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const {
+        return static_cast<PolicyAudioPort*>(const_cast<DeviceDescriptor*>(this));
+    }
+
     // AudioPortConfig
-    virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; }
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
             const struct audio_port_config *srcConfig = NULL) const;
 
-    // AudioPort
+    // PolicyAudioPort
+    virtual sp<AudioPort> asAudioPort() const {
+        return static_cast<AudioPort*>(const_cast<DeviceDescriptor*>(this));
+    }
     virtual void attach(const sp<HwModule>& module);
     virtual void detach();
 
+    // AudioPort
     virtual void toAudioPort(struct audio_port *port) const;
-    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
 
-    audio_port_handle_t getId() const;
+    void importAudioPortAndPickAudioProfile(const sp<PolicyAudioPort>& policyPort,
+                                            bool force = false);
+
     void dump(String8 *dst, int spaces, int index, bool verbose = true) const;
-    void log() const;
-    std::string toString() const;
 
 private:
-    String8 mAddress{""};
-    String8 mTagName; // Unique human readable identifier for a device port found in conf file.
-    audio_devices_t     mDeviceType;
+    std::string mTagName; // Unique human readable identifier for a device port found in conf file.
     FormatVector        mEncodedFormats;
-    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
     audio_format_t      mCurrentEncodedFormat;
 };
 
 class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
 {
 public:
-    DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
+    DeviceVector() : SortedVector() {}
     explicit DeviceVector(const sp<DeviceDescriptor>& item) : DeviceVector()
     {
         add(item);
@@ -97,13 +110,16 @@
     void remove(const DeviceVector &devices);
     ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
 
-    audio_devices_t types() const { return mDeviceTypes; }
+    DeviceTypeSet types() const { return mDeviceTypes; }
 
     // If 'address' is empty and 'codec' is AUDIO_FORMAT_DEFAULT, a device with a non-empty
     // address may be returned if there is no device with the specified 'type' and empty address.
     sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address,
                                    audio_format_t codec) const;
-    DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
+    DeviceVector getDevicesFromTypes(const DeviceTypeSet& types) const;
+    DeviceVector getDevicesFromType(audio_devices_t type) const {
+        return getDevicesFromTypes({type});
+    }
 
     /**
      * @brief getDeviceFromId
@@ -112,9 +128,35 @@
      * equal to AUDIO_PORT_HANDLE_NONE, it also returns a nullptr.
      */
     sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
-    sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
+    sp<DeviceDescriptor> getDeviceFromTagName(const std::string &tagName) const;
     DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
-    audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
+
+    DeviceVector getFirstDevicesFromTypes(std::vector<audio_devices_t> orderedTypes) const;
+    sp<DeviceDescriptor> getFirstExistingDevice(std::vector<audio_devices_t> orderedTypes) const;
+
+    // Return device descriptor that is used to open an input/output stream.
+    // Null pointer will be returned if
+    //     1) this collection is empty
+    //     2) the device descriptors are not the same category(input or output)
+    //     3) there are more than one device type for input case
+    //     4) the combination of all devices is invalid for selection
+    sp<DeviceDescriptor> getDeviceForOpening() const;
+
+    // If there are devices with the given type and the devices to add is not empty,
+    // remove all the devices with the given type and add all the devices to add.
+    void replaceDevicesByType(audio_devices_t typeToRemove, const DeviceVector &devicesToAdd);
+
+    bool containsDeviceAmongTypes(const DeviceTypeSet& deviceTypes) const {
+        return !Intersection(mDeviceTypes, deviceTypes).empty();
+    }
+
+    bool containsDeviceWithType(audio_devices_t deviceType) const {
+        return containsDeviceAmongTypes({deviceType});
+    }
+
+    bool onlyContainsDevicesWithType(audio_devices_t deviceType) const {
+        return isSingleDeviceType(mDeviceTypes, deviceType);
+    }
 
     bool contains(const sp<DeviceDescriptor>& item) const { return indexOf(item) >= 0; }
 
@@ -196,7 +238,7 @@
     {
         for (const auto &device : *this) {
             if (device->address() != "") {
-                return device->address();
+                return String8(device->address().c_str());
             }
         }
         return String8("");
@@ -208,7 +250,7 @@
 
 private:
     void refreshTypes();
-    audio_devices_t mDeviceTypes;
+    DeviceTypeSet mDeviceTypes;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index eb34da4..23f0c9a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -82,19 +82,19 @@
     status_t addInputProfile(const sp<IOProfile> &profile);
     status_t addProfile(const sp<IOProfile> &profile);
 
-    status_t addOutputProfile(const String8& name, const audio_config_t *config,
+    status_t addOutputProfile(const std::string& name, const audio_config_t *config,
             audio_devices_t device, const String8& address);
-    status_t removeOutputProfile(const String8& name);
-    status_t addInputProfile(const String8& name, const audio_config_t *config,
+    status_t removeOutputProfile(const std::string& name);
+    status_t addInputProfile(const std::string& name, const audio_config_t *config,
             audio_devices_t device, const String8& address);
-    status_t removeInputProfile(const String8& name);
+    status_t removeInputProfile(const std::string& name);
 
     audio_module_handle_t getHandle() const { return mHandle; }
     void setHandle(audio_module_handle_t handle);
 
-    sp<AudioPort> findPortByTagName(const String8 &tagName) const
+    sp<PolicyAudioPort> findPortByTagName(const std::string &tagName) const
     {
-        return mPorts.findByTagName(tagName);
+        return findByTagName(mPorts, tagName);
     }
 
     /**
@@ -106,7 +106,8 @@
      * @return true if the HwModule supports the connection between the sink and the source,
      * false otherwise
      */
-    bool supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const;
+    bool supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                       const sp<PolicyAudioPort> &dstPort) const;
 
     // TODO remove from here (split serialization)
     void dump(String8 *dst) const;
@@ -122,7 +123,7 @@
     DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
     DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
     AudioRouteVector mRoutes;
-    AudioPortVector mPorts;
+    PolicyAudioPortVector mPorts;
 };
 
 class HwModuleCollection : public Vector<sp<HwModule> >
@@ -130,8 +131,8 @@
 public:
     sp<HwModule> getModuleFromName(const char *name) const;
 
-    sp<HwModule> getModuleForDeviceTypes(audio_devices_t device,
-                                         audio_format_t encodedFormat) const;
+    sp<HwModule> getModuleForDeviceType(audio_devices_t device,
+                                        audio_format_t encodedFormat) const;
 
     sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device,
                                     audio_format_t encodedFormat) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index e0b56d4..2044863 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -16,8 +16,10 @@
 
 #pragma once
 
-#include "AudioPort.h"
 #include "DeviceDescriptor.h"
+#include "PolicyAudioPort.h"
+#include "policy.h"
+#include <media/AudioContainers.h>
 #include <utils/String8.h>
 #include <system/audio.h>
 
@@ -30,18 +32,28 @@
 // It is used by the policy manager to determine if an output or input is suitable for
 // a given use case,  open/close it accordingly and connect/disconnect audio tracks
 // to/from it.
-class IOProfile : public AudioPort
+class IOProfile : public AudioPort, public PolicyAudioPort
 {
 public:
-    IOProfile(const String8 &name, audio_port_role_t role)
+    IOProfile(const std::string &name, audio_port_role_t role)
         : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
           maxOpenCount(1),
           curOpenCount(0),
           maxActiveCount(1),
           curActiveCount(0) {}
 
+    virtual ~IOProfile() = default;
+
     // For a Profile aka MixPort, tag name and name are equivalent.
-    virtual const String8 getTagName() const { return getName(); }
+    virtual const std::string getTagName() const { return getName(); }
+
+    virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+        addAudioProfileAndSort(mProfiles, profile);
+    }
+
+    virtual sp<AudioPort> asAudioPort() const {
+        return static_cast<AudioPort*>(const_cast<IOProfile*>(this));
+    }
 
     // FIXME: this is needed because shared MMAP stream clients use the same audio session.
     // Once capture clients are tracked individually and not per session this can be removed
@@ -51,7 +63,7 @@
     // flags are parsed before maxActiveCount by the serializer.
     void setFlags(uint32_t flags) override
     {
-        AudioPort::setFlags(flags);
+        PolicyAudioPort::setFlags(flags);
         if (getRole() == AUDIO_PORT_ROLE_SINK && (flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
             maxActiveCount = 0;
         }
@@ -91,15 +103,12 @@
 
     bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
 
-    bool supportsDeviceTypes(audio_devices_t device) const
+    bool supportsDeviceTypes(const DeviceTypeSet& deviceTypes) const
     {
-        if (audio_is_output_devices(device)) {
-            if (deviceSupportsEncodedFormats(device)) {
-                return mSupportedDevices.types() & device;
-            }
-            return false;
-        }
-        return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
+        const bool areOutputDevices = Intersection(deviceTypes, getAudioDeviceInAllSet()).empty();
+        const bool devicesSupported = !mSupportedDevices.getDevicesFromTypes(deviceTypes).empty();
+        return devicesSupported &&
+               (!areOutputDevices || devicesSupportEncodedFormats(deviceTypes));
     }
 
     /**
@@ -114,18 +123,18 @@
     bool supportsDevice(const sp<DeviceDescriptor> &device, bool forceCheckOnAddress = false) const
     {
         if (!device_distinguishes_on_address(device->type()) && !forceCheckOnAddress) {
-            return supportsDeviceTypes(device->type());
+            return supportsDeviceTypes(DeviceTypeSet({device->type()}));
         }
         return mSupportedDevices.contains(device);
     }
 
-    bool deviceSupportsEncodedFormats(audio_devices_t device) const
+    bool devicesSupportEncodedFormats(DeviceTypeSet deviceTypes) const
     {
-        if (device == AUDIO_DEVICE_NONE) {
+        if (deviceTypes.empty()) {
             return true; // required for isOffloadSupported() check
         }
         DeviceVector deviceList =
-            mSupportedDevices.getDevicesFromTypeMask(device);
+            mSupportedDevices.getDevicesFromTypes(deviceTypes);
         if (!deviceList.empty()) {
             return deviceList.itemAt(0)->hasCurrentEncodedFormat();
         }
@@ -183,13 +192,13 @@
 class InputProfile : public IOProfile
 {
 public:
-    explicit InputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
+    explicit InputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
 };
 
 class OutputProfile : public IOProfile
 {
 public:
-    explicit OutputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
+    explicit OutputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
index d408446..fd8b81a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
@@ -16,8 +16,9 @@
 
 #pragma once
 
-#include <system/audio.h>
 #include <Volume.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <vector>
@@ -33,7 +34,7 @@
     virtual void addCurrentVolumeIndex(audio_devices_t device, int index) = 0;
     virtual bool canBeMuted() const = 0;
     virtual int getVolumeIndexMin() const = 0;
-    virtual int getVolumeIndex(audio_devices_t device) const = 0;
+    virtual int getVolumeIndex(const DeviceTypeSet& device) const = 0;
     virtual int getVolumeIndexMax() const = 0;
     virtual float volIndexToDb(device_category device, int indexInUi) const = 0;
     virtual bool hasVolumeIndexForDevice(audio_devices_t device) const = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
new file mode 100644
index 0000000..99df3c0
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include "AudioCollections.h"
+#include "AudioProfileVectorHelper.h"
+#include "HandleGenerator.h"
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class HwModule;
+class AudioRoute;
+
+class PolicyAudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
+{
+public:
+    PolicyAudioPort() : mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
+
+    virtual ~PolicyAudioPort() = default;
+
+    virtual const std::string getTagName() const = 0;
+
+    virtual sp<AudioPort> asAudioPort() const = 0;
+
+    virtual void setFlags(uint32_t flags)
+    {
+        //force direct flag if offload flag is set: offloading implies a direct output stream
+        // and all common behaviors are driven by checking only the direct flag
+        // this should normally be set appropriately in the policy configuration file
+        if (asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE &&
+                (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+            flags |= AUDIO_OUTPUT_FLAG_DIRECT;
+        }
+        mFlags = flags;
+    }
+    uint32_t getFlags() const { return mFlags; }
+
+    virtual void attach(const sp<HwModule>& module);
+    virtual void detach();
+    bool isAttached() { return mModule != 0; }
+
+    // Audio port IDs are in a different namespace than AudioFlinger unique IDs
+    static audio_port_handle_t getNextUniqueId();
+
+    // searches for an exact match
+    virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
+
+    // searches for a compatible match, currently implemented for input
+    // parameters are input|output, returned value is the best match.
+    status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+                                         audio_channel_mask_t &channelMask,
+                                         audio_format_t &format) const
+    {
+        return checkCompatibleProfile(
+                asAudioPort()->getAudioProfiles(), samplingRate, channelMask, format,
+                asAudioPort()->getType(), asAudioPort()->getRole());
+    }
+
+    void pickAudioProfile(uint32_t &samplingRate,
+                          audio_channel_mask_t &channelMask,
+                          audio_format_t &format) const;
+
+    static const audio_format_t sPcmFormatCompareTable[];
+
+    static int compareFormats(audio_format_t format1, audio_format_t format2);
+
+    // Used to select an audio HAL output stream with a sample format providing the
+    // less degradation for a given AudioTrack sample format.
+    static bool isBetterFormatMatch(audio_format_t newFormat,
+                                    audio_format_t currentFormat,
+                                    audio_format_t targetFormat);
+    static uint32_t formatDistance(audio_format_t format1,
+                                   audio_format_t format2);
+    static const uint32_t kFormatDistanceMax = 4;
+
+    audio_module_handle_t getModuleHandle() const;
+    uint32_t getModuleVersionMajor() const;
+    const char *getModuleName() const;
+    sp<HwModule> getModule() const { return mModule; }
+
+    inline bool isDirectOutput() const
+    {
+        return (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) &&
+                (asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE) &&
+                (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+    }
+
+    void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+    const AudioRouteVector &getRoutes() const { return mRoutes; }
+
+private:
+    void pickChannelMask(audio_channel_mask_t &channelMask,
+                         const ChannelMaskSet &channelMasks) const;
+    void pickSamplingRate(uint32_t &rate, const SampleRateSet &samplingRates) const;
+
+    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
+    sp<HwModule> mModule;     // audio HW module exposing this I/O stream
+    AudioRouteVector mRoutes; // Routes involving this port
+};
+
+class PolicyAudioPortConfig : public virtual RefBase
+{
+public:
+    virtual ~PolicyAudioPortConfig() = default;
+
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const = 0;
+
+    status_t validationBeforeApplyConfig(const struct audio_port_config *config) const;
+
+    void applyPolicyAudioPortConfig(const struct audio_port_config *config) {
+        if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+            mFlags = config->flags;
+        }
+    }
+
+    void toPolicyAudioPortConfig(
+            struct audio_port_config *dstConfig,
+            const struct audio_port_config *srcConfig = NULL) const;
+
+
+    virtual bool hasSameHwModuleAs(const sp<PolicyAudioPortConfig>& other) const {
+        return (other.get() != nullptr) && (other->getPolicyAudioPort().get() != nullptr) &&
+                (getPolicyAudioPort().get() != nullptr) &&
+                (other->getPolicyAudioPort()->getModuleHandle() ==
+                        getPolicyAudioPort()->getModuleHandle());
+    }
+
+    union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
+};
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
index c90a582..cd10010 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -18,16 +18,16 @@
 //#define LOG_NDEBUG 0
 
 #include "AudioCollections.h"
-#include "AudioPort.h"
 #include "AudioRoute.h"
 #include "HwModule.h"
-#include "AudioGain.h"
+#include "PolicyAudioPort.h"
 
 namespace android {
 
-sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+sp<PolicyAudioPort> findByTagName(const PolicyAudioPortVector& policyAudioPortVector,
+                                  const std::string &tagName)
 {
-    for (const auto& port : *this) {
+    for (const auto& port : policyAudioPortVector) {
         if (port->getTagName() == tagName) {
             return port;
         }
@@ -35,15 +35,15 @@
     return nullptr;
 }
 
-void AudioRouteVector::dump(String8 *dst, int spaces) const
+void dumpAudioRouteVector(const AudioRouteVector& audioRouteVector, String8 *dst, int spaces)
 {
-    if (isEmpty()) {
+    if (audioRouteVector.isEmpty()) {
         return;
     }
-    dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", size());
-    for (size_t i = 0; i < size(); i++) {
+    dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", audioRouteVector.size());
+    for (size_t i = 0; i < audioRouteVector.size(); i++) {
         dst->appendFormat("%*s- Route %zu:\n", spaces, "", i + 1);
-        itemAt(i)->dump(dst, 4);
+        audioRouteVector.itemAt(i)->dump(dst, 4);
     }
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
deleted file mode 100644
index 2725870..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2015 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 "APM::AudioGain"
-//#define LOG_NDEBUG 0
-
-//#define VERY_VERBOSE_LOGGING
-#ifdef VERY_VERBOSE_LOGGING
-#define ALOGVV ALOGV
-#else
-#define ALOGVV(a...) do { } while(0)
-#endif
-
-#include "AudioGain.h"
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <math.h>
-
-namespace android {
-
-AudioGain::AudioGain(int index, bool useInChannelMask)
-{
-    mIndex = index;
-    mUseInChannelMask = useInChannelMask;
-    memset(&mGain, 0, sizeof(struct audio_gain));
-}
-
-void AudioGain::getDefaultConfig(struct audio_gain_config *config)
-{
-    config->index = mIndex;
-    config->mode = mGain.mode;
-    config->channel_mask = mGain.channel_mask;
-    if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
-        config->values[0] = mGain.default_value;
-    } else {
-        uint32_t numValues;
-        if (mUseInChannelMask) {
-            numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
-        } else {
-            numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
-        }
-        for (size_t i = 0; i < numValues; i++) {
-            config->values[i] = mGain.default_value;
-        }
-    }
-    if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
-        config->ramp_duration_ms = mGain.min_ramp_ms;
-    }
-}
-
-status_t AudioGain::checkConfig(const struct audio_gain_config *config)
-{
-    if ((config->mode & ~mGain.mode) != 0) {
-        return BAD_VALUE;
-    }
-    if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
-        if ((config->values[0] < mGain.min_value) ||
-                    (config->values[0] > mGain.max_value)) {
-            return BAD_VALUE;
-        }
-    } else {
-        if ((config->channel_mask & ~mGain.channel_mask) != 0) {
-            return BAD_VALUE;
-        }
-        uint32_t numValues;
-        if (mUseInChannelMask) {
-            numValues = audio_channel_count_from_in_mask(config->channel_mask);
-        } else {
-            numValues = audio_channel_count_from_out_mask(config->channel_mask);
-        }
-        for (size_t i = 0; i < numValues; i++) {
-            if ((config->values[i] < mGain.min_value) ||
-                    (config->values[i] > mGain.max_value)) {
-                return BAD_VALUE;
-            }
-        }
-    }
-    if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
-        if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
-                    (config->ramp_duration_ms > mGain.max_ramp_ms)) {
-            return BAD_VALUE;
-        }
-    }
-    return NO_ERROR;
-}
-
-void AudioGain::dump(String8 *dst, int spaces, int index) const
-{
-    dst->appendFormat("%*sGain %d:\n", spaces, "", index+1);
-    dst->appendFormat("%*s- mode: %08x\n", spaces, "", mGain.mode);
-    dst->appendFormat("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
-    dst->appendFormat("%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
-    dst->appendFormat("%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
-    dst->appendFormat("%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
-    dst->appendFormat("%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
-    dst->appendFormat("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
-    dst->appendFormat("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index a096e8f..cb3c953 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -22,7 +22,6 @@
 #include <policy.h>
 #include <AudioPolicyInterface.h>
 #include "AudioInputDescriptor.h"
-#include "AudioGain.h"
 #include "AudioPolicyMix.h"
 #include "HwModule.h"
 
@@ -35,8 +34,8 @@
 {
     if (profile != NULL) {
         profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-        if (profile->mGains.size() > 0) {
-            profile->mGains[0]->getDefaultConfig(&mGain);
+        if (profile->getGains().size() > 0) {
+            profile->getGains()[0]->getDefaultConfig(&mGain);
         }
     }
 }
@@ -49,16 +48,29 @@
     return mProfile->getModuleHandle();
 }
 
-audio_port_handle_t AudioInputDescriptor::getId() const
-{
-    return mId;
-}
-
 audio_source_t AudioInputDescriptor::source() const
 {
     return getHighestPriorityAttributes().source;
 }
 
+status_t AudioInputDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+                                                    audio_port_config *backupConfig)
+{
+    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+    status_t status = NO_ERROR;
+
+    toAudioPortConfig(&localBackupConfig);
+    if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+        AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+        applyPolicyAudioPortConfig(config);
+    }
+
+    if (backupConfig != NULL) {
+        *backupConfig = localBackupConfig;
+    }
+    return status;
+}
+
 void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
                                              const struct audio_port_config *srcConfig) const
 {
@@ -71,8 +83,8 @@
     }
 
     AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+    toPolicyAudioPortConfig(dstConfig, srcConfig);
 
-    dstConfig->id = mId;
     dstConfig->role = AUDIO_PORT_ROLE_SINK;
     dstConfig->type = AUDIO_PORT_TYPE_MIX;
     dstConfig->ext.mix.hw_module = getModuleHandle();
@@ -213,7 +225,7 @@
     mDevice = device;
 
     ALOGV("opening input for device %s profile %p name %s",
-          mDevice->toString().c_str(), mProfile.get(), mProfile->getName().string());
+          mDevice->toString().c_str(), mProfile.get(), mProfile->getName().c_str());
 
     audio_devices_t deviceType = mDevice->type();
 
@@ -221,7 +233,7 @@
                                                   input,
                                                   &lConfig,
                                                   &deviceType,
-                                                  mDevice->address(),
+                                                  String8(mDevice->address().c_str()),
                                                   source,
                                                   flags);
     LOG_ALWAYS_FATAL_IF(mDevice->type() != deviceType,
@@ -235,7 +247,7 @@
         mSamplingRate = lConfig.sample_rate;
         mChannelMask = lConfig.channel_mask;
         mFormat = lConfig.format;
-        mId = AudioPort::getNextUniqueId();
+        mId = PolicyAudioPort::getNextUniqueId();
         mIoHandle = *input;
         mProfile->curOpenCount++;
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 8a60cf2..dd51658 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -21,27 +21,28 @@
 #include "AudioOutputDescriptor.h"
 #include "AudioPolicyMix.h"
 #include "IOProfile.h"
-#include "AudioGain.h"
 #include "Volume.h"
 #include "HwModule.h"
 #include "TypeConverter.h"
+#include <media/AudioGain.h>
 #include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
 
 // A device mask for all audio output devices that are considered "remote" when evaluating
 // active output devices in isStreamActiveRemotely()
-#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
 
 namespace android {
 
-AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
+DeviceTypeSet APM_AUDIO_OUT_DEVICE_REMOTE_ALL = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+
+AudioOutputDescriptor::AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
                                              AudioPolicyClientInterface *clientInterface)
-    : mPort(port), mClientInterface(clientInterface)
+    : mPolicyAudioPort(policyAudioPort), mClientInterface(clientInterface)
 {
-    if (mPort.get() != nullptr) {
-        mPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-        if (mPort->mGains.size() > 0) {
-            mPort->mGains[0]->getDefaultConfig(&mGain);
+    if (mPolicyAudioPort.get() != nullptr) {
+        mPolicyAudioPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
+        if (mPolicyAudioPort->asAudioPort()->getGains().size() > 0) {
+            mPolicyAudioPort->asAudioPort()->getGains()[0]->getDefaultConfig(&mGain);
         }
     }
 }
@@ -55,7 +56,8 @@
 
 audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const
 {
-    return mPort.get() != nullptr ? mPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
+    return mPolicyAudioPort.get() != nullptr ?
+            mPolicyAudioPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
 }
 
 audio_patch_handle_t AudioOutputDescriptor::getPatchHandle() const
@@ -68,11 +70,6 @@
     mPatchHandle = handle;
 }
 
-audio_port_handle_t AudioOutputDescriptor::getId() const
-{
-    return mId;
-}
-
 bool AudioOutputDescriptor::sharesHwModuleWith(
         const sp<AudioOutputDescriptor>& outputDesc)
 {
@@ -144,7 +141,7 @@
     return false;
 }
 
-bool AudioOutputDescriptor::isFixedVolume(audio_devices_t device __unused)
+bool AudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes __unused)
 {
     return false;
 }
@@ -152,7 +149,7 @@
 bool AudioOutputDescriptor::setVolume(float volumeDb,
                                       VolumeSource volumeSource,
                                       const StreamTypeVector &/*streams*/,
-                                      audio_devices_t /*device*/,
+                                      const DeviceTypeSet& /*deviceTypes*/,
                                       uint32_t delayMs,
                                       bool force)
 {
@@ -167,9 +164,27 @@
     return false;
 }
 
-void AudioOutputDescriptor::toAudioPortConfig(
-                                                 struct audio_port_config *dstConfig,
-                                                 const struct audio_port_config *srcConfig) const
+status_t AudioOutputDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+                                                     audio_port_config *backupConfig)
+{
+    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+    status_t status = NO_ERROR;
+
+    toAudioPortConfig(&localBackupConfig);
+    if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+        AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+        applyPolicyAudioPortConfig(config);
+    }
+
+    if (backupConfig != NULL) {
+        *backupConfig = localBackupConfig;
+    }
+    return status;
+}
+
+
+void AudioOutputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+                                              const struct audio_port_config *srcConfig) const
 {
     dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
                             AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
@@ -177,8 +192,8 @@
         dstConfig->config_mask |= srcConfig->config_mask;
     }
     AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+    toPolicyAudioPortConfig(dstConfig, srcConfig);
 
-    dstConfig->id = mId;
     dstConfig->role = AUDIO_PORT_ROLE_SOURCE;
     dstConfig->type = AUDIO_PORT_TYPE_MIX;
     dstConfig->ext.mix.hw_module = getModuleHandle();
@@ -188,7 +203,7 @@
 void AudioOutputDescriptor::toAudioPort(struct audio_port *port) const
 {
     // Should not be called for duplicated ports, see SwAudioOutputDescriptor::toAudioPortConfig.
-    mPort->toAudioPort(port);
+    mPolicyAudioPort->asAudioPort()->toAudioPort(port);
     port->id = mId;
     port->ext.mix.hw_module = getModuleHandle();
 }
@@ -320,13 +335,13 @@
     return filteredDevices.filter(devices);
 }
 
-bool SwAudioOutputDescriptor::deviceSupportsEncodedFormats(audio_devices_t device)
+bool SwAudioOutputDescriptor::devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes)
 {
     if (isDuplicated()) {
-        return (mOutput1->deviceSupportsEncodedFormats(device)
-                    || mOutput2->deviceSupportsEncodedFormats(device));
+        return (mOutput1->devicesSupportEncodedFormats(deviceTypes)
+                    || mOutput2->devicesSupportEncodedFormats(deviceTypes));
     } else {
-       return mProfile->deviceSupportsEncodedFormats(device);
+       return mProfile->devicesSupportEncodedFormats(deviceTypes);
     }
 }
 
@@ -349,16 +364,16 @@
     AudioOutputDescriptor::setClientActive(client, active);
 }
 
-bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
+bool SwAudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes)
 {
     // unit gain if rerouting to external policy
-    if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+    if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
         if (mPolicyMix != NULL) {
             ALOGV("max gain when rerouting for output=%d", mIoHandle);
             return true;
         }
     }
-    if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+    if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
         ALOGV("max gain when output device is telephony tx");
         return true;
     }
@@ -391,12 +406,12 @@
 
 bool SwAudioOutputDescriptor::setVolume(float volumeDb,
                                         VolumeSource vs, const StreamTypeVector &streamTypes,
-                                        audio_devices_t device,
+                                        const DeviceTypeSet& deviceTypes,
                                         uint32_t delayMs,
                                         bool force)
 {
     StreamTypeVector streams = streamTypes;
-    if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) {
+    if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, deviceTypes, delayMs, force)) {
         return false;
     }
     if (streams.empty()) {
@@ -406,7 +421,7 @@
         // APM loops on all group, so filter on active group to set the port gain,
         // let the other groups set the stream volume as per legacy
         // TODO: Pass in the device address and check against it.
-        if (device == devicePort->type() &&
+        if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
                 devicePort->hasGainController(true) && isActive(vs)) {
             ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
             // @todo: here we might be in trouble if the SwOutput has several active clients with
@@ -452,8 +467,11 @@
                                        audio_io_handle_t *output)
 {
     mDevices = devices;
-    const String8& address = devices.getFirstValidAddress();
-    audio_devices_t device = devices.types();
+    sp<DeviceDescriptor> device = devices.getDeviceForOpening();
+    LOG_ALWAYS_FATAL_IF(device == nullptr,
+                        "%s failed to get device descriptor for opening "
+                        "with the requested devices, all device types: %s",
+                        __func__, dumpDeviceTypes(devices.types()).c_str());
 
     audio_config_t lConfig;
     if (config == nullptr) {
@@ -483,27 +501,25 @@
     mFlags = (audio_output_flags_t)(mFlags | flags);
 
     ALOGV("opening output for device %s profile %p name %s",
-          mDevices.toString().c_str(), mProfile.get(), mProfile->getName().string());
+          mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
 
     status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
                                                    output,
                                                    &lConfig,
-                                                   &device,
-                                                   address,
+                                                   device,
                                                    &mLatency,
                                                    mFlags);
-    LOG_ALWAYS_FATAL_IF(mDevices.types() != device,
-                        "%s openOutput returned device %08x when given device %08x",
-                        __FUNCTION__, mDevices.types(), device);
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
-                            "%s openOutput returned output handle %d for device %08x",
-                            __FUNCTION__, *output, device);
+                            "%s openOutput returned output handle %d for device %s, "
+                            "selected device %s for opening",
+                            __FUNCTION__, *output, devices.toString().c_str(),
+                            device->toString().c_str());
         mSamplingRate = lConfig.sample_rate;
         mChannelMask = lConfig.channel_mask;
         mFormat = lConfig.format;
-        mId = AudioPort::getNextUniqueId();
+        mId = PolicyAudioPort::getNextUniqueId();
         mIoHandle = *output;
         mProfile->curOpenCount++;
     }
@@ -589,7 +605,7 @@
         return INVALID_OPERATION;
     }
 
-    mId = AudioPort::getNextUniqueId();
+    mId = PolicyAudioPort::getNextUniqueId();
     mIoHandle = *ioHandle;
     mOutput1 = output1;
     mOutput2 = output2;
@@ -632,12 +648,12 @@
 
 bool HwAudioOutputDescriptor::setVolume(float volumeDb,
                                         VolumeSource volumeSource, const StreamTypeVector &streams,
-                                        audio_devices_t device,
+                                        const DeviceTypeSet& deviceTypes,
                                         uint32_t delayMs,
                                         bool force)
 {
-    bool changed =
-        AudioOutputDescriptor::setVolume(volumeDb, volumeSource, streams, device, delayMs, force);
+    bool changed = AudioOutputDescriptor::setVolume(
+            volumeDb, volumeSource, streams, deviceTypes, delayMs, force);
 
     if (changed) {
       // TODO: use gain controller on source device if any to adjust volume
@@ -664,7 +680,8 @@
     for (size_t i = 0; i < this->size(); i++) {
         const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
         if (outputDesc->isActive(volumeSource, inPastMs, sysTime)
-                && ((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) == 0)) {
+                && (!(outputDesc->devices()
+                        .containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL)))) {
             return true;
         }
     }
@@ -676,7 +693,7 @@
     nsecs_t sysTime = systemTime();
     for (size_t i = 0; i < size(); i++) {
         const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-        if (((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+        if (outputDesc->devices().containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL) &&
                 outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
             // do not consider re routing (when the output is going to a dynamic policy)
             // as "remote playback"
@@ -707,9 +724,8 @@
     for (size_t i = 0; i < size(); i++) {
         sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
         if (!outputDesc->isDuplicated() &&
-             outputDesc->devices().types()  & AUDIO_DEVICE_OUT_ALL_A2DP &&
-             outputDesc->deviceSupportsEncodedFormats(
-                     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
+             outputDesc->devices().containsDeviceAmongTypes(getAudioDeviceOutAllA2dpSet()) &&
+             outputDesc->devicesSupportEncodedFormats(getAudioDeviceOutAllA2dpSet())) {
             return this->keyAt(i);
         }
     }
@@ -725,7 +741,7 @@
         sp<HwModule> primaryHwModule = primaryOutput->mProfile->getModule();
 
         for (const auto &outputProfile : primaryHwModule->getOutputProfiles()) {
-            if (outputProfile->supportsDeviceTypes(AUDIO_DEVICE_OUT_ALL_A2DP)) {
+            if (outputProfile->supportsDeviceTypes(getAudioDeviceOutAllA2dpSet())) {
                 return true;
             }
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index 3a4db90..bf0cc94 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -18,7 +18,6 @@
 //#define LOG_NDEBUG 0
 
 #include "AudioPatch.h"
-#include "AudioGain.h"
 #include "TypeConverter.h"
 
 #include <log/log.h>
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index c42923a..20c0a24 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -20,9 +20,8 @@
 #include "AudioPolicyMix.h"
 #include "TypeConverter.h"
 #include "HwModule.h"
-#include "AudioPort.h"
+#include "PolicyAudioPort.h"
 #include "IOProfile.h"
-#include "AudioGain.h"
 #include <AudioOutputDescriptor.h>
 
 namespace android {
@@ -456,9 +455,9 @@
         }
         // check if this mix goes to a device in the list of devices
         bool deviceMatch = false;
+        const AudioDeviceTypeAddr mixDevice(mix->mDeviceType, mix->mDeviceAddress.string());
         for (size_t j = 0; j < devices.size(); j++) {
-            if (devices[j].mType == mix->mDeviceType
-                    && devices[j].mAddress == mix->mDeviceAddress) {
+            if (mixDevice.equals(devices[j])) {
                 deviceMatch = true;
                 break;
             }
@@ -523,7 +522,7 @@
             }
         }
         if (ruleAllowsUid) {
-            devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress));
+            devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress.string()));
         }
     }
     return NO_ERROR;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
deleted file mode 100644
index c11490a..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Copyright (C) 2015 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 "APM::AudioPort"
-//#define LOG_NDEBUG 0
-#include "TypeConverter.h"
-#include "AudioPort.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include <policy.h>
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-namespace android {
-
-// --- AudioPort class implementation
-void AudioPort::attach(const sp<HwModule>& module)
-{
-    ALOGV("%s: attaching module %s to port %s", __FUNCTION__, getModuleName(), mName.string());
-    mModule = module;
-}
-
-void AudioPort::detach()
-{
-    mModule = nullptr;
-}
-
-// Note that is a different namespace than AudioFlinger unique IDs
-audio_port_handle_t AudioPort::getNextUniqueId()
-{
-    return getNextHandle();
-}
-
-audio_module_handle_t AudioPort::getModuleHandle() const
-{
-    return mModule != 0 ? mModule->getHandle() : AUDIO_MODULE_HANDLE_NONE;
-}
-
-uint32_t AudioPort::getModuleVersionMajor() const
-{
-    return mModule != 0 ? mModule->getHalVersionMajor() : 0;
-}
-
-const char *AudioPort::getModuleName() const
-{
-    return mModule != 0 ? mModule->getName() : "invalid module";
-}
-
-void AudioPort::toAudioPort(struct audio_port *port) const
-{
-    // TODO: update this function once audio_port structure reflects the new profile definition.
-    // For compatibility reason: flatening the AudioProfile into audio_port structure.
-    SortedVector<audio_format_t> flatenedFormats;
-    SampleRateVector flatenedRates;
-    ChannelsVector flatenedChannels;
-    for (const auto& profile : mProfiles) {
-        if (profile->isValid()) {
-            audio_format_t formatToExport = profile->getFormat();
-            const SampleRateVector &ratesToExport = profile->getSampleRates();
-            const ChannelsVector &channelsToExport = profile->getChannels();
-
-            if (flatenedFormats.indexOf(formatToExport) < 0) {
-                flatenedFormats.add(formatToExport);
-            }
-            for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
-                uint32_t rate = ratesToExport[rateIndex];
-                if (flatenedRates.indexOf(rate) < 0) {
-                    flatenedRates.add(rate);
-                }
-            }
-            for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
-                audio_channel_mask_t channels = channelsToExport[chanIndex];
-                if (flatenedChannels.indexOf(channels) < 0) {
-                    flatenedChannels.add(channels);
-                }
-            }
-            if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
-                    flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
-                    flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
-                ALOGE("%s: bailing out: cannot export profiles to port config", __FUNCTION__);
-                return;
-            }
-        }
-    }
-    port->role = mRole;
-    port->type = mType;
-    strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
-    port->num_sample_rates = flatenedRates.size();
-    port->num_channel_masks = flatenedChannels.size();
-    port->num_formats = flatenedFormats.size();
-    for (size_t i = 0; i < flatenedRates.size(); i++) {
-        port->sample_rates[i] = flatenedRates[i];
-    }
-    for (size_t i = 0; i < flatenedChannels.size(); i++) {
-        port->channel_masks[i] = flatenedChannels[i];
-    }
-    for (size_t i = 0; i < flatenedFormats.size(); i++) {
-        port->formats[i] = flatenedFormats[i];
-    }
-
-    ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
-
-    uint32_t i;
-    for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
-        port->gains[i] = mGains[i]->getGain();
-    }
-    port->num_gains = i;
-}
-
-void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
-{
-    for (const auto& profileToImport : port->mProfiles) {
-        if (profileToImport->isValid()) {
-            // Import only valid port, i.e. valid format, non empty rates and channels masks
-            bool hasSameProfile = false;
-            for (const auto& profile : mProfiles) {
-                if (*profile == *profileToImport) {
-                    // never import a profile twice
-                    hasSameProfile = true;
-                    break;
-                }
-            }
-            if (hasSameProfile) { // never import a same profile twice
-                continue;
-            }
-            addAudioProfile(profileToImport);
-        }
-    }
-}
-
-status_t AudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
-{
-    status_t status = NO_ERROR;
-    auto config_mask = config->config_mask;
-    if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
-        config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
-        status = checkGain(&config->gain, config->gain.index);
-        if (status != NO_ERROR) {
-            return status;
-        }
-    }
-    if (config_mask != 0) {
-        // TODO should we check sample_rate / channel_mask / format separately?
-        status = mProfiles.checkExactProfile(config->sample_rate,
-                                             config->channel_mask,
-                                             config->format);
-    }
-    return status;
-}
-
-void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
-{
-    pickedRate = 0;
-    // For direct outputs, pick minimum sampling rate: this helps ensuring that the
-    // channel count / sampling rate combination chosen will be supported by the connected
-    // sink
-    if (isDirectOutput()) {
-        uint32_t samplingRate = UINT_MAX;
-        for (size_t i = 0; i < samplingRates.size(); i ++) {
-            if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
-                samplingRate = samplingRates[i];
-            }
-        }
-        pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
-    } else {
-        uint32_t maxRate = SAMPLE_RATE_HZ_MAX;
-
-        // For mixed output and inputs, use max mixer sampling rates. Do not
-        // limit sampling rate otherwise
-        // For inputs, also see checkCompatibleSamplingRate().
-        if (mType != AUDIO_PORT_TYPE_MIX) {
-            maxRate = UINT_MAX;
-        }
-        // TODO: should mSamplingRates[] be ordered in terms of our preference
-        // and we return the first (and hence most preferred) match?  This is of concern if
-        // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
-        for (size_t i = 0; i < samplingRates.size(); i ++) {
-            if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
-                pickedRate = samplingRates[i];
-            }
-        }
-    }
-}
-
-void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
-                                const ChannelsVector &channelMasks) const
-{
-    pickedChannelMask = AUDIO_CHANNEL_NONE;
-    // For direct outputs, pick minimum channel count: this helps ensuring that the
-    // channel count / sampling rate combination chosen will be supported by the connected
-    // sink
-    if (isDirectOutput()) {
-        uint32_t channelCount = UINT_MAX;
-        for (size_t i = 0; i < channelMasks.size(); i ++) {
-            uint32_t cnlCount;
-            if (useInputChannelMask()) {
-                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
-            } else {
-                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
-            }
-            if ((cnlCount < channelCount) && (cnlCount > 0)) {
-                pickedChannelMask = channelMasks[i];
-                channelCount = cnlCount;
-            }
-        }
-    } else {
-        uint32_t channelCount = 0;
-        uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
-        // For mixed output and inputs, use max mixer channel count. Do not
-        // limit channel count otherwise
-        if (mType != AUDIO_PORT_TYPE_MIX) {
-            maxCount = UINT_MAX;
-        }
-        for (size_t i = 0; i < channelMasks.size(); i ++) {
-            uint32_t cnlCount;
-            if (useInputChannelMask()) {
-                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
-            } else {
-                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
-            }
-            if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
-                pickedChannelMask = channelMasks[i];
-                channelCount = cnlCount;
-            }
-        }
-    }
-}
-
-/* format in order of increasing preference */
-const audio_format_t AudioPort::sPcmFormatCompareTable[] = {
-        AUDIO_FORMAT_DEFAULT,
-        AUDIO_FORMAT_PCM_16_BIT,
-        AUDIO_FORMAT_PCM_8_24_BIT,
-        AUDIO_FORMAT_PCM_24_BIT_PACKED,
-        AUDIO_FORMAT_PCM_32_BIT,
-        AUDIO_FORMAT_PCM_FLOAT,
-};
-
-int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
-{
-    // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
-    // compressed format and better than any PCM format. This is by design of pickFormat()
-    if (!audio_is_linear_pcm(format1)) {
-        if (!audio_is_linear_pcm(format2)) {
-            return 0;
-        }
-        return 1;
-    }
-    if (!audio_is_linear_pcm(format2)) {
-        return -1;
-    }
-
-    int index1 = -1, index2 = -1;
-    for (size_t i = 0;
-            (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
-            i ++) {
-        if (sPcmFormatCompareTable[i] == format1) {
-            index1 = i;
-        }
-        if (sPcmFormatCompareTable[i] == format2) {
-            index2 = i;
-        }
-    }
-    // format1 not found => index1 < 0 => format2 > format1
-    // format2 not found => index2 < 0 => format2 < format1
-    return index1 - index2;
-}
-
-uint32_t AudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
-{
-    if (format1 == format2) {
-        return 0;
-    }
-    if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
-        return kFormatDistanceMax;
-    }
-    int diffBytes = (int)audio_bytes_per_sample(format1) -
-            audio_bytes_per_sample(format2);
-
-    return abs(diffBytes);
-}
-
-bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
-                                    audio_format_t currentFormat,
-                                    audio_format_t targetFormat)
-{
-    return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
-}
-
-void AudioPort::pickAudioProfile(uint32_t &samplingRate,
-                                 audio_channel_mask_t &channelMask,
-                                 audio_format_t &format) const
-{
-    format = AUDIO_FORMAT_DEFAULT;
-    samplingRate = 0;
-    channelMask = AUDIO_CHANNEL_NONE;
-
-    // special case for uninitialized dynamic profile
-    if (!mProfiles.hasValidProfile()) {
-        return;
-    }
-    audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
-    // For mixed output and inputs, use best mixer output format.
-    // Do not limit format otherwise
-    if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
-        bestFormat = AUDIO_FORMAT_INVALID;
-    }
-
-    for (size_t i = 0; i < mProfiles.size(); i ++) {
-        if (!mProfiles[i]->isValid()) {
-            continue;
-        }
-        audio_format_t formatToCompare = mProfiles[i]->getFormat();
-        if ((compareFormats(formatToCompare, format) > 0) &&
-                (compareFormats(formatToCompare, bestFormat) <= 0)) {
-            uint32_t pickedSamplingRate = 0;
-            audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
-            pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
-            pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
-
-            if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
-                    && pickedSamplingRate != 0) {
-                format = formatToCompare;
-                channelMask = pickedChannelMask;
-                samplingRate = pickedSamplingRate;
-                // TODO: shall we return on the first one or still trying to pick a better Profile?
-            }
-        }
-    }
-    ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__, mName.string(),
-          samplingRate, channelMask, format);
-}
-
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
-{
-    if (index < 0 || (size_t)index >= mGains.size()) {
-        return BAD_VALUE;
-    }
-    return mGains[index]->checkConfig(gainConfig);
-}
-
-void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
-{
-    if (!mName.isEmpty()) {
-        dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
-    }
-    if (verbose) {
-        mProfiles.dump(dst, spaces);
-
-        if (mGains.size() != 0) {
-            dst->appendFormat("%*s- gains:\n", spaces, "");
-            for (size_t i = 0; i < mGains.size(); i++) {
-                mGains[i]->dump(dst, spaces + 2, i);
-            }
-        }
-    }
-}
-
-void AudioPort::log(const char* indent) const
-{
-    ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.string(), mType, mRole);
-}
-
-// --- AudioPortConfig class implementation
-
-status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
-                                               struct audio_port_config *backupConfig)
-{
-    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
-    status_t status = NO_ERROR;
-
-    toAudioPortConfig(&localBackupConfig);
-
-    sp<AudioPort> audioport = getAudioPort();
-    if (audioport == 0) {
-        status = NO_INIT;
-        goto exit;
-    }
-    status = audioport->checkExactAudioProfile(config);
-    if (status != NO_ERROR) {
-        goto exit;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-        mSamplingRate = config->sample_rate;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-        mChannelMask = config->channel_mask;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-        mFormat = config->format;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
-        mGain = config->gain;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
-        mFlags = config->flags;
-    }
-
-exit:
-    if (status != NO_ERROR) {
-        applyAudioPortConfig(&localBackupConfig);
-    }
-    if (backupConfig != NULL) {
-        *backupConfig = localBackupConfig;
-    }
-    return status;
-}
-
-namespace {
-
-template<typename T>
-void updateField(
-        const T& portConfigField, T audio_port_config::*port_config_field,
-        struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
-        unsigned int configMask, T defaultValue)
-{
-    if (dstConfig->config_mask & configMask) {
-        if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
-            dstConfig->*port_config_field = srcConfig->*port_config_field;
-        } else {
-            dstConfig->*port_config_field = portConfigField;
-        }
-    } else {
-        dstConfig->*port_config_field = defaultValue;
-    }
-}
-
-} // namespace
-
-void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig,
-                                        const struct audio_port_config *srcConfig) const
-{
-    updateField(mSamplingRate, &audio_port_config::sample_rate,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
-    updateField(mChannelMask, &audio_port_config::channel_mask,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
-            (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
-    updateField(mFormat, &audio_port_config::format,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
-
-    sp<AudioPort> audioport = getAudioPort();
-    if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
-        dstConfig->gain = mGain;
-        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
-                && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
-            dstConfig->gain = srcConfig->gain;
-        }
-    } else {
-        dstConfig->gain.index = -1;
-    }
-    if (dstConfig->gain.index != -1) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
-    } else {
-        dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
-    }
-
-    updateField(mFlags, &audio_port_config::flags,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FLAGS, { AUDIO_INPUT_FLAG_NONE });
-}
-
-bool AudioPortConfig::hasGainController(bool canUseForVolume) const
-{
-    sp<AudioPort> audioport = getAudioPort();
-    if (audioport == nullptr) {
-        return false;
-    }
-    return canUseForVolume ? audioport->getGains().canUseForVolume()
-                           : audioport->getGains().size() > 0;
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
deleted file mode 100644
index 69d6b0c..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#include <algorithm>
-#include <set>
-#include <string>
-
-#define LOG_TAG "APM::AudioProfile"
-//#define LOG_NDEBUG 0
-
-#include <media/AudioResamplerPublic.h>
-#include <utils/Errors.h>
-
-#include "AudioGain.h"
-#include "AudioPort.h"
-#include "AudioProfile.h"
-#include "HwModule.h"
-#include "TypeConverter.h"
-
-namespace android {
-
-ChannelsVector ChannelsVector::asInMask() const
-{
-    ChannelsVector inMaskVector;
-    for (const auto& channel : *this) {
-        if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
-            inMaskVector.add(audio_channel_mask_out_to_in(channel));
-        }
-    }
-    return inMaskVector;
-}
-
-ChannelsVector ChannelsVector::asOutMask() const
-{
-    ChannelsVector outMaskVector;
-    for (const auto& channel : *this) {
-        if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
-            outMaskVector.add(audio_channel_mask_in_to_out(channel));
-        }
-    }
-    return outMaskVector;
-}
-
-bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
-{
-    return (left.getFormat() == compareTo.getFormat()) &&
-            (left.getChannels() == compareTo.getChannels()) &&
-            (left.getSampleRates() == compareTo.getSampleRates());
-}
-
-static AudioProfile* createFullDynamicImpl()
-{
-    AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
-            ChannelsVector(), SampleRateVector());
-    dynamicProfile->setDynamicFormat(true);
-    dynamicProfile->setDynamicChannels(true);
-    dynamicProfile->setDynamicRate(true);
-    return dynamicProfile;
-}
-
-// static
-sp<AudioProfile> AudioProfile::createFullDynamic()
-{
-    static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
-    return dynamicProfile;
-}
-
-AudioProfile::AudioProfile(audio_format_t format,
-                           audio_channel_mask_t channelMasks,
-                           uint32_t samplingRate) :
-        mName(String8("")),
-        mFormat(format)
-{
-    mChannelMasks.add(channelMasks);
-    mSamplingRates.add(samplingRate);
-}
-
-AudioProfile::AudioProfile(audio_format_t format,
-                           const ChannelsVector &channelMasks,
-                           const SampleRateVector &samplingRateCollection) :
-        mName(String8("")),
-        mFormat(format),
-        mChannelMasks(channelMasks),
-        mSamplingRates(samplingRateCollection) {}
-
-void AudioProfile::setChannels(const ChannelsVector &channelMasks)
-{
-    if (mIsDynamicChannels) {
-        mChannelMasks = channelMasks;
-    }
-}
-
-void AudioProfile::setSampleRates(const SampleRateVector &sampleRates)
-{
-    if (mIsDynamicRate) {
-        mSamplingRates = sampleRates;
-    }
-}
-
-void AudioProfile::clear()
-{
-    if (mIsDynamicChannels) {
-        mChannelMasks.clear();
-    }
-    if (mIsDynamicRate) {
-        mSamplingRates.clear();
-    }
-}
-
-status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
-                                  audio_format_t format) const
-{
-    if (audio_formats_match(format, mFormat) &&
-            supportsChannels(channelMask) &&
-            supportsRate(samplingRate)) {
-        return NO_ERROR;
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
-                                                   uint32_t &updatedSamplingRate) const
-{
-    ALOG_ASSERT(samplingRate > 0);
-
-    if (mSamplingRates.isEmpty()) {
-        updatedSamplingRate = samplingRate;
-        return NO_ERROR;
-    }
-
-    // Search for the closest supported sampling rate that is above (preferred)
-    // or below (acceptable) the desired sampling rate, within a permitted ratio.
-    // The sampling rates are sorted in ascending order.
-    size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
-
-    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
-    if (orderOfDesiredRate < mSamplingRates.size()) {
-        uint32_t candidate = mSamplingRates[orderOfDesiredRate];
-        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
-            updatedSamplingRate = candidate;
-            return NO_ERROR;
-        }
-    }
-    // But if we have to up-sample from a lower sampling rate, that's OK.
-    if (orderOfDesiredRate != 0) {
-        uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
-        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
-            updatedSamplingRate = candidate;
-            return NO_ERROR;
-        }
-    }
-    // leave updatedSamplingRate unmodified
-    return BAD_VALUE;
-}
-
-status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-                                                  audio_channel_mask_t &updatedChannelMask,
-                                                  audio_port_type_t portType,
-                                                  audio_port_role_t portRole) const
-{
-    if (mChannelMasks.isEmpty()) {
-        updatedChannelMask = channelMask;
-        return NO_ERROR;
-    }
-    const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
-    const bool isIndex = audio_channel_mask_get_representation(channelMask)
-            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
-    const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
-    int bestMatch = 0;
-    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
-        audio_channel_mask_t supported = mChannelMasks[i];
-        if (supported == channelMask) {
-            // Exact matches always taken.
-            updatedChannelMask = channelMask;
-            return NO_ERROR;
-        }
-
-        // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
-        if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
-            // Approximate (best) match:
-            // The match score measures how well the supported channel mask matches the
-            // desired mask, where increasing-is-better.
-            //
-            // TODO: Some tweaks may be needed.
-            // Should be a static function of the data processing library.
-            //
-            // In priority:
-            // match score = 1000 if legacy channel conversion equivalent (always prefer this)
-            // OR
-            // match score += 100 if the channel mask representations match
-            // match score += number of channels matched.
-            // match score += 100 if the channel mask representations DO NOT match
-            //   but the profile has positional channel mask and less than 2 channels.
-            //   This is for audio HAL convention to not list index masks for less than 2 channels
-            //
-            // If there are no matched channels, the mask may still be accepted
-            // but the playback or record will be silent.
-            const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
-                    == AUDIO_CHANNEL_REPRESENTATION_INDEX);
-            const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
-            int match;
-            if (isIndex && isSupportedIndex) {
-                // index equivalence
-                match = 100 + __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask)
-                            & audio_channel_mask_get_bits(supported));
-            } else if (isIndex && !isSupportedIndex) {
-                const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
-                match = __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
-                if (supportedChannelCount <= FCC_2) {
-                    match += 100;
-                }
-            } else if (!isIndex && isSupportedIndex) {
-                const uint32_t equivalentBits = (1 << channelCount) - 1;
-                match = __builtin_popcount(
-                        equivalentBits & audio_channel_mask_get_bits(supported));
-            } else {
-                // positional equivalence
-                match = 100 + __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask)
-                            & audio_channel_mask_get_bits(supported));
-                switch (supported) {
-                case AUDIO_CHANNEL_IN_FRONT_BACK:
-                case AUDIO_CHANNEL_IN_STEREO:
-                    if (channelMask == AUDIO_CHANNEL_IN_MONO) {
-                        match = 1000;
-                    }
-                    break;
-                case AUDIO_CHANNEL_IN_MONO:
-                    if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
-                            || channelMask == AUDIO_CHANNEL_IN_STEREO) {
-                        match = 1000;
-                    }
-                    break;
-                default:
-                    break;
-                }
-            }
-            if (match > bestMatch) {
-                bestMatch = match;
-                updatedChannelMask = supported;
-            }
-        }
-    }
-    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-void AudioProfile::dump(String8 *dst, int spaces) const
-{
-    dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
-             mIsDynamicChannels ? "[dynamic channels]" : "",
-             mIsDynamicRate ? "[dynamic rates]" : "");
-    if (mName.length() != 0) {
-        dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
-    }
-    std::string formatLiteral;
-    if (FormatConverter::toString(mFormat, formatLiteral)) {
-        dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
-    }
-    if (!mSamplingRates.isEmpty()) {
-        dst->appendFormat("%*s- sampling rates:", spaces, "");
-        for (size_t i = 0; i < mSamplingRates.size(); i++) {
-            dst->appendFormat("%d", mSamplingRates[i]);
-            dst->append(i == (mSamplingRates.size() - 1) ? "" : ", ");
-        }
-        dst->append("\n");
-    }
-
-    if (!mChannelMasks.isEmpty()) {
-        dst->appendFormat("%*s- channel masks:", spaces, "");
-        for (size_t i = 0; i < mChannelMasks.size(); i++) {
-            dst->appendFormat("0x%04x", mChannelMasks[i]);
-            dst->append(i == (mChannelMasks.size() - 1) ? "" : ", ");
-        }
-        dst->append("\n");
-    }
-}
-
-ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
-{
-    ssize_t index = Vector::add(profile);
-    // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
-    // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
-    // [](const audio_format_t *format1, const audio_format_t *format2) {
-    //     return compareFormats(*format1, *format2);
-    // }
-    sort(compareFormats);
-    return index;
-}
-
-ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
-{
-    // Check valid profile to add:
-    if (!profileToAdd->hasValidFormat()) {
-        return -1;
-    }
-    if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
-        FormatVector formats;
-        formats.add(profileToAdd->getFormat());
-        setFormats(FormatVector(formats));
-        return 0;
-    }
-    if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
-        setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
-        return 0;
-    }
-    if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
-        setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
-        return 0;
-    }
-    // Go through the list of profile to avoid duplicates
-    for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
-        const sp<AudioProfile> &profile = itemAt(profileIndex);
-        if (profile->isValid() && profile == profileToAdd) {
-            // Nothing to do
-            return profileIndex;
-        }
-    }
-    profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
-    return add(profileToAdd);
-}
-
-status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
-                                               audio_channel_mask_t channelMask,
-                                               audio_format_t format) const
-{
-    if (isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (const auto& profile : *this) {
-        if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
-                                                    audio_channel_mask_t &channelMask,
-                                                    audio_format_t &format,
-                                                    audio_port_type_t portType,
-                                                    audio_port_role_t portRole) const
-{
-    if (isEmpty()) {
-        return NO_ERROR;
-    }
-
-    const bool checkInexact = // when port is input and format is linear pcm
-            portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
-            && audio_is_linear_pcm(format);
-
-    // iterate from best format to worst format (reverse order)
-    for (ssize_t i = size() - 1; i >= 0 ; --i) {
-        const sp<AudioProfile> profile = itemAt(i);
-        audio_format_t formatToCompare = profile->getFormat();
-        if (formatToCompare == format ||
-                (checkInexact
-                        && formatToCompare != AUDIO_FORMAT_DEFAULT
-                        && audio_is_linear_pcm(formatToCompare))) {
-            // Compatible profile has been found, checks if this profile has compatible
-            // rate and channels as well
-            audio_channel_mask_t updatedChannels;
-            uint32_t updatedRate;
-            if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
-                                                    portType, portRole) == NO_ERROR &&
-                    profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
-                // for inexact checks we take the first linear pcm format due to sorting.
-                format = formatToCompare;
-                channelMask = updatedChannels;
-                samplingRate = updatedRate;
-                return NO_ERROR;
-            }
-        }
-    }
-    return BAD_VALUE;
-}
-
-void AudioProfileVector::clearProfiles()
-{
-    for (size_t i = size(); i != 0; ) {
-        sp<AudioProfile> profile = itemAt(--i);
-        if (profile->isDynamicFormat() && profile->hasValidFormat()) {
-            removeAt(i);
-            continue;
-        }
-        profile->clear();
-    }
-}
-
-// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
-// The result is ordered according to 'order'.
-template<typename T, typename Order>
-std::vector<typename T::value_type> intersectFilterAndOrder(
-        const T& input1, const T& input2, const Order& order)
-{
-    std::set<typename T::value_type> set1{input1.begin(), input1.end()};
-    std::set<typename T::value_type> set2{input2.begin(), input2.end()};
-    std::set<typename T::value_type> common;
-    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
-            std::inserter(common, common.begin()));
-    std::vector<typename T::value_type> result;
-    for (const auto& e : order) {
-        if (common.find(e) != common.end()) result.push_back(e);
-    }
-    return result;
-}
-
-// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
-// 'comp' is a comparator function.
-template<typename T, typename Compare>
-std::vector<typename T::value_type> intersectAndOrder(
-        const T& input1, const T& input2, Compare comp)
-{
-    std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
-    std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
-    std::vector<typename T::value_type> result;
-    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
-            std::back_inserter(result), comp);
-    return result;
-}
-
-status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
-            const std::vector<audio_format_t>& preferredFormats,
-            const std::vector<audio_channel_mask_t>& preferredOutputChannels,
-            bool preferHigherSamplingRates,
-            audio_config_base *bestOutputConfig) const
-{
-    auto formats = intersectFilterAndOrder(getSupportedFormats(),
-            outputProfiles.getSupportedFormats(), preferredFormats);
-    // Pick the best compatible profile.
-    for (const auto& f : formats) {
-        sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
-        sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
-        if (inputProfile == nullptr || outputProfile == nullptr) {
-            continue;
-        }
-        auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(),
-                outputProfile->getChannels(), preferredOutputChannels);
-        if (channels.empty()) {
-            continue;
-        }
-        auto sampleRates = preferHigherSamplingRates ?
-                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
-                        std::greater<typename SampleRateVector::value_type>()) :
-                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
-                        std::less<typename SampleRateVector::value_type>());
-        if (sampleRates.empty()) {
-            continue;
-        }
-        ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
-                __func__, *channels.begin(), *sampleRates.begin(), f);
-        bestOutputConfig->format = f;
-        bestOutputConfig->sample_rate = *sampleRates.begin();
-        bestOutputConfig->channel_mask = *channels.begin();
-        return NO_ERROR;
-    }
-    return BAD_VALUE;
-}
-
-sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->isValid()) {
-            return itemAt(i);
-        }
-    }
-    return 0;
-}
-
-sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
-            return itemAt(i);
-        }
-    }
-    return 0;
-}
-
-FormatVector AudioProfileVector::getSupportedFormats() const
-{
-    FormatVector supportedFormats;
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->hasValidFormat()) {
-            supportedFormats.add(itemAt(i)->getFormat());
-        }
-    }
-    return supportedFormats;
-}
-
-bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicChannels()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool AudioProfileVector::hasDynamicProfile() const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->isDynamic()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicRate()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void AudioProfileVector::setFormats(const FormatVector &formats)
-{
-    // Only allow to change the format of dynamic profile
-    sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
-    if (dynamicFormatProfile == 0) {
-        return;
-    }
-    for (size_t i = 0; i < formats.size(); i++) {
-        sp<AudioProfile> profile = new AudioProfile(formats[i],
-                dynamicFormatProfile->getChannels(),
-                dynamicFormatProfile->getSampleRates());
-        profile->setDynamicFormat(true);
-        profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
-        profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
-        add(profile);
-    }
-}
-
-void AudioProfileVector::dump(String8 *dst, int spaces) const
-{
-    dst->appendFormat("%*s- Profiles:\n", spaces, "");
-    for (size_t i = 0; i < size(); i++) {
-        dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
-        itemAt(i)->dump(dst, spaces + 8);
-    }
-}
-
-sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->getFormat() == format) {
-            return itemAt(i);
-        }
-    }
-    return 0;
-}
-
-void AudioProfileVector::setSampleRatesFor(
-        const SampleRateVector &sampleRates, audio_format_t format)
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicRate()) {
-            if (profile->hasValidRates()) {
-                // Need to create a new profile with same format
-                sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
-                        sampleRates);
-                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
-                add(profileToAdd);
-            } else {
-                profile->setSampleRates(sampleRates);
-            }
-            return;
-        }
-    }
-}
-
-void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicChannels()) {
-            if (profile->hasValidChannels()) {
-                // Need to create a new profile with same format
-                sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
-                        profile->getSampleRates());
-                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
-                add(profileToAdd);
-            } else {
-                profile->setChannels(channelMasks);
-            }
-            return;
-        }
-    }
-}
-
-// static
-int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
-                                       const sp<AudioProfile> *profile2)
-{
-    return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
new file mode 100644
index 0000000..8ccb8b9
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <algorithm>
+#include <set>
+#include <string>
+
+#define LOG_TAG "APM::AudioProfileVectorHelper"
+//#define LOG_NDEBUG 0
+
+#include <media/AudioContainers.h>
+#include <media/AudioResamplerPublic.h>
+#include <utils/Errors.h>
+
+#include "AudioProfileVectorHelper.h"
+#include "HwModule.h"
+#include "PolicyAudioPort.h"
+#include "policy.h"
+
+namespace android {
+
+void sortAudioProfiles(AudioProfileVector &audioProfileVector) {
+    std::sort(audioProfileVector.begin(), audioProfileVector.end(),
+            [](const sp<AudioProfile> & a, const sp<AudioProfile> & b)
+            {
+                return PolicyAudioPort::compareFormats(a->getFormat(), b->getFormat()) < 0;
+            });
+}
+
+ssize_t addAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                               const sp<AudioProfile> &profile)
+{
+    ssize_t ret = audioProfileVector.add(profile);
+    // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+    sortAudioProfiles(audioProfileVector);
+    return ret;
+}
+
+sp<AudioProfile> getAudioProfileForFormat(const AudioProfileVector &audioProfileVector,
+                                          audio_format_t format)
+{
+    for (const auto &profile : audioProfileVector) {
+        if (profile->getFormat() == format) {
+            return profile;
+        }
+    }
+    return nullptr;
+}
+
+void setSampleRatesForAudioProfiles(AudioProfileVector &audioProfileVector,
+                                    const SampleRateSet &sampleRateSet,
+                                    audio_format_t format)
+{
+    for (const auto &profile : audioProfileVector) {
+        if (profile->getFormat() == format && profile->isDynamicRate()) {
+            if (profile->hasValidRates()) {
+                // Need to create a new profile with same format
+                sp<AudioProfile> profileToAdd = new AudioProfile(
+                        format, profile->getChannels(), sampleRateSet);
+                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                addAudioProfileAndSort(audioProfileVector, profileToAdd);
+            } else {
+                profile->setSampleRates(sampleRateSet);
+            }
+            return;
+        }
+    }
+}
+
+void setChannelsForAudioProfiles(AudioProfileVector &audioProfileVector,
+                                 const ChannelMaskSet &channelMaskSet,
+                                 audio_format_t format)
+{
+    for (const auto &profile : audioProfileVector) {
+        if (profile->getFormat() == format && profile->isDynamicChannels()) {
+            if (profile->hasValidChannels()) {
+                // Need to create a new profile with same format
+                sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMaskSet,
+                        profile->getSampleRates());
+                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                addAudioProfileAndSort(audioProfileVector, profileToAdd);
+            } else {
+                profile->setChannels(channelMaskSet);
+            }
+            return;
+        }
+    }
+}
+
+void addProfilesForFormats(AudioProfileVector &audioProfileVector, const FormatVector &formatVector)
+{
+    // Only allow to change the format of dynamic profile
+    sp<AudioProfile> dynamicFormatProfile = getAudioProfileForFormat(
+            audioProfileVector, gDynamicFormat);
+    if (!dynamicFormatProfile) {
+        return;
+    }
+    for (const auto &format : formatVector) {
+        sp<AudioProfile> profile = new AudioProfile(format,
+                dynamicFormatProfile->getChannels(),
+                dynamicFormatProfile->getSampleRates());
+        profile->setDynamicFormat(true);
+        profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+        profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+        addAudioProfileAndSort(audioProfileVector, profile);
+    }
+}
+
+void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                                      const sp<AudioProfile> &profileToAdd)
+{
+    // Check valid profile to add:
+    if (!profileToAdd->hasValidFormat()) {
+        ALOGW("Adding dynamic audio profile without valid format");
+        return;
+    }
+    if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+        FormatVector formats;
+        formats.push_back(profileToAdd->getFormat());
+        addProfilesForFormats(audioProfileVector, FormatVector(formats));
+        return;
+    }
+    if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+        setSampleRatesForAudioProfiles(
+                audioProfileVector, profileToAdd->getSampleRates(), profileToAdd->getFormat());
+        return;
+    }
+    if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+        setChannelsForAudioProfiles(
+                audioProfileVector, profileToAdd->getChannels(), profileToAdd->getFormat());
+        return;
+    }
+    // Go through the list of profile to avoid duplicates
+    for (size_t profileIndex = 0; profileIndex < audioProfileVector.size(); profileIndex++) {
+        const sp<AudioProfile> &profile = audioProfileVector.at(profileIndex);
+        if (profile->isValid() && profile == profileToAdd) {
+            // Nothing to do
+            return;
+        }
+    }
+    profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+    addAudioProfileAndSort(audioProfileVector, profileToAdd);
+}
+
+void appendAudioProfiles(AudioProfileVector &audioProfileVector,
+                         const AudioProfileVector &audioProfileVectorToAppend)
+{
+    audioProfileVector.insert(audioProfileVector.end(),
+                              audioProfileVectorToAppend.begin(),
+                              audioProfileVectorToAppend.end());
+}
+
+status_t checkExact(const sp<AudioProfile> &audioProfile,
+                    uint32_t samplingRate,
+                    audio_channel_mask_t channelMask,
+                    audio_format_t format)
+{
+    if (audio_formats_match(format, audioProfile->getFormat()) &&
+            audioProfile->supportsChannels(channelMask) &&
+            audioProfile->supportsRate(samplingRate)) {
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
+status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
+                                     uint32_t samplingRate,
+                                     uint32_t &updatedSamplingRate)
+{
+    ALOG_ASSERT(samplingRate > 0);
+
+    const SampleRateSet sampleRates = audioProfile->getSampleRates();
+    if (sampleRates.empty()) {
+        updatedSamplingRate = samplingRate;
+        return NO_ERROR;
+    }
+
+    // Search for the closest supported sampling rate that is above (preferred)
+    // or below (acceptable) the desired sampling rate, within a permitted ratio.
+    // The sampling rates are sorted in ascending order.
+    auto desiredRate = sampleRates.lower_bound(samplingRate);
+
+    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+    if (desiredRate != sampleRates.end()) {
+        if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+            updatedSamplingRate = *desiredRate;
+            return NO_ERROR;
+        }
+    }
+    // But if we have to up-sample from a lower sampling rate, that's OK.
+    if (desiredRate != sampleRates.begin()) {
+        uint32_t candidate = *(--desiredRate);
+        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
+            updatedSamplingRate = candidate;
+            return NO_ERROR;
+        }
+    }
+    // leave updatedSamplingRate unmodified
+    return BAD_VALUE;
+}
+
+status_t checkCompatibleChannelMask(const sp<AudioProfile> &audioProfile,
+                                    audio_channel_mask_t channelMask,
+                                    audio_channel_mask_t &updatedChannelMask,
+                                    audio_port_type_t portType,
+                                    audio_port_role_t portRole)
+{
+    const ChannelMaskSet channelMasks = audioProfile->getChannels();
+    if (channelMasks.empty()) {
+        updatedChannelMask = channelMask;
+        return NO_ERROR;
+    }
+    const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
+    const bool isIndex = audio_channel_mask_get_representation(channelMask)
+            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+    const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
+    int bestMatch = 0;
+    for (const auto &supported : channelMasks) {
+        if (supported == channelMask) {
+            // Exact matches always taken.
+            updatedChannelMask = channelMask;
+            return NO_ERROR;
+        }
+
+        // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+        if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+            // Approximate (best) match:
+            // The match score measures how well the supported channel mask matches the
+            // desired mask, where increasing-is-better.
+            //
+            // TODO: Some tweaks may be needed.
+            // Should be a static function of the data processing library.
+            //
+            // In priority:
+            // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+            // OR
+            // match score += 100 if the channel mask representations match
+            // match score += number of channels matched.
+            // match score += 100 if the channel mask representations DO NOT match
+            //   but the profile has positional channel mask and less than 2 channels.
+            //   This is for audio HAL convention to not list index masks for less than 2 channels
+            //
+            // If there are no matched channels, the mask may still be accepted
+            // but the playback or record will be silent.
+            const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+                    == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+            const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
+            int match;
+            if (isIndex && isSupportedIndex) {
+                // index equivalence
+                match = 100 + __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask)
+                            & audio_channel_mask_get_bits(supported));
+            } else if (isIndex && !isSupportedIndex) {
+                const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
+                match = __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
+                if (supportedChannelCount <= FCC_2) {
+                    match += 100;
+                }
+            } else if (!isIndex && isSupportedIndex) {
+                const uint32_t equivalentBits = (1 << channelCount) - 1;
+                match = __builtin_popcount(
+                        equivalentBits & audio_channel_mask_get_bits(supported));
+            } else {
+                // positional equivalence
+                match = 100 + __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask)
+                            & audio_channel_mask_get_bits(supported));
+                switch (supported) {
+                case AUDIO_CHANNEL_IN_FRONT_BACK:
+                case AUDIO_CHANNEL_IN_STEREO:
+                    if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+                        match = 1000;
+                    }
+                    break;
+                case AUDIO_CHANNEL_IN_MONO:
+                    if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+                            || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+                        match = 1000;
+                    }
+                    break;
+                default:
+                    break;
+                }
+            }
+            if (match > bestMatch) {
+                bestMatch = match;
+                updatedChannelMask = supported;
+            }
+        }
+    }
+    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
+}
+
+status_t checkExactProfile(const AudioProfileVector& audioProfileVector,
+                           const uint32_t samplingRate,
+                           audio_channel_mask_t channelMask,
+                           audio_format_t format)
+{
+    if (audioProfileVector.empty()) {
+        return NO_ERROR;
+    }
+
+    for (const auto& profile : audioProfileVector) {
+        if (checkExact(profile, samplingRate, channelMask, format) == NO_ERROR) {
+            return NO_ERROR;
+        }
+    }
+    return BAD_VALUE;
+}
+
+status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
+                                uint32_t &samplingRate,
+                                audio_channel_mask_t &channelMask,
+                                audio_format_t &format,
+                                audio_port_type_t portType,
+                                audio_port_role_t portRole)
+{
+    if (audioProfileVector.empty()) {
+        return NO_ERROR;
+    }
+
+    const bool checkInexact = // when port is input and format is linear pcm
+            portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
+            && audio_is_linear_pcm(format);
+
+    // iterate from best format to worst format (reverse order)
+    for (ssize_t i = audioProfileVector.size() - 1; i >= 0 ; --i) {
+        const sp<AudioProfile> profile = audioProfileVector.at(i);
+        audio_format_t formatToCompare = profile->getFormat();
+        if (formatToCompare == format ||
+                (checkInexact
+                        && formatToCompare != AUDIO_FORMAT_DEFAULT
+                        && audio_is_linear_pcm(formatToCompare))) {
+            // Compatible profile has been found, checks if this profile has compatible
+            // rate and channels as well
+            audio_channel_mask_t updatedChannels;
+            uint32_t updatedRate;
+            if (checkCompatibleChannelMask(profile, channelMask, updatedChannels,
+                                           portType, portRole) == NO_ERROR &&
+                    checkCompatibleSamplingRate(profile, samplingRate, updatedRate) == NO_ERROR) {
+                // for inexact checks we take the first linear pcm format due to sorting.
+                format = formatToCompare;
+                channelMask = updatedChannels;
+                samplingRate = updatedRate;
+                return NO_ERROR;
+            }
+        }
+    }
+    return BAD_VALUE;
+}
+
+// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
+// The result is ordered according to 'order'.
+template<typename T, typename Order>
+std::vector<typename T::value_type> intersectFilterAndOrder(
+        const T& input1, const T& input2, const Order& order)
+{
+    std::set<typename T::value_type> set1{input1.begin(), input1.end()};
+    std::set<typename T::value_type> set2{input2.begin(), input2.end()};
+    std::set<typename T::value_type> common;
+    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+            std::inserter(common, common.begin()));
+    std::vector<typename T::value_type> result;
+    for (const auto& e : order) {
+        if (common.find(e) != common.end()) result.push_back(e);
+    }
+    return result;
+}
+
+// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
+// 'comp' is a comparator function.
+template<typename T, typename Compare>
+std::vector<typename T::value_type> intersectAndOrder(
+        const T& input1, const T& input2, Compare comp)
+{
+    std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
+    std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
+    std::vector<typename T::value_type> result;
+    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+            std::back_inserter(result), comp);
+    return result;
+}
+
+status_t findBestMatchingOutputConfig(
+        const AudioProfileVector &audioProfileVector,
+        const AudioProfileVector &outputProfileVector,
+        const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
+        const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
+        bool preferHigherSamplingRates,
+        audio_config_base &bestOutputConfig)
+{
+    auto formats = intersectFilterAndOrder(audioProfileVector.getSupportedFormats(),
+            outputProfileVector.getSupportedFormats(), preferredFormatVector);
+    // Pick the best compatible profile.
+    for (const auto& f : formats) {
+        sp<AudioProfile> inputProfile = audioProfileVector.getFirstValidProfileFor(f);
+        sp<AudioProfile> outputProfile = outputProfileVector.getFirstValidProfileFor(f);
+        if (inputProfile == nullptr || outputProfile == nullptr) {
+            continue;
+        }
+        auto channels = intersectFilterAndOrder(asOutMask(inputProfile->getChannels()),
+                outputProfile->getChannels(), preferredOutputChannelVector);
+        if (channels.empty()) {
+            continue;
+        }
+        auto sampleRates = preferHigherSamplingRates ?
+                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+                        std::greater<typename SampleRateSet::value_type>()) :
+                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+                        std::less<typename SampleRateSet::value_type>());
+        if (sampleRates.empty()) {
+            continue;
+        }
+        ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
+                __func__, *channels.begin(), *sampleRates.begin(), f);
+        bestOutputConfig.format = f;
+        bestOutputConfig.sample_rate = *sampleRates.begin();
+        bestOutputConfig.channel_mask = *channels.begin();
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
index 79f0919..2a18f19 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -19,7 +19,6 @@
 
 #include "AudioRoute.h"
 #include "HwModule.h"
-#include "AudioGain.h"
 
 namespace android
 {
@@ -27,25 +26,26 @@
 void AudioRoute::dump(String8 *dst, int spaces) const
 {
     dst->appendFormat("%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
-    dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+    dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().c_str());
     if (mSources.size() != 0) {
         dst->appendFormat("%*s- Sources: \n", spaces, "");
         for (size_t i = 0; i < mSources.size(); i++) {
-            dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+            dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().c_str());
         }
     }
     dst->append("\n");
 }
 
-bool AudioRoute::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const
+bool AudioRoute::supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                               const sp<PolicyAudioPort> &dstPort) const
 {
     if (mSink == 0 || dstPort == 0 || dstPort != mSink) {
         return false;
     }
-    ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().string());
+    ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().c_str());
     for (const auto &sourcePort : mSources) {
         if (sourcePort == srcPort) {
-            ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().string());
+            ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().c_str());
             return true;
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index ad07ab1..1dc7020 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -21,7 +21,6 @@
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include <TypeConverter.h>
-#include "AudioGain.h"
 #include "AudioOutputDescriptor.h"
 #include "AudioPatch.h"
 #include "ClientDescriptor.h"
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index ecd5b34..86dbba8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -22,52 +22,56 @@
 #include <set>
 #include "DeviceDescriptor.h"
 #include "TypeConverter.h"
-#include "AudioGain.h"
 #include "HwModule.h"
 
 namespace android {
 
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
-        DeviceDescriptor(type, FormatVector{}, tagName)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+        DeviceDescriptor(type, "" /*tagName*/)
 {
 }
 
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
-        const String8 &tagName) :
-    AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
-              audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
-                                             AUDIO_PORT_ROLE_SOURCE),
-    mTagName(tagName), mDeviceType(type), mEncodedFormats(encodedFormats)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+                                   const std::string &tagName,
+                                   const FormatVector &encodedFormats) :
+        DeviceDescriptor(type, tagName, "" /*address*/, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+                                   const std::string &tagName,
+                                   const std::string &address,
+                                   const FormatVector &encodedFormats) :
+        DeviceDescriptor(AudioDeviceTypeAddr(type, address), tagName, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr,
+                                   const std::string &tagName,
+                                   const FormatVector &encodedFormats) :
+        DeviceDescriptorBase(deviceTypeAddr), mTagName(tagName), mEncodedFormats(encodedFormats)
 {
     mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT;
-    if (audio_is_remote_submix_device(type)) {
-        mAddress = String8("0");
-    }
     /* If framework runs against a pre 5.0 Audio HAL, encoded formats are absent from the config.
      * FIXME: APM should know the version of the HAL and don't add the formats for V5.0.
      * For now, the workaround to remove AC3 and IEC61937 support on HDMI is to declare
      * something like 'encodedFormats="AUDIO_FORMAT_PCM_16_BIT"' on the HDMI devicePort.
      */
-    if (type == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.isEmpty()) {
-        mEncodedFormats.add(AUDIO_FORMAT_AC3);
-        mEncodedFormats.add(AUDIO_FORMAT_IEC61937);
+    if (mDeviceTypeAddr.mType == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.empty()) {
+        mEncodedFormats.push_back(AUDIO_FORMAT_AC3);
+        mEncodedFormats.push_back(AUDIO_FORMAT_IEC61937);
     }
 }
 
-audio_port_handle_t DeviceDescriptor::getId() const
-{
-    return mId;
-}
-
 void DeviceDescriptor::attach(const sp<HwModule>& module)
 {
-    AudioPort::attach(module);
+    PolicyAudioPort::attach(module);
     mId = getNextUniqueId();
 }
 
 void DeviceDescriptor::detach() {
     mId = AUDIO_PORT_HANDLE_NONE;
-    AudioPort::detach();
+    PolicyAudioPort::detach();
 }
 
 template<typename T>
@@ -88,7 +92,7 @@
         return false;
     }
 
-    return (mDeviceType == other->mDeviceType) && (mAddress == other->mAddress) &&
+    return mDeviceTypeAddr.equals(other->mDeviceTypeAddr) &&
            checkEqual(mEncodedFormats, other->mEncodedFormats);
 }
 
@@ -97,7 +101,7 @@
     if (!device_has_encoding_capability(type())) {
         return true;
     }
-    if (mEncodedFormats.isEmpty()) {
+    if (mEncodedFormats.empty()) {
         return true;
     }
 
@@ -106,7 +110,7 @@
 
 bool DeviceDescriptor::supportsFormat(audio_format_t format)
 {
-    if (mEncodedFormats.isEmpty()) {
+    if (mEncodedFormats.empty()) {
         return true;
     }
 
@@ -118,13 +122,69 @@
     return false;
 }
 
+status_t DeviceDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+                                                audio_port_config *backupConfig)
+{
+    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+    status_t status = NO_ERROR;
+
+    toAudioPortConfig(&localBackupConfig);
+    if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+        AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+        applyPolicyAudioPortConfig(config);
+    }
+
+    if (backupConfig != NULL) {
+        *backupConfig = localBackupConfig;
+    }
+    return status;
+}
+
+void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+                                         const struct audio_port_config *srcConfig) const
+{
+    DeviceDescriptorBase::toAudioPortConfig(dstConfig, srcConfig);
+    toPolicyAudioPortConfig(dstConfig, srcConfig);
+
+    dstConfig->ext.device.hw_module = getModuleHandle();
+}
+
+void DeviceDescriptor::toAudioPort(struct audio_port *port) const
+{
+    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
+    DeviceDescriptorBase::toAudioPort(port);
+    port->ext.device.hw_module = getModuleHandle();
+}
+
+void DeviceDescriptor::importAudioPortAndPickAudioProfile(
+        const sp<PolicyAudioPort>& policyPort, bool force) {
+    if (!force && !policyPort->asAudioPort()->hasDynamicAudioProfile()) {
+        return;
+    }
+    AudioPort::importAudioPort(policyPort->asAudioPort());
+    policyPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
+}
+
+void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
+{
+    String8 extraInfo;
+    if (!mTagName.empty()) {
+        extraInfo.appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.c_str());
+    }
+
+    std::string descBaseDumpStr;
+    DeviceDescriptorBase::dump(&descBaseDumpStr, spaces, index, extraInfo.string(), verbose);
+    dst->append(descBaseDumpStr.c_str());
+}
+
+
 void DeviceVector::refreshTypes()
 {
-    mDeviceTypes = AUDIO_DEVICE_NONE;
+    mDeviceTypes.clear();
     for (size_t i = 0; i < size(); i++) {
-        mDeviceTypes |= itemAt(i)->type();
+        mDeviceTypes.insert(itemAt(i)->type());
     }
-    ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
+    ALOGV("DeviceVector::refreshTypes() mDeviceTypes %s", dumpDeviceTypes(mDeviceTypes).c_str());
 }
 
 ssize_t DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
@@ -199,17 +259,6 @@
     return devices;
 }
 
-audio_devices_t DeviceVector::getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const
-{
-    audio_devices_t deviceTypes = AUDIO_DEVICE_NONE;
-    for (const auto& device : *this) {
-        if (device->getModuleHandle() == moduleHandle) {
-            deviceTypes |= device->type();
-        }
-    }
-    return deviceTypes;
-}
-
 sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address,
                                              audio_format_t format) const
 {
@@ -219,11 +268,11 @@
             // If format is specified, match it and ignore address
             // Otherwise if address is specified match it
             // Otherwise always match
-            if (((address == "" || itemAt(i)->address() == address) &&
+            if (((address == "" || (itemAt(i)->address().compare(address.c_str()) == 0)) &&
                  format == AUDIO_FORMAT_DEFAULT) ||
                 (itemAt(i)->supportsFormat(format) && format != AUDIO_FORMAT_DEFAULT)) {
                 device = itemAt(i);
-                if (itemAt(i)->address() == address) {
+                if (itemAt(i)->address().compare(address.c_str()) == 0) {
                     break;
                 }
             }
@@ -246,17 +295,15 @@
     return nullptr;
 }
 
-DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
+DeviceVector DeviceVector::getDevicesFromTypes(const DeviceTypeSet& types) const
 {
     DeviceVector devices;
-    bool isOutput = audio_is_output_devices(type);
-    type &= ~AUDIO_DEVICE_BIT_IN;
-    for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
-        bool curIsOutput = audio_is_output_devices(itemAt(i)->type());
-        audio_devices_t curType = itemAt(i)->type() & ~AUDIO_DEVICE_BIT_IN;
-        if ((isOutput == curIsOutput) && ((type & curType) != 0)) {
+    if (types.empty()) {
+        return devices;
+    }
+    for (size_t i = 0; i < size(); i++) {
+        if (types.count(itemAt(i)->type()) != 0) {
             devices.add(itemAt(i));
-            type &= ~curType;
             ALOGV("DeviceVector::%s() for type %08x found %p",
                     __func__, itemAt(i)->type(), itemAt(i).get());
         }
@@ -264,7 +311,7 @@
     return devices;
 }
 
-sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const std::string &tagName) const
 {
     for (const auto& device : *this) {
         if (device->getTagName() == tagName) {
@@ -274,6 +321,56 @@
     return nullptr;
 }
 
+DeviceVector DeviceVector::getFirstDevicesFromTypes(
+        std::vector<audio_devices_t> orderedTypes) const
+{
+    DeviceVector devices;
+    for (auto deviceType : orderedTypes) {
+        if (!(devices = getDevicesFromType(deviceType)).isEmpty()) {
+            break;
+        }
+    }
+    return devices;
+}
+
+sp<DeviceDescriptor> DeviceVector::getFirstExistingDevice(
+        std::vector<audio_devices_t> orderedTypes) const {
+    sp<DeviceDescriptor> device;
+    for (auto deviceType : orderedTypes) {
+        if ((device = getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT)) != nullptr) {
+            break;
+        }
+    }
+    return device;
+}
+
+sp<DeviceDescriptor> DeviceVector::getDeviceForOpening() const
+{
+    if (isEmpty()) {
+        // Return nullptr if this collection is empty.
+        return nullptr;
+    } else if (areAllOfSameDeviceType(types(), audio_is_input_device)) {
+        // For input case, return the first one when there is only one device.
+        return size() > 1 ? nullptr : *begin();
+    } else if (areAllOfSameDeviceType(types(), audio_is_output_device)) {
+        // For output case, return the device descriptor according to apm strategy.
+        audio_devices_t deviceType = apm_extract_one_audio_device(types());
+        return deviceType == AUDIO_DEVICE_NONE ? nullptr :
+                getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT);
+    }
+    // Return null pointer if the devices are not all input/output device.
+    return nullptr;
+}
+
+void DeviceVector::replaceDevicesByType(
+        audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) {
+    DeviceVector devicesToRemove = getDevicesFromType(typeToRemove);
+    if (!devicesToRemove.isEmpty() && !devicesToAdd.isEmpty()) {
+        remove(devicesToRemove);
+        add(devicesToAdd);
+    }
+}
+
 void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const
 {
     if (isEmpty()) {
@@ -285,84 +382,6 @@
     }
 }
 
-void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
-                                         const struct audio_port_config *srcConfig) const
-{
-    dstConfig->config_mask = AUDIO_PORT_CONFIG_GAIN;
-    if (mSamplingRate != 0) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
-    }
-    if (mChannelMask != AUDIO_CHANNEL_NONE) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
-    }
-    if (mFormat != AUDIO_FORMAT_INVALID) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
-    }
-
-    if (srcConfig != NULL) {
-        dstConfig->config_mask |= srcConfig->config_mask;
-    }
-
-    AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
-
-    dstConfig->id = mId;
-    dstConfig->role = audio_is_output_device(mDeviceType) ?
-                        AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
-    dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
-    dstConfig->ext.device.type = mDeviceType;
-
-    //TODO Understand why this test is necessary. i.e. why at boot time does it crash
-    // without the test?
-    // This has been demonstrated to NOT be true (at start up)
-    // ALOG_ASSERT(mModule != NULL);
-    dstConfig->ext.device.hw_module = getModuleHandle();
-    (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mAddress.string());
-}
-
-void DeviceDescriptor::toAudioPort(struct audio_port *port) const
-{
-    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceType);
-    AudioPort::toAudioPort(port);
-    port->id = mId;
-    toAudioPortConfig(&port->active_config);
-    port->ext.device.type = mDeviceType;
-    port->ext.device.hw_module = getModuleHandle();
-    (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mAddress.string());
-}
-
-void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port, bool force) {
-    if (!force && !port->hasDynamicAudioProfile()) {
-        return;
-    }
-    AudioPort::importAudioPort(port);
-    port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-}
-
-void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
-{
-    dst->appendFormat("%*sDevice %d:\n", spaces, "", index + 1);
-    if (mId != 0) {
-        dst->appendFormat("%*s- id: %2d\n", spaces, "", mId);
-    }
-    if (!mTagName.isEmpty()) {
-        dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
-    }
-
-    dst->appendFormat("%*s- type: %-48s\n", spaces, "", ::android::toString(mDeviceType).c_str());
-
-    if (mAddress.size() != 0) {
-        dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
-    }
-    AudioPort::dump(dst, spaces, verbose);
-}
-
-std::string DeviceDescriptor::toString() const
-{
-    std::stringstream sstream;
-    sstream << "type:0x" << std::hex << type() << ",@:" << mAddress;
-    return sstream.str();
-}
-
 std::string DeviceVector::toString() const
 {
     if (isEmpty()) {
@@ -411,13 +430,4 @@
     return filteredDevices;
 }
 
-void DeviceDescriptor::log() const
-{
-    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceType,
-          ::android::toString(mDeviceType).c_str(),
-          mAddress.string());
-
-    AudioPort::log("  ");
-}
-
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 1f9b725..886e4c9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -19,7 +19,6 @@
 
 #include "HwModule.h"
 #include "IOProfile.h"
-#include "AudioGain.h"
 #include <policy.h>
 #include <system/audio.h>
 
@@ -42,7 +41,7 @@
     }
 }
 
-status_t HwModule::addOutputProfile(const String8& name, const audio_config_t *config,
+status_t HwModule::addOutputProfile(const std::string& name, const audio_config_t *config,
                                     audio_devices_t device, const String8& address)
 {
     sp<IOProfile> profile = new OutputProfile(name);
@@ -50,8 +49,7 @@
     profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
                                               config->sample_rate));
 
-    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
-    devDesc->setAddress(address);
+    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
     addDynamicDevice(devDesc);
     // Reciprocally attach the device to the module
     devDesc->attach(this);
@@ -96,7 +94,7 @@
     }
 }
 
-status_t HwModule::removeOutputProfile(const String8& name)
+status_t HwModule::removeOutputProfile(const std::string& name)
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
         if (mOutputProfiles[i]->getName() == name) {
@@ -111,27 +109,26 @@
     return NO_ERROR;
 }
 
-status_t HwModule::addInputProfile(const String8& name, const audio_config_t *config,
+status_t HwModule::addInputProfile(const std::string& name, const audio_config_t *config,
                                    audio_devices_t device, const String8& address)
 {
     sp<IOProfile> profile = new InputProfile(name);
     profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
                                               config->sample_rate));
 
-    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
-    devDesc->setAddress(address);
+    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
     addDynamicDevice(devDesc);
     // Reciprocally attach the device to the module
     devDesc->attach(this);
     profile->addSupportedDevice(devDesc);
 
     ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
-          name.string(), config->sample_rate, config->channel_mask);
+          name.c_str(), config->sample_rate, config->channel_mask);
 
     return addInputProfile(profile);
 }
 
-status_t HwModule::removeInputProfile(const String8& name)
+status_t HwModule::removeInputProfile(const std::string& name)
 {
     for (size_t i = 0; i < mInputProfiles.size(); i++) {
         if (mInputProfiles[i]->getName() == name) {
@@ -157,7 +154,7 @@
 sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
 {
     sp<DeviceDescriptor> sinkDevice = 0;
-    if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+    if (route->getSink()->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
         sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
     }
     return sinkDevice;
@@ -167,7 +164,7 @@
 {
     DeviceVector sourceDevices;
     for (const auto& source : route->getSources()) {
-        if (source->getType() == AUDIO_PORT_TYPE_DEVICE) {
+        if (source->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
             sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(source->getTagName()));
         }
     }
@@ -187,20 +184,20 @@
     for (const auto& stream : mInputProfiles) {
         DeviceVector sourceDevices;
         for (const auto& route : stream->getRoutes()) {
-            sp<AudioPort> sink = route->getSink();
+            sp<PolicyAudioPort> sink = route->getSink();
             if (sink == 0 || stream != sink) {
                 ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
                 continue;
             }
             DeviceVector sourceDevicesForRoute = getRouteSourceDevices(route);
             if (sourceDevicesForRoute.isEmpty()) {
-                ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+                ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
                 continue;
             }
             sourceDevices.add(sourceDevicesForRoute);
         }
         if (sourceDevices.isEmpty()) {
-            ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+            ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
             continue;
         }
         stream->setSupportedDevices(sourceDevices);
@@ -208,14 +205,14 @@
     for (const auto& stream : mOutputProfiles) {
         DeviceVector sinkDevices;
         for (const auto& route : stream->getRoutes()) {
-            sp<AudioPort> source = route->getSources().findByTagName(stream->getTagName());
+            sp<PolicyAudioPort> source = findByTagName(route->getSources(), stream->getTagName());
             if (source == 0 || stream != source) {
                 ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
                 continue;
             }
             sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(route);
             if (sinkDevice == 0) {
-                ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+                ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().c_str());
                 continue;
             }
             sinkDevices.add(sinkDevice);
@@ -230,7 +227,8 @@
     mHandle = handle;
 }
 
-bool HwModule::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const {
+bool HwModule::supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                             const sp<PolicyAudioPort> &dstPort) const {
     for (const auto &route : mRoutes) {
         if (route->supportsPatch(srcPort, dstPort)) {
             return true;
@@ -260,7 +258,7 @@
     }
     mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
     mDynamicDevices.dump(dst, String8("Dynamic"),  2, true);
-    mRoutes.dump(dst, 2);
+    dumpAudioRouteVector(mRoutes, dst, 2);
 }
 
 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -273,14 +271,14 @@
     return nullptr;
 }
 
-sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t type,
-                                                          audio_format_t encodedFormat) const
+sp <HwModule> HwModuleCollection::getModuleForDeviceType(audio_devices_t type,
+                                                         audio_format_t encodedFormat) const
 {
     for (const auto& module : *this) {
         const auto& profiles = audio_is_output_device(type) ?
                 module->getOutputProfiles() : module->getInputProfiles();
         for (const auto& profile : profiles) {
-            if (profile->supportsDeviceTypes(type)) {
+            if (profile->supportsDeviceTypes({type})) {
                 if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
                     DeviceVector declaredDevices = module->getDeclaredDevices();
                     sp <DeviceDescriptor> deviceDesc =
@@ -300,7 +298,7 @@
 sp<HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device,
                                                      audio_format_t encodedFormat) const
 {
-    return getModuleForDeviceTypes(device->type(), encodedFormat);
+    return getModuleForDeviceType(device->type(), encodedFormat);
 }
 
 DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
@@ -335,8 +333,8 @@
             }
             if (allowToCreate) {
                 moduleDevice->attach(hwModule);
-                moduleDevice->setAddress(devAddress);
-                moduleDevice->setName(String8(name));
+                moduleDevice->setAddress(devAddress.string());
+                moduleDevice->setName(name);
             }
             return moduleDevice;
         }
@@ -354,15 +352,15 @@
                                                       const char *name,
                                                       const audio_format_t encodedFormat) const
 {
-    sp<HwModule> hwModule = getModuleForDeviceTypes(type, encodedFormat);
+    sp<HwModule> hwModule = getModuleForDeviceType(type, encodedFormat);
     if (hwModule == 0) {
         ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
               address);
         return nullptr;
     }
-    sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
-    device->setName(String8(name));
-    device->setAddress(String8(address));
+
+    sp<DeviceDescriptor> device = new DeviceDescriptor(type, name, address);
+    device->setName(name);
     device->setEncodedFormat(encodedFormat);
 
   // Add the device to the list of dynamic devices
@@ -382,7 +380,7 @@
             // @todo quid of audio profile? import the profile from device of the same type?
             const auto &isoTypeDeviceForProfile =
                 profile->getSupportedDevices().getDevice(type, String8(), AUDIO_FORMAT_DEFAULT);
-            device->importAudioPort(isoTypeDeviceForProfile, true /* force */);
+            device->importAudioPortAndPickAudioProfile(isoTypeDeviceForProfile, true /* force */);
 
             ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
                   device->toString().c_str(), profile->getTagName().c_str());
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index f755fcd..bf1a0f7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,7 +20,6 @@
 #include <system/audio-base.h>
 #include "IOProfile.h"
 #include "HwModule.h"
-#include "AudioGain.h"
 #include "TypeConverter.h"
 
 namespace android {
@@ -108,7 +107,9 @@
 
 void IOProfile::dump(String8 *dst) const
 {
-    AudioPort::dump(dst, 4);
+    std::string portStr;
+    AudioPort::dump(&portStr, 4);
+    dst->append(portStr.c_str());
 
     dst->appendFormat("    - flags: 0x%04x", getFlags());
     std::string flagsLiteral;
diff --git a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
new file mode 100644
index 0000000..8c61b90
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2015 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 "APM::PolicyAudioPort"
+//#define LOG_NDEBUG 0
+#include "TypeConverter.h"
+#include "PolicyAudioPort.h"
+#include "HwModule.h"
+#include <policy.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+namespace android {
+
+// --- PolicyAudioPort class implementation
+void PolicyAudioPort::attach(const sp<HwModule>& module)
+{
+    ALOGV("%s: attaching module %s to port %s",
+            __FUNCTION__, getModuleName(), asAudioPort()->getName().c_str());
+    mModule = module;
+}
+
+void PolicyAudioPort::detach()
+{
+    mModule = nullptr;
+}
+
+// Note that is a different namespace than AudioFlinger unique IDs
+audio_port_handle_t PolicyAudioPort::getNextUniqueId()
+{
+    return getNextHandle();
+}
+
+audio_module_handle_t PolicyAudioPort::getModuleHandle() const
+{
+    return mModule != 0 ? mModule->getHandle() : AUDIO_MODULE_HANDLE_NONE;
+}
+
+uint32_t PolicyAudioPort::getModuleVersionMajor() const
+{
+    return mModule != 0 ? mModule->getHalVersionMajor() : 0;
+}
+
+const char *PolicyAudioPort::getModuleName() const
+{
+    return mModule != 0 ? mModule->getName() : "invalid module";
+}
+
+status_t PolicyAudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
+{
+    status_t status = NO_ERROR;
+    auto config_mask = config->config_mask;
+    if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
+        config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+        status = asAudioPort()->checkGain(&config->gain, config->gain.index);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    if (config_mask != 0) {
+        // TODO should we check sample_rate / channel_mask / format separately?
+        status = checkExactProfile(asAudioPort()->getAudioProfiles(), config->sample_rate,
+                config->channel_mask, config->format);
+    }
+    return status;
+}
+
+void PolicyAudioPort::pickSamplingRate(uint32_t &pickedRate,
+                                       const SampleRateSet &samplingRates) const
+{
+    pickedRate = 0;
+    // For direct outputs, pick minimum sampling rate: this helps ensuring that the
+    // channel count / sampling rate combination chosen will be supported by the connected
+    // sink
+    if (isDirectOutput()) {
+        uint32_t samplingRate = UINT_MAX;
+        for (const auto rate : samplingRates) {
+            if ((rate < samplingRate) && (rate > 0)) {
+                samplingRate = rate;
+            }
+        }
+        pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+    } else {
+        uint32_t maxRate = SAMPLE_RATE_HZ_MAX;
+
+        // For mixed output and inputs, use max mixer sampling rates. Do not
+        // limit sampling rate otherwise
+        // For inputs, also see checkCompatibleSamplingRate().
+        if (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) {
+            maxRate = UINT_MAX;
+        }
+        // TODO: should mSamplingRates[] be ordered in terms of our preference
+        // and we return the first (and hence most preferred) match?  This is of concern if
+        // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+        for (const auto rate : samplingRates) {
+            if ((rate > pickedRate) && (rate <= maxRate)) {
+                pickedRate = rate;
+            }
+        }
+    }
+}
+
+void PolicyAudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+                                      const ChannelMaskSet &channelMasks) const
+{
+    pickedChannelMask = AUDIO_CHANNEL_NONE;
+    // For direct outputs, pick minimum channel count: this helps ensuring that the
+    // channel count / sampling rate combination chosen will be supported by the connected
+    // sink
+    if (isDirectOutput()) {
+        uint32_t channelCount = UINT_MAX;
+        for (const auto channelMask : channelMasks) {
+            uint32_t cnlCount;
+            if (asAudioPort()->useInputChannelMask()) {
+                cnlCount = audio_channel_count_from_in_mask(channelMask);
+            } else {
+                cnlCount = audio_channel_count_from_out_mask(channelMask);
+            }
+            if ((cnlCount < channelCount) && (cnlCount > 0)) {
+                pickedChannelMask = channelMask;
+                channelCount = cnlCount;
+            }
+        }
+    } else {
+        uint32_t channelCount = 0;
+        uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
+
+        // For mixed output and inputs, use max mixer channel count. Do not
+        // limit channel count otherwise
+        if (asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) {
+            maxCount = UINT_MAX;
+        }
+        for (const auto channelMask : channelMasks) {
+            uint32_t cnlCount;
+            if (asAudioPort()->useInputChannelMask()) {
+                cnlCount = audio_channel_count_from_in_mask(channelMask);
+            } else {
+                cnlCount = audio_channel_count_from_out_mask(channelMask);
+            }
+            if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+                pickedChannelMask = channelMask;
+                channelCount = cnlCount;
+            }
+        }
+    }
+}
+
+/* format in order of increasing preference */
+const audio_format_t PolicyAudioPort::sPcmFormatCompareTable[] = {
+        AUDIO_FORMAT_DEFAULT,
+        AUDIO_FORMAT_PCM_16_BIT,
+        AUDIO_FORMAT_PCM_8_24_BIT,
+        AUDIO_FORMAT_PCM_24_BIT_PACKED,
+        AUDIO_FORMAT_PCM_32_BIT,
+        AUDIO_FORMAT_PCM_FLOAT,
+};
+
+int PolicyAudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
+{
+    // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
+    // compressed format and better than any PCM format. This is by design of pickFormat()
+    if (!audio_is_linear_pcm(format1)) {
+        if (!audio_is_linear_pcm(format2)) {
+            return 0;
+        }
+        return 1;
+    }
+    if (!audio_is_linear_pcm(format2)) {
+        return -1;
+    }
+
+    int index1 = -1, index2 = -1;
+    for (size_t i = 0;
+            (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
+            i ++) {
+        if (sPcmFormatCompareTable[i] == format1) {
+            index1 = i;
+        }
+        if (sPcmFormatCompareTable[i] == format2) {
+            index2 = i;
+        }
+    }
+    // format1 not found => index1 < 0 => format2 > format1
+    // format2 not found => index2 < 0 => format2 < format1
+    return index1 - index2;
+}
+
+uint32_t PolicyAudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
+{
+    if (format1 == format2) {
+        return 0;
+    }
+    if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
+        return kFormatDistanceMax;
+    }
+    int diffBytes = (int)audio_bytes_per_sample(format1) -
+            audio_bytes_per_sample(format2);
+
+    return abs(diffBytes);
+}
+
+bool PolicyAudioPort::isBetterFormatMatch(audio_format_t newFormat,
+                                          audio_format_t currentFormat,
+                                          audio_format_t targetFormat)
+{
+    return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
+}
+
+void PolicyAudioPort::pickAudioProfile(uint32_t &samplingRate,
+                                       audio_channel_mask_t &channelMask,
+                                       audio_format_t &format) const
+{
+    format = AUDIO_FORMAT_DEFAULT;
+    samplingRate = 0;
+    channelMask = AUDIO_CHANNEL_NONE;
+
+    // special case for uninitialized dynamic profile
+    if (!asAudioPort()->hasValidAudioProfile()) {
+        return;
+    }
+    audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+    // For mixed output and inputs, use best mixer output format.
+    // Do not limit format otherwise
+    if ((asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
+        bestFormat = AUDIO_FORMAT_INVALID;
+    }
+
+    const AudioProfileVector& audioProfiles = asAudioPort()->getAudioProfiles();
+    for (size_t i = 0; i < audioProfiles.size(); i ++) {
+        if (!audioProfiles[i]->isValid()) {
+            continue;
+        }
+        audio_format_t formatToCompare = audioProfiles[i]->getFormat();
+        if ((compareFormats(formatToCompare, format) > 0) &&
+                (compareFormats(formatToCompare, bestFormat) <= 0)) {
+            uint32_t pickedSamplingRate = 0;
+            audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+            pickChannelMask(pickedChannelMask, audioProfiles[i]->getChannels());
+            pickSamplingRate(pickedSamplingRate, audioProfiles[i]->getSampleRates());
+
+            if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+                    && pickedSamplingRate != 0) {
+                format = formatToCompare;
+                channelMask = pickedChannelMask;
+                samplingRate = pickedSamplingRate;
+                // TODO: shall we return on the first one or still trying to pick a better Profile?
+            }
+        }
+    }
+    ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__,
+            asAudioPort()->getName().c_str(), samplingRate, channelMask, format);
+}
+
+// --- PolicyAudioPortConfig class implementation
+
+status_t PolicyAudioPortConfig::validationBeforeApplyConfig(
+        const struct audio_port_config *config) const
+{
+    sp<PolicyAudioPort> policyAudioPort = getPolicyAudioPort();
+    return policyAudioPort ? policyAudioPort->checkExactAudioProfile(config) : NO_INIT;
+}
+
+void PolicyAudioPortConfig::toPolicyAudioPortConfig(struct audio_port_config *dstConfig,
+                                                    const struct audio_port_config *srcConfig) const
+{
+    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+        if ((srcConfig != nullptr) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS)) {
+            dstConfig->flags = srcConfig->flags;
+        } else {
+            dstConfig->flags = mFlags;
+        }
+    } else {
+        dstConfig->flags = { AUDIO_INPUT_FLAG_NONE };
+    }
+}
+
+
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 5f820c2..4de8d3b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -406,8 +406,8 @@
             samplingRatesFromString(samplingRates, ","));
 
     profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
-    profile->setDynamicChannels(profile->getChannels().isEmpty());
-    profile->setDynamicRate(profile->getSampleRates().isEmpty());
+    profile->setDynamicChannels(profile->getChannels().empty());
+    profile->setDynamicRate(profile->getSampleRates().empty());
 
     return profile;
 }
@@ -430,16 +430,19 @@
     audio_port_role_t portRole = (role == Attributes::roleSource) ?
             AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
-    Element mixPort = new IOProfile(String8(name.c_str()), portRole);
+    Element mixPort = new IOProfile(name, portRole);
 
     AudioProfileTraits::Collection profiles;
     status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
     if (status != NO_ERROR) {
         return Status::fromStatusT(status);
     }
-    if (profiles.isEmpty()) {
-        profiles.add(AudioProfile::createFullDynamic());
+    if (profiles.empty()) {
+        profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
     }
+    // The audio profiles are in order of listed in audio policy configuration file.
+    // Sort audio profiles accroding to the format.
+    sortAudioProfiles(profiles);
     mixPort->setAudioProfiles(profiles);
 
     std::string flags = getXmlAttribute(child, Attributes::flags);
@@ -508,22 +511,20 @@
     if (!encodedFormatsLiteral.empty()) {
         encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
     }
-    Element deviceDesc = new DeviceDescriptor(type, encodedFormats, String8(name.c_str()));
-
     std::string address = getXmlAttribute(cur, Attributes::address);
-    if (!address.empty()) {
-        ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
-        deviceDesc->setAddress(String8(address.c_str()));
-    }
+    Element deviceDesc = new DeviceDescriptor(type, name, address, encodedFormats);
 
     AudioProfileTraits::Collection profiles;
     status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
     if (status != NO_ERROR) {
         return Status::fromStatusT(status);
     }
-    if (profiles.isEmpty()) {
-        profiles.add(AudioProfile::createFullDynamic());
+    if (profiles.empty()) {
+        profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
     }
+    // The audio profiles are in order of listed in audio policy configuration file.
+    // Sort audio profiles accroding to the format.
+    sortAudioProfiles(profiles);
     deviceDesc->setAudioProfiles(profiles);
 
     // Deserialize AudioGain children
@@ -532,7 +533,7 @@
         return Status::fromStatusT(status);
     }
     ALOGV("%s: adding device tag %s type %08x address %s", __func__,
-          deviceDesc->getName().string(), type, deviceDesc->address().string());
+          deviceDesc->getName().c_str(), type, deviceDesc->address().c_str());
     return deviceDesc;
 }
 
@@ -555,7 +556,7 @@
         return Status::fromStatusT(BAD_VALUE);
     }
     // Convert Sink name to port pointer
-    sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
+    sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
     if (sink == NULL) {
         ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
         return Status::fromStatusT(BAD_VALUE);
@@ -568,13 +569,13 @@
         return Status::fromStatusT(BAD_VALUE);
     }
     // Tokenize and Convert Sources name to port pointer
-    AudioPortVector sources;
+    PolicyAudioPortVector sources;
     std::unique_ptr<char[]> sourcesLiteral{strndup(
                 sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
     char *devTag = strtok(sourcesLiteral.get(), ",");
     while (devTag != NULL) {
         if (strlen(devTag) != 0) {
-            sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
+            sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
             if (source == NULL) {
                 ALOGE("%s: no source found with name=%s", __func__, devTag);
                 return Status::fromStatusT(BAD_VALUE);
@@ -586,7 +587,7 @@
 
     sink->addRoute(route);
     for (size_t i = 0; i < sources.size(); i++) {
-        sp<AudioPort> source = sources.itemAt(i);
+        sp<PolicyAudioPort> source = sources.itemAt(i);
         source->addRoute(route);
     }
     route->setSources(sources);
@@ -648,7 +649,7 @@
                         ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
                                 reinterpret_cast<const char*>(attachedDevice.get()));
                         sp<DeviceDescriptor> device = module->getDeclaredDevices().
-                                getDeviceFromTagName(String8(reinterpret_cast<const char*>(
+                                getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
                                                         attachedDevice.get())));
                         ctx->addAvailableDevice(device);
                     }
@@ -663,7 +664,7 @@
                 ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
                         reinterpret_cast<const char*>(defaultOutputDevice.get()));
                 sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
-                        String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
+                        std::string(reinterpret_cast<const char*>(defaultOutputDevice.get())));
                 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                     ctx->setDefaultOutputDevice(device);
                     ALOGV("%s: default is %08x",
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
old mode 100644
new mode 100755
index d0775ad..a1c69f2
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -25,6 +25,7 @@
         "src/ProductStrategy.cpp",
         "src/VolumeCurve.cpp",
         "src/VolumeGroup.cpp",
+        "src/LastRemovableMediaDevices.cpp",
     ],
     cflags: [
         "-Wall",
@@ -44,4 +45,7 @@
         "libaudiopolicycomponents",
         "libaudiopolicyengine_config",
     ],
+    shared_libs: [
+        "libaudiofoundation",
+    ],
 }
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
old mode 100644
new mode 100755
index fca9a60..7f339dc
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -20,6 +20,7 @@
 #include <EngineInterface.h>
 #include <ProductStrategy.h>
 #include <VolumeGroup.h>
+#include <LastRemovableMediaDevices.h>
 
 namespace android {
 namespace audio_policy {
@@ -49,10 +50,8 @@
         return mForceUse[usage];
     }
     android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> /*devDesc*/,
-                                               audio_policy_dev_state_t /*state*/) override
-    {
-        return NO_ERROR;
-    }
+                                               audio_policy_dev_state_t /*state*/) override;
+
     product_strategy_t getProductStrategyForAttributes(
             const audio_attributes_t &attr) const override;
 
@@ -86,8 +85,21 @@
 
     status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const override;
 
+    std::vector<audio_devices_t> getLastRemovableMediaDevices(
+            device_out_group_t group = GROUP_NONE) const
+    {
+        return mLastRemovableMediaDevices.getLastRemovableMediaDevices(group);
+    }
+
     void dump(String8 *dst) const override;
 
+    status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+            const AudioDeviceTypeAddr &device) override;
+
+    status_t removePreferredDeviceForStrategy(product_strategy_t strategy) override;
+
+    status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+            AudioDeviceTypeAddr &device) const override;
 
     engineConfig::ParsingResult loadAudioPolicyEngineConfig();
 
@@ -115,11 +127,13 @@
 
     status_t restoreOriginVolumeCurve(audio_stream_type_t stream);
 
- private:
+private:
     AudioPolicyManagerObserver *mApmObserver = nullptr;
 
     ProductStrategyMap mProductStrategies;
+    ProductStrategyPreferredRoutingMap mProductStrategyPreferredDevices;
     VolumeGroupMap mVolumeGroups;
+    LastRemovableMediaDevices mLastRemovableMediaDevices;
     audio_mode_t mPhoneState = AUDIO_MODE_NORMAL;  /**< current phone state. */
 
     /** current forced use configuration. */
diff --git a/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
new file mode 100755
index 0000000..a3053a4
--- /dev/null
+++ b/services/audiopolicy/engine/common/include/LastRemovableMediaDevices.h
@@ -0,0 +1,52 @@
+/*
+ * 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 ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H
+#define ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H
+
+#include <vector>
+#include <HwModule.h>
+#include <system/audio_policy.h>
+
+namespace android {
+
+typedef enum {
+    GROUP_NONE = -1,
+    GROUP_WIRED,
+    GROUP_BT_A2DP,
+    NUM_GROUP
+} device_out_group_t;
+
+class LastRemovableMediaDevices
+{
+public:
+    void setRemovableMediaDevices(sp<DeviceDescriptor> desc, audio_policy_dev_state_t state);
+    std::vector<audio_devices_t> getLastRemovableMediaDevices(
+            device_out_group_t group = GROUP_NONE) const;
+
+private:
+    struct DeviceGroupDescriptor {
+        sp<DeviceDescriptor> desc;
+        device_out_group_t group;
+    };
+    std::vector<DeviceGroupDescriptor> mMediaDevices;
+
+    device_out_group_t getDeviceOutGroup(audio_devices_t device) const;
+};
+
+} // namespace android
+
+#endif // ANDROID_LAST_REMOVABLE_MEDIA_DEVICES_H
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index c538f52..3ebe7d1 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -27,6 +27,8 @@
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <media/AudioAttributes.h>
+#include <media/AudioContainers.h>
+#include <media/AudioPolicy.h>
 
 namespace android {
 
@@ -77,12 +79,12 @@
 
     std::string getDeviceAddress() const { return mDeviceAddress; }
 
-    void setDeviceTypes(audio_devices_t devices)
+    void setDeviceTypes(const DeviceTypeSet& devices)
     {
         mApplicableDevices = devices;
     }
 
-    audio_devices_t getDeviceTypes() const { return mApplicableDevices; }
+    DeviceTypeSet getDeviceTypes() const { return mApplicableDevices; }
 
     audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
     audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
@@ -109,7 +111,7 @@
     /**
      * Applicable device(s) type mask for this strategy.
      */
-    audio_devices_t mApplicableDevices = AUDIO_DEVICE_NONE;
+    DeviceTypeSet mApplicableDevices;
 };
 
 class ProductStrategyMap : public std::map<product_strategy_t, sp<ProductStrategy> >
@@ -144,7 +146,7 @@
      */
     audio_attributes_t getAttributesForProductStrategy(product_strategy_t strategy) const;
 
-    audio_devices_t getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
+    DeviceTypeSet getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
 
     std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const;
 
@@ -162,4 +164,10 @@
     product_strategy_t mDefaultStrategy = PRODUCT_STRATEGY_NONE;
 };
 
+class ProductStrategyPreferredRoutingMap : public std::map<product_strategy_t, AudioDeviceTypeAddr>
+{
+public:
+    void dump(String8 *dst, int spaces = 0) const;
+};
+
 } // namespace android
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index d3d0904..2e75ff1 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -91,9 +91,9 @@
         return valueFor(device);
     }
 
-    virtual int getVolumeIndex(audio_devices_t device) const
+    virtual int getVolumeIndex(const DeviceTypeSet& deviceTypes) const
     {
-        device = Volume::getDeviceForVolume(device);
+        audio_devices_t device = Volume::getDeviceForVolume(deviceTypes);
         // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME
         if (mIndexCur.find(device) == end(mIndexCur)) {
             device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME;
@@ -114,7 +114,7 @@
 
     bool hasVolumeIndexForDevice(audio_devices_t device) const
     {
-        device = Volume::getDeviceForVolume(device);
+        device = Volume::getDeviceForVolume({device});
         return mIndexCur.find(device) != end(mIndexCur);
     }
 
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 840eb34..01efc7a 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -63,6 +63,17 @@
     return NO_ERROR;
 }
 
+status_t EngineBase::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+                                              audio_policy_dev_state_t state)
+{
+    audio_devices_t deviceType = devDesc->type();
+    if ((deviceType != AUDIO_DEVICE_NONE) && audio_is_output_device(deviceType)) {
+        mLastRemovableMediaDevices.setRemovableMediaDevices(devDesc, state);
+    }
+
+    return NO_ERROR;
+}
+
 product_strategy_t EngineBase::getProductStrategyForAttributes(const audio_attributes_t &attr) const
 {
     return mProductStrategies.getProductStrategyForAttributes(attr);
@@ -272,9 +283,57 @@
     return NO_ERROR;
 }
 
+status_t EngineBase::setPreferredDeviceForStrategy(product_strategy_t strategy,
+            const AudioDeviceTypeAddr &device)
+{
+    // verify strategy exists
+    if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
+        ALOGE("%s invalid strategy %u", __func__, strategy);
+        return BAD_VALUE;
+    }
+
+    mProductStrategyPreferredDevices[strategy] = device;
+    return NO_ERROR;
+}
+
+status_t EngineBase::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+    // verify strategy exists
+    if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
+        ALOGE("%s invalid strategy %u", __func__, strategy);
+        return BAD_VALUE;
+    }
+
+    if (mProductStrategyPreferredDevices.erase(strategy) == 0) {
+        // no preferred device was set
+        return NAME_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
+status_t EngineBase::getPreferredDeviceForStrategy(product_strategy_t strategy,
+            AudioDeviceTypeAddr &device) const
+{
+    // verify strategy exists
+    if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
+        ALOGE("%s unknown strategy %u", __func__, strategy);
+        return BAD_VALUE;
+    }
+    // preferred device for this strategy?
+    auto devIt = mProductStrategyPreferredDevices.find(strategy);
+    if (devIt == mProductStrategyPreferredDevices.end()) {
+        ALOGV("%s no preferred device for strategy %u", __func__, strategy);
+        return NAME_NOT_FOUND;
+    }
+
+    device = devIt->second;
+    return NO_ERROR;
+}
+
 void EngineBase::dump(String8 *dst) const
 {
     mProductStrategies.dump(dst, 2);
+    mProductStrategyPreferredDevices.dump(dst, 2);
     mVolumeGroups.dump(dst, 2);
 }
 
diff --git a/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
new file mode 100755
index 0000000..87b6aaf
--- /dev/null
+++ b/services/audiopolicy/engine/common/src/LastRemovableMediaDevices.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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_TAG "APM::AudioPolicyEngine/LastRemovableMediaDevices"
+//#define LOG_NDEBUG 0
+
+#include "LastRemovableMediaDevices.h"
+#include <log/log.h>
+
+namespace android {
+
+void LastRemovableMediaDevices::setRemovableMediaDevices(sp<DeviceDescriptor> desc,
+                                                         audio_policy_dev_state_t state)
+{
+    if (desc == nullptr) {
+        return;
+    } else {
+        if ((state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) &&
+                (getDeviceOutGroup(desc->type()) != GROUP_NONE)) {
+            setRemovableMediaDevices(desc, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE);
+            mMediaDevices.insert(mMediaDevices.begin(), {desc, getDeviceOutGroup(desc->type())});
+        } else if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+            for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {
+                if ((iter->desc)->equals(desc)) {
+                    mMediaDevices.erase(iter);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+std::vector<audio_devices_t> LastRemovableMediaDevices::getLastRemovableMediaDevices(
+        device_out_group_t group) const
+{
+    std::vector<audio_devices_t> ret;
+    for (auto iter = mMediaDevices.begin(); iter != mMediaDevices.end(); ++iter) {
+        if ((group == GROUP_NONE) || (group == getDeviceOutGroup((iter->desc)->type()))) {
+            ret.push_back((iter->desc)->type());
+        }
+    }
+    return ret;
+}
+
+device_out_group_t LastRemovableMediaDevices::getDeviceOutGroup(audio_devices_t device) const
+{
+    switch (device) {
+    case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+    case AUDIO_DEVICE_OUT_LINE:
+    case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+    case AUDIO_DEVICE_OUT_USB_HEADSET:
+    case AUDIO_DEVICE_OUT_USB_ACCESSORY:
+    case AUDIO_DEVICE_OUT_USB_DEVICE:
+    case AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:
+        return GROUP_WIRED;
+    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+    case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+        return GROUP_BT_A2DP;
+    default:
+        return GROUP_NONE;
+    }
+}
+
+} // namespace android
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index ac3e462..fe15ff6 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -143,8 +143,9 @@
 {
     dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
     std::string deviceLiteral;
-    if (!OutputDeviceConverter::toString(mApplicableDevices, deviceLiteral)) {
-        ALOGE("%s: failed to convert device %d", __FUNCTION__, mApplicableDevices);
+    if (!deviceTypesToString(mApplicableDevices, deviceLiteral)) {
+        ALOGE("%s: failed to convert device %s",
+              __FUNCTION__, dumpDeviceTypes(mApplicableDevices).c_str());
     }
     dst->appendFormat("%*sSelected Device: {type:%s, @:%s}\n", spaces + 2, "",
                        deviceLiteral.c_str(), mDeviceAddress.c_str());
@@ -236,14 +237,14 @@
 }
 
 
-audio_devices_t ProductStrategyMap::getDeviceTypesForProductStrategy(
+DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
         product_strategy_t strategy) const
 {
     if (find(strategy) == end()) {
         ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
         product_strategy_t defaultStrategy = getDefault();
         if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
-            return AUDIO_DEVICE_NONE;
+            return {AUDIO_DEVICE_NONE};
         }
         return at(getDefault())->getDeviceTypes();
     }
@@ -309,5 +310,15 @@
     }
 }
 
+void ProductStrategyPreferredRoutingMap::dump(android::String8* dst, int spaces) const {
+    dst->appendFormat("\n%*sPreferred devices per product strategy dump:", spaces, "");
+    for (const auto& iter : *this) {
+        dst->appendFormat("\n%*sStrategy %u dev:%08x addr:%s",
+                          spaces + 2, "",
+                          (uint32_t) iter.first,
+                          iter.second.mType, iter.second.mAddress.c_str());
+    }
+    dst->appendFormat("\n");
+}
 }
 
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
index ebd82a7..349f969 100644
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
@@ -16,8 +16,7 @@
 
 #pragma once
 
-#include <AudioGain.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <AudioPatch.h>
 #include <IOProfile.h>
 #include <DeviceDescriptor.h>
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index 0c58a7c..dfb20b5 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -292,6 +292,39 @@
      */
     virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const = 0;
 
+    /**
+     * @brief setPreferredDeviceForStrategy sets the default device to be used for a
+     * strategy when available
+     * @param strategy the audio strategy whose routing will be affected
+     * @param device the audio device to route to when available
+     * @return BAD_VALUE if the strategy is invalid,
+     *     or NO_ERROR if the preferred device was set
+     */
+    virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+            const AudioDeviceTypeAddr &device) = 0;
+
+    /**
+     * @brief removePreferredDeviceForStrategy removes the preferred device previously set
+     * for the given strategy
+     * @param strategy the audio strategy whose routing will be affected
+     * @return BAD_VALUE if the strategy is invalid,
+     *     or NO_ERROR if the preferred device was removed
+     */
+    virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0;
+
+    /**
+     * @brief getPreferredDeviceForStrategy queries which device is set as the
+     * preferred device for the given strategy
+     * @param strategy the strategy to query
+     * @param device returns configured as the preferred device if one was set
+     * @return BAD_VALUE if the strategy is invalid,
+     *     or NAME_NOT_FOUND if no preferred device was set
+     *     or NO_ERROR if the device parameter was initialized to the preferred device
+     */
+    virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+            AudioDeviceTypeAddr &device) const = 0;
+
+
     virtual void dump(String8 *dst) const = 0;
 
 protected:
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index c27dc88..8f522f0 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -33,6 +33,7 @@
 
     ],
     shared_libs: [
+        "libaudiofoundation",
         "liblog",
         "libcutils",
         "libutils",
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 3987294..752ba92 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -32,6 +32,7 @@
 #include <policy.h>
 #include <AudioIODescriptorInterface.h>
 #include <ParameterManagerWrapper.h>
+#include <media/AudioContainers.h>
 
 #include <media/TypeConverter.h>
 
@@ -167,13 +168,15 @@
     mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
 
     if (audio_is_output_device(devDesc->type())) {
+        // FIXME: Use DeviceTypeSet when the interface is ready
         return mPolicyParameterMgr->setAvailableOutputDevices(
-                    getApmObserver()->getAvailableOutputDevices().types());
+                    deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
     } else if (audio_is_input_device(devDesc->type())) {
+        // FIXME: Use DeviceTypeSet when the interface is ready
         return mPolicyParameterMgr->setAvailableInputDevices(
-                    getApmObserver()->getAvailableInputDevices().types());
+                    deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
     }
-    return BAD_TYPE;
+    return EngineBase::setDeviceConnectionState(devDesc, state);
 }
 
 status_t Engine::loadAudioPolicyEngineConfig()
@@ -211,7 +214,7 @@
     }
     const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
-    uint32_t availableOutputDevicesType = availableOutputDevices.types();
+    DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
 
     /** This is the only case handled programmatically because the PFW is unable to know the
      * activity of streams.
@@ -223,7 +226,7 @@
      *
      * -When media is not playing anymore, fall back on the sonification behavior
      */
-    audio_devices_t devices = AUDIO_DEVICE_NONE;
+    DeviceTypeSet deviceTypes;
     if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
             !is_state_in_call(getPhoneState()) &&
             !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
@@ -232,7 +235,7 @@
                              SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
         product_strategy_t strategyForMedia =
                 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
-        devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
+        deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
     } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
         (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
          outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
@@ -240,36 +243,37 @@
             // compressed format as they would likely not be mixed and dropped.
             // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
         product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
-        devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
+        deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
     } else {
-        devices = productStrategies.getDeviceTypesForProductStrategy(ps);
+        deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps);
     }
-    if (devices == AUDIO_DEVICE_NONE ||
-            (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
+    if (deviceTypes.empty() ||
+            Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
         auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
         ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
         return DeviceVector(defaultDevice);
     }
-    if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
+    if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
+            deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
         // We do expect only one device for these types of devices
         // Criterion device address garantee this one is available
         // If this criterion is not wished, need to ensure this device is available
         const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
-        ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
-        auto busDevice = availableOutputDevices.getDevice(devices, address, AUDIO_FORMAT_DEFAULT);
+        ALOGV("%s:device %s %s %d",
+                __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
+        auto busDevice = availableOutputDevices.getDevice(
+                *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
         if (busDevice == nullptr) {
-            ALOGE("%s:unavailable device 0x%x %s, fallback on default", __func__, devices,
-                  address.c_str());
+            ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
+                  dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
             auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
             ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
             return DeviceVector(defaultDevice);
         }
-        return DeviceVector(availableOutputDevices.getDevice(devices,
-                                                             address,
-                                                             AUDIO_FORMAT_DEFAULT));
+        return DeviceVector(busDevice);
     }
-    ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
-    return availableOutputDevices.getDevicesFromTypeMask(devices);
+    ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
+    return availableOutputDevices.getDevicesFromTypes(deviceTypes);
 }
 
 DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@@ -366,7 +370,8 @@
         ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
         return false;
     }
-    getProductStrategies().at(strategy)->setDeviceTypes(devices);
+    // FIXME: stop using deviceTypesFromBitMask when the interface is ready
+    getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
     return true;
 }
 
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 4b57444..465a6f9 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -259,7 +259,7 @@
     std::string criterionName = audio_is_output_device(devDesc->type()) ?
                 gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
 
-    ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->address().string(),
+    ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->address().c_str(),
           state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
     ISelectionCriterionInterface *criterion =
             getElement<ISelectionCriterionInterface>(criterionName, mPolicyCriteria);
@@ -271,7 +271,7 @@
 
     auto criterionType = criterion->getCriterionType();
     int deviceAddressId;
-    if (not criterionType->getNumericalValue(devDesc->address().string(), deviceAddressId)) {
+    if (not criterionType->getNumericalValue(devDesc->address().c_str(), deviceAddressId)) {
         ALOGW("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->address().c_str());
         return BAD_TYPE;
     }
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 5bfad29..8443008 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,8 +16,7 @@
 
 #pragma once
 
-#include <AudioGain.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <HwModule.h>
 #include <DeviceDescriptor.h>
 #include <system/audio.h>
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 2b9cf09..aaf4158 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -21,6 +21,7 @@
         "libaudiopolicyengine_config",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "liblog",
         "libcutils",
         "libutils",
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
old mode 100644
new mode 100755
index c602f3a..02b99d0
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -27,10 +27,11 @@
 #include "Engine.h"
 #include <android-base/macros.h>
 #include <AudioPolicyManagerObserver.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <IOProfile.h>
 #include <AudioIODescriptorInterface.h>
 #include <policy.h>
+#include <media/AudioContainers.h>
 #include <utils/String8.h>
 #include <utils/Log.h>
 
@@ -136,27 +137,23 @@
     return EngineBase::setForceUse(usage, config);
 }
 
-audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
-                                                DeviceVector availableOutputDevices,
-                                                DeviceVector availableInputDevices,
-                                                const SwAudioOutputCollection &outputs,
-                                                uint32_t outputDeviceTypesToIgnore) const
+DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
+                                              DeviceVector availableOutputDevices,
+                                              DeviceVector availableInputDevices,
+                                              const SwAudioOutputCollection &outputs) const
 {
-    uint32_t device = AUDIO_DEVICE_NONE;
-    uint32_t availableOutputDevicesType =
-            availableOutputDevices.types() & ~outputDeviceTypesToIgnore;
+    DeviceVector devices;
 
     switch (strategy) {
 
     case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
-        device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+        devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         break;
 
     case STRATEGY_SONIFICATION_RESPECTFUL:
         if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
-            device = getDeviceForStrategyInt(
-                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
         } else {
             bool media_active_locally =
                     outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
@@ -165,17 +162,18 @@
                         toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
                         SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
             // routing is same as media without the "remote" device
-            device = getDeviceForStrategyInt(STRATEGY_MEDIA,
+            availableOutputDevices.remove(availableOutputDevices.getDevicesFromType(
+                    AUDIO_DEVICE_OUT_REMOTE_SUBMIX));
+            devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
                     availableOutputDevices,
-                    availableInputDevices, outputs,
-                    AUDIO_DEVICE_OUT_REMOTE_SUBMIX | outputDeviceTypesToIgnore);
+                    availableInputDevices, outputs);
             // if no media is playing on the device, check for mandatory use of "safe" speaker
             // when media would have played on speaker, and the safe speaker path is available
-            if (!media_active_locally
-                    && (device & AUDIO_DEVICE_OUT_SPEAKER)
-                    && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
-                device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-                device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+            if (!media_active_locally) {
+                devices.replaceDevicesByType(
+                        AUDIO_DEVICE_OUT_SPEAKER,
+                        availableOutputDevices.getDevicesFromType(
+                                AUDIO_DEVICE_OUT_SPEAKER_SAFE));
             }
         }
         break;
@@ -183,9 +181,8 @@
     case STRATEGY_DTMF:
         if (!isInCall()) {
             // when off call, DTMF strategy follows the same rules as MEDIA strategy
-            device = getDeviceForStrategyInt(
-                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         // when in call, DTMF and PHONE strategies follow the same rules
@@ -197,24 +194,27 @@
         //   - cannot route from voice call RX OR
         //   - audio HAL version is < 3.0 and TX device is on the primary HW module
         if (getPhoneState() == AUDIO_MODE_IN_CALL) {
-            audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
+            audio_devices_t txDevice = getDeviceForInputSource(
+                    AUDIO_SOURCE_VOICE_COMMUNICATION)->type();
             sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
-            audio_devices_t availPrimaryInputDevices =
-                 availableInputDevices.getDeviceTypesFromHwModule(primaryOutput->getModuleHandle());
+            DeviceVector availPrimaryInputDevices =
+                    availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
 
             // TODO: getPrimaryOutput return only devices from first module in
             // audio_policy_configuration.xml, hearing aid is not there, but it's
             // a primary device
             // FIXME: this is not the right way of solving this problem
-            audio_devices_t availPrimaryOutputDevices =
-                (primaryOutput->supportedDevices().types() | AUDIO_DEVICE_OUT_HEARING_AID) &
-                availableOutputDevices.types();
+            DeviceVector availPrimaryOutputDevices = availableOutputDevices.getDevicesFromTypes(
+                    primaryOutput->supportedDevices().types());
+            availPrimaryOutputDevices.add(
+                    availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID));
 
-            if (((availableInputDevices.types() &
-                    AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
-                    (((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                         (primaryOutput->getAudioPort()->getModuleVersionMajor() < 3))) {
-                availableOutputDevicesType = availPrimaryOutputDevices;
+            if ((availableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
+                    String8(""), AUDIO_FORMAT_DEFAULT) == nullptr) ||
+                    ((availPrimaryInputDevices.getDevice(
+                            txDevice, String8(""), AUDIO_FORMAT_DEFAULT) != nullptr) &&
+                            (primaryOutput->getPolicyAudioPort()->getModuleVersionMajor() < 3))) {
+                availableOutputDevices = availPrimaryOutputDevices;
             }
         }
         // for phone strategy, we first consider the forced use and then the available devices by
@@ -222,49 +222,40 @@
         switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
         case AUDIO_POLICY_FORCE_BT_SCO:
             if (!isInCall() || strategy != STRATEGY_DTMF) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-                if (device) break;
+                devices = availableOutputDevices.getDevicesFromType(
+                        AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
-            if (device) break;
+            devices = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+            if (!devices.isEmpty()) break;
             // if SCO device is requested but no SCO device is available, fall back to default case
             FALLTHROUGH_INTENDED;
 
         default:    // FORCE_NONE
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
-            if (device) break;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
+            if (!devices.isEmpty()) break;
             // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
             if (!isInCall() &&
                     (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
                      outputs.isA2dpSupported()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
-                if (device) break;
+                devices = availableOutputDevices.getFirstDevicesFromTypes({
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES});
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
-            if (device) break;
+            devices = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET,
+                    AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET,
+                    AUDIO_DEVICE_OUT_USB_DEVICE});
+            if (!devices.isEmpty()) break;
             if (!isInCall()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
-                if (device) break;
+                devices = availableOutputDevices.getFirstDevicesFromTypes({
+                        AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,
+                        AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE);
             break;
 
         case AUDIO_POLICY_FORCE_SPEAKER:
@@ -273,22 +264,18 @@
             if (!isInCall() &&
                     (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
                      outputs.isA2dpSupported()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
-                if (device) break;
+                devices = availableOutputDevices.getDevicesFromType(
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+                if (!devices.isEmpty()) break;
             }
             if (!isInCall()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
-                if (device) break;
+                devices = availableOutputDevices.getFirstDevicesFromTypes({
+                        AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE,
+                        AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL,
+                        AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
             break;
         }
     break;
@@ -298,9 +285,8 @@
         // If incall, just select the STRATEGY_PHONE device
         if (isInCall() ||
                 outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
-            device = getDeviceForStrategyInt(
-                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         FALLTHROUGH_INTENDED;
@@ -313,41 +299,37 @@
 
         if ((strategy == STRATEGY_SONIFICATION) ||
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
 
         // if SCO headset is connected and we are told to use it, play ringtone over
         // speaker and BT SCO
-        if ((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) {
-            uint32_t device2 = AUDIO_DEVICE_NONE;
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-            }
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
-            }
+        if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+            DeviceVector devices2;
+            devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+                    AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
             // Use ONLY Bluetooth SCO output when ringing in vibration mode
             if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
                     && (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
                 if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
                         == AUDIO_POLICY_FORCE_BT_SCO) {
-                    if (device2 != AUDIO_DEVICE_NONE) {
-                        device = device2;
+                    if (!devices2.isEmpty()) {
+                        devices = devices2;
                         break;
                     }
                 }
             }
             // Use both Bluetooth SCO and phone default output when ringing in normal mode
             if (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) {
-                if ((strategy == STRATEGY_SONIFICATION) &&
-                        (device & AUDIO_DEVICE_OUT_SPEAKER) &&
-                        (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
-                    device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-                    device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+                if (strategy == STRATEGY_SONIFICATION) {
+                    devices.replaceDevicesByType(
+                            AUDIO_DEVICE_OUT_SPEAKER,
+                            availableOutputDevices.getDevicesFromType(
+                                    AUDIO_DEVICE_OUT_SPEAKER_SAFE));
                 }
-                if (device2 != AUDIO_DEVICE_NONE) {
-                    device |= device2;
+                if (!devices2.isEmpty()) {
+                    devices.add(devices2);
                     break;
                 }
             }
@@ -361,25 +343,20 @@
             // compressed format as they would likely not be mixed and dropped.
             for (size_t i = 0; i < outputs.size(); i++) {
                 sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
-                audio_devices_t devices = desc->devices().types() &
-                    (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
-                if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
-                        devices != AUDIO_DEVICE_NONE) {
-                    availableOutputDevicesType = availableOutputDevices.types() & ~devices;
+                if (desc->isActive() && !audio_is_linear_pcm(desc->getFormat())) {
+                    availableOutputDevices.remove(desc->devices().getDevicesFromTypes({
+                            AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_SPDIF,
+                            AUDIO_DEVICE_OUT_HDMI_ARC}));
                 }
             }
-            availableOutputDevices =
-                    availableOutputDevices.getDevicesFromTypeMask(availableOutputDevicesType);
             if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
                     outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
-                return getDeviceForStrategyInt(
-                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+                return getDevicesForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
             }
             if (isInCall()) {
-                return getDeviceForStrategyInt(
-                        STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
-                        outputDeviceTypesToIgnore);
+                return getDevicesForStrategyInt(
+                        STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             }
         }
         // For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
@@ -388,128 +365,114 @@
     // FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
     case STRATEGY_REROUTING:
     case STRATEGY_MEDIA: {
-        uint32_t device2 = AUDIO_DEVICE_NONE;
+        DeviceVector devices2;
         if (strategy != STRATEGY_SONIFICATION) {
             // no sonification on remote submix (e.g. WFD)
-            if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                                 String8("0"), AUDIO_FORMAT_DEFAULT) != 0) {
-                device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+            sp<DeviceDescriptor> remoteSubmix;
+            if ((remoteSubmix = availableOutputDevices.getDevice(
+                    AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0"),
+                    AUDIO_FORMAT_DEFAULT)) != nullptr) {
+                devices2.add(remoteSubmix);
             }
         }
         if (isInCall() && (strategy == STRATEGY_MEDIA)) {
-            device = getDeviceForStrategyInt(
-                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         // FIXME: Find a better solution to prevent routing to BT hearing aid(b/122931261).
-        if ((device2 == AUDIO_DEVICE_NONE) &&
+        if ((devices2.isEmpty()) &&
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
         }
-        if ((device2 == AUDIO_DEVICE_NONE) &&
-                (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
-                 outputs.isA2dpSupported()) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
-            }
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
-            }
-        }
-        if ((device2 == AUDIO_DEVICE_NONE) &&
+        if ((devices2.isEmpty()) &&
             (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+        if (devices2.isEmpty() && (getLastRemovableMediaDevices().size() > 0)) {
+            if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
+                    outputs.isA2dpSupported()) {
+                // Get the last connected device of wired and bluetooth a2dp
+                devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+                        getLastRemovableMediaDevices());
+            } else {
+                // Get the last connected device of wired except bluetooth a2dp
+                devices2 = availableOutputDevices.getFirstDevicesFromTypes(
+                        getLastRemovableMediaDevices(GROUP_WIRED));
+            }
         }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
-        }
-        if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+        if ((devices2.isEmpty()) && (strategy != STRATEGY_SONIFICATION)) {
             // no sonification on aux digital (e.g. HDMI)
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_AUX_DIGITAL);
         }
-        if ((device2 == AUDIO_DEVICE_NONE) &&
+        if ((devices2.isEmpty()) &&
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+            devices2 = availableOutputDevices.getDevicesFromType(
+                    AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
         }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+        if (devices2.isEmpty()) {
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
-        int device3 = AUDIO_DEVICE_NONE;
+        DeviceVector devices3;
         if (strategy == STRATEGY_MEDIA) {
             // ARC, SPDIF and AUX_LINE can co-exist with others.
-            device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC;
-            device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF);
-            device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE);
+            devices3 = availableOutputDevices.getDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_SPDIF, AUDIO_DEVICE_OUT_AUX_LINE});
         }
 
-        device2 |= device3;
+        devices2.add(devices3);
         // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
         // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
-        device |= device2;
+        devices.add(devices2);
 
         // If hdmi system audio mode is on, remove speaker out of output list.
         if ((strategy == STRATEGY_MEDIA) &&
             (getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO) ==
                 AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
-            device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+            devices.remove(devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
         }
 
         // for STRATEGY_SONIFICATION:
         // if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
-        if ((strategy == STRATEGY_SONIFICATION) &&
-                (device & AUDIO_DEVICE_OUT_SPEAKER) &&
-                (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
-            device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-            device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+        if (strategy == STRATEGY_SONIFICATION) {
+            devices.replaceDevicesByType(
+                    AUDIO_DEVICE_OUT_SPEAKER,
+                    availableOutputDevices.getDevicesFromType(
+                            AUDIO_DEVICE_OUT_SPEAKER_SAFE));
         }
         } break;
 
     default:
-        ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+        ALOGW("getDevicesForStrategy() unknown strategy: %d", strategy);
         break;
     }
 
-    if (device == AUDIO_DEVICE_NONE) {
-        ALOGV("getDeviceForStrategy() no device found for strategy %d", strategy);
-        device = getApmObserver()->getDefaultOutputDevice()->type();
-        ALOGE_IF(device == AUDIO_DEVICE_NONE,
-                 "getDeviceForStrategy() no default device defined");
+    if (devices.isEmpty()) {
+        ALOGV("getDevicesForStrategy() no device found for strategy %d", strategy);
+        sp<DeviceDescriptor> defaultOutputDevice = getApmObserver()->getDefaultOutputDevice();
+        if (defaultOutputDevice != nullptr) {
+            devices.add(defaultOutputDevice);
+        }
+        ALOGE_IF(devices.isEmpty(),
+                 "getDevicesForStrategy() no default device defined");
     }
-    ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
-    return device;
+
+    ALOGVV("getDevices"
+           "ForStrategy() strategy %d, device %x", strategy, devices.types());
+    return devices;
 }
 
 
-audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
+sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) const
 {
     const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
     const DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
-    audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
+    DeviceVector availableDevices = availableInputDevices;
     sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
-    audio_devices_t availablePrimaryDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
-        primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
-    uint32_t device = AUDIO_DEVICE_NONE;
+    DeviceVector availablePrimaryDevices = availableInputDevices.getDevicesFromHwModule(
+            primaryOutput->getModuleHandle());
+    sp<DeviceDescriptor> device;
 
     // when a call is active, force device selection to match source VOICE_COMMUNICATION
     // for most other input sources to avoid rerouting call TX audio
@@ -532,57 +495,47 @@
     switch (inputSource) {
     case AUDIO_SOURCE_DEFAULT:
     case AUDIO_SOURCE_MIC:
-    if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
-        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
-    } else if ((getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) &&
-        (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
-        device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-        device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-        device = AUDIO_DEVICE_IN_USB_HEADSET;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-        device = AUDIO_DEVICE_IN_USB_DEVICE;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-        device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-    }
-    break;
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_BLUETOOTH_A2DP, String8(""), AUDIO_FORMAT_DEFAULT);
+        if (device != nullptr) break;
+        if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
+            device = availableDevices.getDevice(
+                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+            if (device != nullptr) break;
+        }
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
+        break;
 
     case AUDIO_SOURCE_VOICE_COMMUNICATION:
         // Allow only use of devices on primary input if in call and HAL does not support routing
         // to voice call path.
         if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
-                (availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
-            availableDeviceTypes = availablePrimaryDeviceTypes;
+                (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX,
+                        String8(""), AUDIO_FORMAT_DEFAULT)) == nullptr) {
+            availableDevices = availablePrimaryDevices;
         }
 
         switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
         case AUDIO_POLICY_FORCE_BT_SCO:
             // if SCO device is requested but no SCO device is available, fall back to default case
-            if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
-                device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+            device = availableDevices.getDevice(
+                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+            if (device != nullptr) {
                 break;
             }
             FALLTHROUGH_INTENDED;
 
         default:    // FORCE_NONE
-            if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-                device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-                device = AUDIO_DEVICE_IN_USB_HEADSET;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-                device = AUDIO_DEVICE_IN_USB_DEVICE;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-            }
+            device = availableDevices.getFirstExistingDevice({
+                    AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                    AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
             break;
 
         case AUDIO_POLICY_FORCE_SPEAKER:
-            if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
-                device = AUDIO_DEVICE_IN_BACK_MIC;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-            }
+            device = availableDevices.getFirstExistingDevice({
+                    AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC});
             break;
         }
         break;
@@ -591,84 +544,67 @@
     case AUDIO_SOURCE_UNPROCESSED:
     case AUDIO_SOURCE_HOTWORD:
         if (inputSource == AUDIO_SOURCE_HOTWORD) {
-            availableDeviceTypes = availablePrimaryDeviceTypes;
+            availableDevices = availablePrimaryDevices;
         }
-        if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO &&
-                availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
-            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-            device = AUDIO_DEVICE_IN_USB_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-            device = AUDIO_DEVICE_IN_USB_DEVICE;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
+            device = availableDevices.getDevice(
+                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+            if (device != nullptr) break;
         }
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
         break;
     case AUDIO_SOURCE_CAMCORDER:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
-            device = AUDIO_DEVICE_IN_BACK_MIC;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-            // This is specifically for a device without built-in mic
-            device = AUDIO_DEVICE_IN_USB_DEVICE;
-        }
+        // For a device without built-in mic, adding usb device
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC,
+                AUDIO_DEVICE_IN_USB_DEVICE});
         break;
     case AUDIO_SOURCE_VOICE_DOWNLINK:
     case AUDIO_SOURCE_VOICE_CALL:
     case AUDIO_SOURCE_VOICE_UPLINK:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
-            device = AUDIO_DEVICE_IN_VOICE_CALL;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_VOICE_CALL, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     case AUDIO_SOURCE_VOICE_PERFORMANCE:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-            device = AUDIO_DEVICE_IN_USB_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-            device = AUDIO_DEVICE_IN_USB_DEVICE;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-        }
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
         break;
     case AUDIO_SOURCE_REMOTE_SUBMIX:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
-            device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_REMOTE_SUBMIX, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     case AUDIO_SOURCE_FM_TUNER:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
-            device = AUDIO_DEVICE_IN_FM_TUNER;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_FM_TUNER, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     case AUDIO_SOURCE_ECHO_REFERENCE:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
-            device = AUDIO_DEVICE_IN_ECHO_REFERENCE;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_ECHO_REFERENCE, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     default:
         ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
         break;
     }
-    if (device == AUDIO_DEVICE_NONE) {
+    if (device == nullptr) {
         ALOGV("getDeviceForInputSource() no device found for source %d", inputSource);
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_STUB) {
-            device = AUDIO_DEVICE_IN_STUB;
-        }
-        ALOGE_IF(device == AUDIO_DEVICE_NONE,
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_STUB, String8(""), AUDIO_FORMAT_DEFAULT);
+        ALOGE_IF(device == nullptr,
                  "getDeviceForInputSource() no default device defined");
     }
-    ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+    ALOGV_IF(device != nullptr,
+             "getDeviceForInputSource()input source %d, device %08x",
+             inputSource, device->type());
     return device;
 }
 
 void Engine::updateDeviceSelectionCache()
 {
     for (const auto &iter : getProductStrategies()) {
-        const auto &strategy = iter.second;
+        const auto& strategy = iter.second;
         auto devices = getDevicesForProductStrategy(strategy->getId());
         mDevicesForStrategies[strategy->getId()] = devices;
         strategy->setDeviceTypes(devices.types());
@@ -676,19 +612,33 @@
     }
 }
 
-DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const
-{
+DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const {
     DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
-    DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
-    const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
 
+    // check if this strategy has a preferred device that is available,
+    // if yes, give priority to it
+    AudioDeviceTypeAddr preferredStrategyDevice;
+    const status_t status = getPreferredDeviceForStrategy(strategy, preferredStrategyDevice);
+    if (status == NO_ERROR) {
+        // there is a preferred device, is it available?
+        sp<DeviceDescriptor> preferredAvailableDevDescr = availableOutputDevices.getDevice(
+                preferredStrategyDevice.mType,
+                String8(preferredStrategyDevice.mAddress.c_str()),
+                AUDIO_FORMAT_DEFAULT);
+        if (preferredAvailableDevDescr != nullptr) {
+            ALOGVV("%s using pref device 0x%08x/%s for strategy %u", __FUNCTION__,
+                   preferredStrategyDevice.mType, preferredStrategyDevice.mAddress, strategy);
+            return DeviceVector(preferredAvailableDevDescr);
+        }
+    }
+
+    DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
+    const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
     auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
-                mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
-    audio_devices_t devices = getDeviceForStrategyInt(legacyStrategy,
-                                                      availableOutputDevices,
-                                                      availableInputDevices, outputs,
-                                                      (uint32_t)AUDIO_DEVICE_NONE);
-    return availableOutputDevices.getDevicesFromTypeMask(devices);
+                          mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
+    return getDevicesForStrategyInt(legacyStrategy,
+                                    availableOutputDevices,
+                                    availableInputDevices, outputs);
 }
 
 DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@@ -747,17 +697,21 @@
     if (device != nullptr) {
         return device;
     }
-    audio_devices_t deviceType = getDeviceForInputSource(attr.source);
 
-    if (audio_is_remote_submix_device(deviceType)) {
-        address = "0";
-        std::size_t pos;
-        std::string tags { attr.tags };
-        if ((pos = tags.find("addr=")) != std::string::npos) {
-            address = tags.substr(pos + std::strlen("addr="));
-        }
+    device = getDeviceForInputSource(attr.source);
+    if (device == nullptr || !audio_is_remote_submix_device(device->type())) {
+        // Return immediately if the device is null or it is not a remote submix device.
+        return device;
     }
-    return availableInputDevices.getDevice(deviceType,
+
+    // For remote submix device, try to find the device by address.
+    address = "0";
+    std::size_t pos;
+    std::string tags { attr.tags };
+    if ((pos = tags.find("addr=")) != std::string::npos) {
+        address = tags.substr(pos + std::strlen("addr="));
+    }
+    return availableInputDevices.getDevice(device->type(),
                                            String8(address.c_str()),
                                            AUDIO_FORMAT_DEFAULT);
 }
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 62938cf..4360c6f 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -18,7 +18,6 @@
 
 #include "EngineBase.h"
 #include "EngineInterface.h"
-#include <AudioGain.h>
 #include <policy.h>
 
 namespace android
@@ -74,15 +73,14 @@
 
     status_t setDefaultDevice(audio_devices_t device);
 
-    audio_devices_t getDeviceForStrategyInt(legacy_strategy strategy,
-                                            DeviceVector availableOutputDevices,
-                                            DeviceVector availableInputDevices,
-                                            const SwAudioOutputCollection &outputs,
-                                            uint32_t outputDeviceTypesToIgnore) const;
+    DeviceVector getDevicesForStrategyInt(legacy_strategy strategy,
+                                          DeviceVector availableOutputDevices,
+                                          DeviceVector availableInputDevices,
+                                          const SwAudioOutputCollection &outputs) const;
 
     DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
 
-    audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
+    sp<DeviceDescriptor> getDeviceForInputSource(audio_source_t inputSource) const;
 
     DeviceStrategyMap mDevicesForStrategies;
 
diff --git a/services/audiopolicy/manager/Android.mk b/services/audiopolicy/manager/Android.mk
index d6ca2f2..cae6cfa 100644
--- a/services/audiopolicy/manager/Android.mk
+++ b/services/audiopolicy/manager/Android.mk
@@ -23,8 +23,6 @@
 
 LOCAL_CFLAGS := -Wall -Werror
 
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
 LOCAL_MODULE:= libaudiopolicymanager
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index 8fbeff9..1fa0d19 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -9,6 +9,7 @@
     export_include_dirs: ["."],
 
     shared_libs: [
+        "libaudiofoundation",
         "libcutils",
         "libdl",
         "libutils",
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b0b63d9..23c0a12 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -73,6 +73,26 @@
         AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
         AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
 
+template <typename T>
+bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    if (left.size() != right.size()) {
+        return false;
+    }
+    for (size_t index = 0; index < right.size(); index++) {
+        if (left[index] != right[index]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+template <typename T>
+bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    return !(left == right);
+}
+
 // ----------------------------------------------------------------------------
 // AudioPolicyInterface implementation
 // ----------------------------------------------------------------------------
@@ -92,7 +112,7 @@
 void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
                                                         audio_policy_dev_state_t state)
 {
-    AudioParameter param(device->address());
+    AudioParameter param(String8(device->address().c_str()));
     const String8 key(state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE ?
                 AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect);
     param.addInt(key, device->type());
@@ -405,7 +425,7 @@
     if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
 
     // Check if the device is currently connected
-    DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromTypeMask(device);
+    DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
     if (deviceList.empty()) {
         // Nothing to do: device is not connected
         return NO_ERROR;
@@ -419,8 +439,8 @@
     // Case 1: A2DP active device switches from primary to primary
     // module
     // Case 2: A2DP device config changes on primary module.
-    if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        sp<HwModule> module = mHwModules.getModuleForDeviceTypes(device, encodedFormat);
+    if (audio_is_a2dp_out_device(device)) {
+        sp<HwModule> module = mHwModules.getModuleForDeviceType(device, encodedFormat);
         audio_module_handle_t primaryHandle = mPrimaryOutput->getModuleHandle();
         if (availablePrimaryOutputDevices().contains(devDesc) &&
            (module != 0 && module->getHandle() == primaryHandle)) {
@@ -476,8 +496,8 @@
         ALOGE("%s() unable to get primary module", __func__);
         return NO_INIT;
     }
-    DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypeMask(
-            AUDIO_DEVICE_OUT_ALL_A2DP);
+    DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypes(
+            getAudioDeviceOutAllA2dpSet());
     for (const auto& device : declaredDevices) {
         formatSet.insert(device->encodedFormats().begin(), device->encodedFormats().end());
     }
@@ -491,7 +511,8 @@
     bool createRxPatch = false;
     uint32_t muteWaitMs = 0;
 
-    if(!hasPrimaryOutput() || mPrimaryOutput->devices().types() == AUDIO_DEVICE_OUT_STUB) {
+    if(!hasPrimaryOutput() ||
+            mPrimaryOutput->devices().onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_STUB)) {
         return muteWaitMs;
     }
     ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device");
@@ -515,9 +536,9 @@
     }
 
     auto telephonyRxModule =
-        mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
+        mHwModules.getModuleForDeviceType(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
     auto telephonyTxModule =
-        mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
+        mHwModules.getModuleForDeviceType(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
     // retrieve Rx Source and Tx Sink device descriptors
     sp<DeviceDescriptor> rxSourceDevice =
         mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
@@ -628,20 +649,6 @@
     return audioPatch;
 }
 
-sp<DeviceDescriptor> AudioPolicyManager::findDevice(
-        const DeviceVector& devices, audio_devices_t device) const {
-    DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
-    ALOG_ASSERT(!deviceList.isEmpty(),
-            "%s() selected device type %#x is not in devices list", __func__, device);
-    return deviceList.itemAt(0);
-}
-
-audio_devices_t AudioPolicyManager::getModuleDeviceTypes(
-        const DeviceVector& devices, const char *moduleId) const {
-    sp<HwModule> mod = mHwModules.getModuleFromName(moduleId);
-    return mod != 0 ? devices.getDeviceTypesFromHwModule(mod->getHandle()) : AUDIO_DEVICE_NONE;
-}
-
 bool AudioPolicyManager::isDeviceOfModule(
         const sp<DeviceDescriptor>& devDesc, const char *moduleId) const {
     sp<HwModule> module = mHwModules.getModuleFromName(moduleId);
@@ -787,27 +794,11 @@
     //FIXME: workaround for truncated touch sounds
     // to be removed when the problem is handled by system UI
     uint32_t delayMs = 0;
-    uint32_t waitMs = 0;
     if (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) {
         delayMs = TOUCH_SOUND_FIXED_DELAY_MS;
     }
-    if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
-        DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/);
-        waitMs = updateCallRouting(newDevices, delayMs);
-    }
-    for (size_t i = 0; i < mOutputs.size(); i++) {
-        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
-        DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/);
-        if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) {
-            // As done in setDeviceConnectionState, we could also fix default device issue by
-            // preventing the force re-routing in case of default dev that distinguishes on address.
-            // Let's give back to engine full device choice decision however.
-            waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs);
-        }
-        if (forceVolumeReeval && !newDevices.isEmpty()) {
-            applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
-        }
-    }
+
+    updateCallAndOutputRouting(forceVolumeReeval, delayMs);
 
     for (const auto& activeDesc : mInputs.getActiveInputs()) {
         auto newDevice = getNewInputDevice(activeDesc);
@@ -861,7 +852,7 @@
                 continue;
             }
             // reject profiles if connected device does not support codec
-            if (!curProfile->deviceSupportsEncodedFormats(devices.types())) {
+            if (!curProfile->devicesSupportEncodedFormats(devices.types())) {
                 continue;
             }
             if (!directOnly) return curProfile;
@@ -1005,7 +996,7 @@
     // FIXME: provide a more generic approach which is not device specific and move this back
     // to getOutputForDevice.
     // TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side.
-    if (outputDevices.types() == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
+    if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX) &&
         (*stream == AUDIO_STREAM_MUSIC  || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
         audio_is_linear_pcm(config->format) &&
         isInCall()) {
@@ -1089,7 +1080,7 @@
         .channel_mask = config->channel_mask,
         .format = config->format,
     };
-    *portId = AudioPort::getNextUniqueId();
+    *portId = PolicyAudioPort::getNextUniqueId();
 
     sp<TrackClientDescriptor> clientDesc =
         new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
@@ -1186,9 +1177,9 @@
             if (!desc->isDuplicated() && (profile == desc->mProfile)) {
                 // reuse direct output if currently open by the same client
                 // and configured with same parameters
-                if ((config->sample_rate == desc->mSamplingRate) &&
-                    (config->format == desc->mFormat) &&
-                    (channelMask == desc->mChannelMask) &&
+                if ((config->sample_rate == desc->getSamplingRate()) &&
+                    (config->format == desc->getFormat()) &&
+                    (channelMask == desc->getChannelMask()) &&
                     (session == desc->mDirectClientSession)) {
                     desc->mDirectOpenCount++;
                     ALOGI("%s reusing direct output %d for session %d", __func__, 
@@ -1215,7 +1206,7 @@
             for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
                 const struct audio_port_config *sink = &patch->mPatch.sinks[j];
                 if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
-                        (sink->ext.device.type & devices.types()) != AUDIO_DEVICE_NONE &&
+                        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);
@@ -1228,13 +1219,13 @@
 
         // only accept an output with the requested parameters
         if (status != NO_ERROR ||
-            (config->sample_rate != 0 && config->sample_rate != outputDesc->mSamplingRate) ||
-            (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->mFormat) ||
-            (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+            (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+            (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+            (channelMask != 0 && channelMask != outputDesc->getChannelMask())) {
             ALOGV("%s failed opening direct output: output %d sample rate %d %d," 
                     "format %d %d, channel mask %04x %04x", __func__, output, config->sample_rate,
-                    outputDesc->mSamplingRate, config->format, outputDesc->mFormat,
-                    channelMask, outputDesc->mChannelMask);
+                    outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
+                    channelMask, outputDesc->getChannelMask());
             if (output != AUDIO_IO_HANDLE_NONE) {
                 outputDesc->close();
             }
@@ -1340,19 +1331,19 @@
     // Each IOProfile represents a MixPort from audio_policy_configuration.xml
     for (const auto &inProfile : inputProfiles) {
         if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
-            msdProfiles.appendVector(inProfile->getAudioProfiles());
+            appendAudioProfiles(msdProfiles, inProfile->getAudioProfiles());
         }
     }
     AudioProfileVector deviceProfiles;
     for (const auto &outProfile : outputProfiles) {
         if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) {
-            deviceProfiles.appendVector(outProfile->getAudioProfiles());
+            appendAudioProfiles(deviceProfiles, outProfile->getAudioProfiles());
         }
     }
     struct audio_config_base bestSinkConfig;
-    status_t result = msdProfiles.findBestMatchingOutputConfig(deviceProfiles,
+    status_t result = findBestMatchingOutputConfig(msdProfiles, deviceProfiles,
             compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
-            &bestSinkConfig);
+            bestSinkConfig);
     if (result != NO_ERROR) {
         ALOGD("%s() no matching profiles found for device: %s, hwAvSync: %d",
                 __func__, outputDevice->toString().c_str(), hwAvSync);
@@ -1505,13 +1496,13 @@
         // If haptic channel is specified, use the haptic output if present.
         // When using haptic output, same audio format and sample rate are required.
         const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
-            outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
+            outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
         if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
             continue;
         }
         if (outputHapticChannelCount >= hapticChannelCount
-            && format == outputDesc->mFormat
-            && samplingRate == outputDesc->mSamplingRate) {
+            && format == outputDesc->getFormat()
+            && samplingRate == outputDesc->getSamplingRate()) {
                 currentMatchCriteria[0] = outputHapticChannelCount;
         }
 
@@ -1519,12 +1510,13 @@
         currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
 
         // channel mask and channel count match
-        uint32_t outputChannelCount = audio_channel_count_from_out_mask(outputDesc->mChannelMask);
+        uint32_t outputChannelCount = audio_channel_count_from_out_mask(
+                outputDesc->getChannelMask());
         if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
             channelCount <= outputChannelCount) {
             if ((audio_channel_mask_get_representation(channelMask) ==
-                    audio_channel_mask_get_representation(outputDesc->mChannelMask)) &&
-                    ((channelMask & outputDesc->mChannelMask) == channelMask)) {
+                    audio_channel_mask_get_representation(outputDesc->getChannelMask())) &&
+                    ((channelMask & outputDesc->getChannelMask()) == channelMask)) {
                 currentMatchCriteria[2] = outputChannelCount;
             }
             currentMatchCriteria[3] = outputChannelCount;
@@ -1532,8 +1524,8 @@
 
         // sampling rate match
         if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
-                samplingRate <= outputDesc->mSamplingRate) {
-            currentMatchCriteria[4] = outputDesc->mSamplingRate;
+                samplingRate <= outputDesc->getSamplingRate()) {
+            currentMatchCriteria[4] = outputDesc->getSamplingRate();
         }
 
         // performance flags match
@@ -1542,8 +1534,8 @@
         // format match
         if (format != AUDIO_FORMAT_INVALID) {
             currentMatchCriteria[6] =
-                AudioPort::kFormatDistanceMax -
-                AudioPort::formatDistance(format, outputDesc->mFormat);
+                PolicyAudioPort::kFormatDistanceMax -
+                PolicyAudioPort::formatDistance(format, outputDesc->getFormat());
         }
 
         // primary output match
@@ -1757,14 +1749,15 @@
     }
 
     if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
-            mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+            mEngine->getForceUse(
+                    AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
         setStrategyMute(streamToStrategy(AUDIO_STREAM_ALARM), true, outputDesc);
     }
 
     // Automatically enable the remote submix input when output is started on a re routing mix
     // of type MIX_TYPE_RECORDERS
-    if (audio_is_remote_submix_device(devices.types()) && policyMix != NULL &&
-        policyMix->mMixType == MIX_TYPE_RECORDERS) {
+    if (isSingleDeviceType(devices.types(), &audio_is_remote_submix_device) &&
+        policyMix != NULL && policyMix->mMixType == MIX_TYPE_RECORDERS) {
         setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                     AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                     address,
@@ -1811,7 +1804,8 @@
             // Automatically disable the remote submix input when output is stopped on a
             // re routing mix of type MIX_TYPE_RECORDERS
             sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
-            if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
+            if (isSingleDeviceType(
+                    outputDesc->devices().types(), &audio_is_remote_submix_device) &&
                 policyMix != NULL &&
                 policyMix->mMixType == MIX_TYPE_RECORDERS) {
                 setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
@@ -2067,7 +2061,7 @@
 
     isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
         mSoundTriggerSessions.indexOfKey(session) >= 0;
-    *portId = AudioPort::getNextUniqueId();
+    *portId = PolicyAudioPort::getNextUniqueId();
 
     clientDesc = new RecordClientDescriptor(*portId, riid, uid, session, attributes, *config,
                                             requestedDeviceId, attributes.source, flags,
@@ -2410,7 +2404,8 @@
         const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
         if (input->clientsList().size() == 0
                 || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())
-                || (input->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
+                || (input->getPolicyAudioPort()->getFlags()
+                        & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
             inputsToClose.push_back(mInputs.keyAt(i));
         } else {
             bool close = false;
@@ -2470,10 +2465,12 @@
 {
     // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
     // stream by the engine.
+    DeviceTypeSet deviceTypes = {device};
     if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
-        device = mEngine->getOutputDevicesForStream(stream, true /*fromCache*/).types();
+        deviceTypes = mEngine->getOutputDevicesForStream(
+                stream, true /*fromCache*/).types();
     }
-    return getVolumeIndex(getVolumeCurves(stream), *index, device);
+    return getVolumeIndex(getVolumeCurves(stream), *index, deviceTypes);
 }
 
 status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
@@ -2498,19 +2495,20 @@
         return status;
     }
 
-    audio_devices_t curSrcDevice;
+    DeviceTypeSet curSrcDevices;
     auto curCurvAttrs = curves.getAttributes();
     if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
         auto attr = curCurvAttrs.front();
-        curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
+        curSrcDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
     } else if (!curves.getStreamTypes().empty()) {
         auto stream = curves.getStreamTypes().front();
-        curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
+        curSrcDevices = mEngine->getOutputDevicesForStream(stream, false).types();
     } else {
         ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
         return BAD_VALUE;
     }
-    curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
+    audio_devices_t curSrcDevice = Volume::getDeviceForVolume(curSrcDevices);
+    resetDeviceTypes(curSrcDevices, curSrcDevice);
 
     // update volume on all outputs and streams matching the following:
     // - The requested stream (or a stream matching for volume control) is active on the output
@@ -2522,11 +2520,10 @@
     // no specific device volume value exists for currently selected device.
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-        audio_devices_t curDevice = desc->devices().types();
+        DeviceTypeSet curDevices = desc->devices().types();
 
-        if (curDevice & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
-            curDevice |= AUDIO_DEVICE_OUT_SPEAKER;
-            curDevice &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+        if (curDevices.erase(AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            curDevices.insert(AUDIO_DEVICE_OUT_SPEAKER);
         }
 
         // Inter / intra volume group priority management: Loop on strategies arranged by priority
@@ -2570,7 +2567,7 @@
             if (!applyVolume) {
                 continue; // next output
             }
-            status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
+            status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevices,
                                                    (vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
                                                         TOUCH_SOUND_FIXED_DELAY_MS : 0));
             if (volStatus != NO_ERROR) {
@@ -2581,12 +2578,14 @@
         if (!(desc->isActive(vs) || isInCall())) {
             continue;
         }
-        if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
+        if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME &&
+                curDevices.find(device) == curDevices.end()) {
             continue;
         }
         if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
-            curSrcDevice |= device;
-            applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
+            curSrcDevices.insert(device);
+            applyVolume = (curSrcDevices.find(
+                    Volume::getDeviceForVolume(curDevices)) != curSrcDevices.end());
         } else {
             applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
         }
@@ -2595,7 +2594,7 @@
             // delayed volume change for system stream to be removed when the problem is
             // handled by system UI
             status_t volStatus = checkAndSetVolume(
-                        curves, vs, index, desc, curDevice,
+                        curves, vs, index, desc, curDevices,
                         ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
                              TOUCH_SOUND_FIXED_DELAY_MS : 0));
             if (volStatus != NO_ERROR) {
@@ -2638,22 +2637,23 @@
 {
     // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
     // stream by the engine.
+    DeviceTypeSet deviceTypes = {device};
     if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
-        device = mEngine->getOutputDevicesForAttributes(attr, nullptr, true /*fromCache*/).types();
+        DeviceTypeSet deviceTypes = mEngine->getOutputDevicesForAttributes(
+                attr, nullptr, true /*fromCache*/).types();
     }
-    return getVolumeIndex(getVolumeCurves(attr), index, device);
+    return getVolumeIndex(getVolumeCurves(attr), index, deviceTypes);
 }
 
 status_t AudioPolicyManager::getVolumeIndex(const IVolumeCurves &curves,
                                             int &index,
-                                            audio_devices_t device) const
+                                            const DeviceTypeSet& deviceTypes) const
 {
-    if (!audio_is_output_device(device)) {
+    if (isSingleDeviceType(deviceTypes, audio_is_output_device)) {
         return BAD_VALUE;
     }
-    device = Volume::getDeviceForVolume(device);
-    index = curves.getVolumeIndex(device);
-    ALOGV("%s: device %08x index %d", __FUNCTION__, device, index);
+    index = curves.getVolumeIndex(deviceTypes);
+    ALOGV("%s: device %s index %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), index);
     return NO_ERROR;
 }
 
@@ -2902,9 +2902,9 @@
             // stereo and let audio flinger do the channel conversion if needed.
             outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
             inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
-            rSubmixModule->addOutputProfile(address, &outputConfig,
+            rSubmixModule->addOutputProfile(address.c_str(), &outputConfig,
                     AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
-            rSubmixModule->addInputProfile(address, &inputConfig,
+            rSubmixModule->addInputProfile(address.c_str(), &inputConfig,
                     AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
 
             if ((res = setDeviceConnectionStateInt(deviceTypeToMakeAvailable,
@@ -3000,8 +3000,8 @@
                     }
                 }
             }
-            rSubmixModule->removeOutputProfile(address);
-            rSubmixModule->removeInputProfile(address);
+            rSubmixModule->removeOutputProfile(address.c_str());
+            rSubmixModule->removeInputProfile(address.c_str());
 
         } else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
             if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
@@ -3042,13 +3042,13 @@
         // reevaluate outputs for all given devices
         for (size_t i = 0; i < devices.size(); i++) {
             sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
-                            devices[i].mType, devices[i].mAddress, String8(),
+                            devices[i].mType, devices[i].mAddress.c_str(), String8(),
                             AUDIO_FORMAT_DEFAULT);
             SortedVector<audio_io_handle_t> outputs;
             if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                     outputs) != NO_ERROR) {
                 ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
-                        " addr=%s", devices[i].mType, devices[i].mAddress.string());
+                        " addr=%s", devices[i].mType, devices[i].mAddress.c_str());
                 return INVALID_OPERATION;
             }
         }
@@ -3068,6 +3068,72 @@
     return res;
 }
 
+status_t AudioPolicyManager::setPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   const AudioDeviceTypeAddr &device) {
+    ALOGI("%s() strategy=%d device=%08x addr=%s", __FUNCTION__,
+            strategy, device.mType, device.mAddress.c_str());
+    // strategy preferred device is only for output devices
+    if (!audio_is_output_device(device.mType)) {
+        ALOGE("%s() device=%08x is NOT an output device", __FUNCTION__, device.mType);
+        return BAD_VALUE;
+    }
+
+    status_t status = mEngine->setPreferredDeviceForStrategy(strategy, device);
+    if (status != NO_ERROR) {
+        ALOGW("Engine could not set preferred device %08x %s for strategy %d",
+                device.mType, device.mAddress.c_str(), strategy);
+        return status;
+    }
+
+    checkForDeviceAndOutputChanges();
+    updateCallAndOutputRouting();
+
+    return NO_ERROR;
+}
+
+void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs)
+{
+    uint32_t waitMs = 0;
+    if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
+        DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/);
+        waitMs = updateCallRouting(newDevices, delayMs);
+    }
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
+        DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/);
+        if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) {
+            // As done in setDeviceConnectionState, we could also fix default device issue by
+            // preventing the force re-routing in case of default dev that distinguishes on address.
+            // Let's give back to engine full device choice decision however.
+            waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs);
+        }
+        if (forceVolumeReeval && !newDevices.isEmpty()) {
+            applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true);
+        }
+    }
+}
+
+status_t AudioPolicyManager::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+    ALOGI("%s() strategy=%d", __FUNCTION__, strategy);
+
+    status_t status = mEngine->removePreferredDeviceForStrategy(strategy);
+    if (status != NO_ERROR) {
+        ALOGW("Engine could not remove preferred device for strategy %d", strategy);
+        return status;
+    }
+
+    checkForDeviceAndOutputChanges();
+    updateCallAndOutputRouting();
+
+    return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   AudioDeviceTypeAddr &device) {
+    return mEngine->getPreferredDeviceForStrategy(strategy, device);
+}
+
 void AudioPolicyManager::dump(String8 *dst) const
 {
     dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this);
@@ -3213,7 +3279,7 @@
     ALOGV("%s() profile %sfound with name: %s, "
         "sample rate: %u, format: 0x%x, channel_mask: 0x%x, output flags: 0x%x",
         __FUNCTION__, profile != 0 ? "" : "NOT ",
-        (profile != 0 ? profile->getTagName().string() : "null"),
+        (profile != 0 ? profile->getTagName().c_str() : "null"),
         config.sample_rate, config.format, config.channel_mask, output_flags);
     return (profile != 0);
 }
@@ -3417,8 +3483,8 @@
         }
 
         // TODO: reconfigure output format and channels here
-        ALOGV("createAudioPatch() setting device %08x on output %d",
-              devices.types(), outputDesc->mIoHandle);
+        ALOGV("createAudioPatch() setting device %s on output %d",
+              dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
         setOutputDevices(outputDesc, devices, true, 0, handle);
         index = mAudioPatches.indexOfKey(*handle);
         if (index >= 0) {
@@ -3836,7 +3902,7 @@
         return BAD_VALUE;
     }
 
-    *portId = AudioPort::getNextUniqueId();
+    *portId = PolicyAudioPort::getNextUniqueId();
 
     struct audio_patch dummyPatch = {};
     sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
@@ -3877,7 +3943,7 @@
     if (srcDevice->hasSameHwModuleAs(sinkDevice) &&
             srcDevice->getModuleVersionMajor() >= 3 &&
             sinkDevice->getModule()->supportsPatch(srcDevice, sinkDevice) &&
-            srcDevice->getAudioPort()->mGains.size() > 0) {
+            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
@@ -3898,12 +3964,14 @@
                 &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
                 &secondaryOutputs);
         if (output == AUDIO_IO_HANDLE_NONE) {
-            ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevices.types());
+            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 %08x is duplicated", __FUNCTION__, sinkDevices.types());
+            ALOGV("%s output for device %s is duplicated",
+                  __FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
             return INVALID_OPERATION;
         }
         status_t status = outputDesc->start();
@@ -4012,7 +4080,7 @@
 float AudioPolicyManager::getStreamVolumeDB(
         audio_stream_type_t stream, int index, audio_devices_t device)
 {
-    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, device);
+    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, {device});
 }
 
 status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
@@ -4112,12 +4180,12 @@
 
     sp<SwAudioOutputDescriptor> outputDesc;
     bool profileUpdated = false;
-    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
-            AUDIO_DEVICE_OUT_HDMI);
+    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+        AUDIO_DEVICE_OUT_HDMI);
     for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
         // Simulate reconnection to update enabled surround sound formats.
-        String8 address = hdmiOutputDevices[i]->address();
-        String8 name = hdmiOutputDevices[i]->getName();
+        String8 address = String8(hdmiOutputDevices[i]->address().c_str());
+        std::string name = hdmiOutputDevices[i]->getName();
         status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
                                                       AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                                       address.c_str(),
@@ -4134,12 +4202,12 @@
         profileUpdated |= (status == NO_ERROR);
     }
     // FIXME: Why doing this for input HDMI devices if we don't augment their reported formats?
-    DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromTypeMask(
+    DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
                 AUDIO_DEVICE_IN_HDMI);
     for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
         // Simulate reconnection to update enabled surround sound formats.
-        String8 address = hdmiInputDevices[i]->address();
-        String8 name = hdmiInputDevices[i]->getName();
+        String8 address = String8(hdmiInputDevices[i]->address().c_str());
+        std::string name = hdmiInputDevices[i]->getName();
         status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
                                                       AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                                       address.c_str(),
@@ -4450,7 +4518,7 @@
                 // give a valid ID to an attached device once confirmed it is reachable
                 if (!device->isAttached()) {
                     device->attach(hwModule);
-                    device->importAudioPort(inProfile, true);
+                    device->importAudioPortAndPickAudioProfile(inProfile, true);
                 }
             }
             inputDesc->close();
@@ -4481,11 +4549,11 @@
     }
     // If microphones address is empty, set it according to device type
     for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
-        if (mAvailableInputDevices[i]->address().isEmpty()) {
+        if (mAvailableInputDevices[i]->address().empty()) {
             if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                mAvailableInputDevices[i]->setAddress(String8(AUDIO_BOTTOM_MICROPHONE_ADDRESS));
+                mAvailableInputDevices[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
             } else if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
-                mAvailableInputDevices[i]->setAddress(String8(AUDIO_BACK_MICROPHONE_ADDRESS));
+                mAvailableInputDevices[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
             }
         }
     }
@@ -4530,7 +4598,7 @@
                                    const sp<SwAudioOutputDescriptor>& outputDesc)
 {
     mOutputs.add(output, outputDesc);
-    applyStreamVolumes(outputDesc, AUDIO_DEVICE_NONE, 0 /* delayMs */, true /* force */);
+    applyStreamVolumes(outputDesc, DeviceTypeSet(), 0 /* delayMs */, true /* force */);
     updateMono(output); // update mono status when adding to output list
     selectOutputForMusicEffects();
     nextAudioPortGeneration();
@@ -4554,7 +4622,7 @@
                                                    SortedVector<audio_io_handle_t>& outputs)
 {
     audio_devices_t deviceType = device->type();
-    const String8 &address = device->address();
+    const String8 &address = String8(device->address().c_str());
     sp<SwAudioOutputDescriptor> desc;
 
     if (audio_device_is_digital(deviceType)) {
@@ -4567,7 +4635,7 @@
         for (size_t i = 0; i < mOutputs.size(); i++) {
             desc = mOutputs.valueAt(i);
             if (!desc->isDuplicated() && desc->supportsDevice(device)
-                    && desc->deviceSupportsEncodedFormats(deviceType)) {
+                    && desc->devicesSupportEncodedFormats({deviceType})) {
                 ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
                       mOutputs.keyAt(i), device->toString().c_str());
                 outputs.add(mOutputs.keyAt(i));
@@ -4606,7 +4674,7 @@
                     // matching profile: save the sample rates, format and channel masks supported
                     // by the profile in our device descriptor
                     if (audio_device_is_digital(deviceType)) {
-                        device->importAudioPort(profile);
+                        device->importAudioPortAndPickAudioProfile(profile);
                     }
                     break;
                 }
@@ -4622,7 +4690,7 @@
             }
 
             ALOGV("opening output for device %08x with params %s profile %p name %s",
-                  deviceType, address.string(), profile.get(), profile->getName().string());
+                  deviceType, address.string(), profile.get(), profile->getName().c_str());
             desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
             status_t status = desc->open(nullptr, DeviceVector(device),
@@ -4708,7 +4776,7 @@
                 outputs.add(output);
                 // Load digital format info only for digital devices
                 if (audio_device_is_digital(deviceType)) {
-                    device->importAudioPort(profile);
+                    device->importAudioPortAndPickAudioProfile(profile);
                 }
 
                 if (device_distinguishes_on_address(deviceType)) {
@@ -4732,7 +4800,7 @@
             if (!desc->isDuplicated()) {
                 // exact match on device
                 if (device_distinguishes_on_address(deviceType) && desc->supportsDevice(device)
-                        && desc->deviceSupportsEncodedFormats(deviceType)) {
+                        && desc->devicesSupportEncodedFormats({deviceType})) {
                     outputs.add(mOutputs.keyAt(i));
                 } else if (!mAvailableOutputDevices.containsAtLeastOne(desc->supportedDevices())) {
                     ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
@@ -4802,7 +4870,7 @@
                 desc = mInputs.valueAt(input_index);
                 if (desc->mProfile == profile) {
                     if (audio_device_is_digital(device->type())) {
-                        device->importAudioPort(profile);
+                        device->importAudioPortAndPickAudioProfile(profile);
                     }
                     break;
                 }
@@ -4826,7 +4894,7 @@
                                          &input);
 
             if (status == NO_ERROR) {
-                const String8& address = device->address();
+                const String8& address = String8(device->address().c_str());
                 if (!address.isEmpty()) {
                     char *param = audio_device_address_to_parameter(device->type(), address);
                     mpClientInterface->setParameters(input, String8(param));
@@ -4851,7 +4919,7 @@
                 profile_index--;
             } else {
                 if (audio_device_is_digital(device->type())) {
-                    device->importAudioPort(profile);
+                    device->importAudioPortAndPickAudioProfile(profile);
                 }
                 ALOGV("checkInputsForDevice(): adding input %d", input);
             }
@@ -5003,7 +5071,7 @@
                 i, openOutputs.valueAt(i)->isDuplicated(),
                 openOutputs.valueAt(i)->supportedDevices().toString().c_str());
         if (openOutputs.valueAt(i)->supportsAllDevices(devices)
-                && openOutputs.valueAt(i)->deviceSupportsEncodedFormats(devices.types())) {
+                && openOutputs.valueAt(i)->devicesSupportEncodedFormats(devices.types())) {
             ALOGVV("%s() found output %d", __func__, openOutputs.keyAt(i));
             outputs.add(openOutputs.keyAt(i));
         }
@@ -5038,6 +5106,7 @@
 
     DeviceVector oldDevices = mEngine->getOutputDevicesForAttributes(attr, 0, true /*fromCache*/);
     DeviceVector newDevices = mEngine->getOutputDevicesForAttributes(attr, 0, false /*fromCache*/);
+
     SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevices(oldDevices, mPreviousOutputs);
     SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevices(newDevices, mOutputs);
 
@@ -5138,9 +5207,8 @@
     }
 
     bool isScoConnected =
-            ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET &
-                    ~AUDIO_DEVICE_BIT_IN) != 0) ||
-            ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0);
+            (mAvailableInputDevices.types().count(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0 ||
+             !Intersection(mAvailableOutputDevices.types(), getAudioDeviceOutAllScoSet()).empty());
 
     // if suspended, restore A2DP output if:
     //      ((SCO device is NOT connected) ||
@@ -5302,12 +5370,13 @@
     }
     /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
       and doesn't really need to.*/
-    DeviceVector speakerSafeDevices = devices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
+    DeviceVector speakerSafeDevices = devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
     if (!speakerSafeDevices.isEmpty()) {
-        devices.merge(mAvailableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER));
+        devices.merge(mAvailableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
         devices.remove(speakerSafeDevices);
     }
-    return devices.types();
+    // FIXME: use DeviceTypeSet when Java layer is ready for it.
+    return deviceTypesToBitMask(devices.types());
 }
 
 void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
@@ -5367,7 +5436,7 @@
         auto ttsVolumeSource = toVolumeSource(AUDIO_STREAM_TTS);
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-            setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, AUDIO_DEVICE_NONE);
+            setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet());
             const uint32_t latency = desc->latency() * 2;
             if (latency > maxLatency) {
                 maxLatency = latency;
@@ -5683,9 +5752,9 @@
 float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
                                         VolumeSource volumeSource,
                                         int index,
-                                        audio_devices_t device)
+                                        const DeviceTypeSet& deviceTypes)
 {
-    float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(device), index);
+    float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);
 
     // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
     // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
@@ -5701,7 +5770,7 @@
             && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
             mOutputs.isActive(ringVolumeSrc, 0)) {
         auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
-        const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, device);
+        const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes);
         return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
     }
 
@@ -5716,9 +5785,9 @@
              volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) ||
              volumeSource == a11yVolumeSrc)) {
         auto &voiceCurves = getVolumeCurves(callVolumeSrc);
-        int voiceVolumeIndex = voiceCurves.getVolumeIndex(device);
+        int voiceVolumeIndex = voiceCurves.getVolumeIndex(deviceTypes);
         const float maxVoiceVolDb =
-                computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, device)
+                computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes)
                 + IN_CALL_EARPIECE_HEADROOM_DB;
         // FIXME: Workaround for call screening applications until a proper audio mode is defined
         // to support this scenario : Exempt the RING stream from the audio cap if the audio was
@@ -5744,9 +5813,10 @@
     // speaker is part of the select devices
     // - if music is playing, always limit the volume to current music volume,
     // with a minimum threshold at -36dB so that notification is always perceived.
-    if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                   AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                   AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) &&
+    if (!Intersection(deviceTypes,
+            {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+             AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
+             AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_HEARING_AID}).empty() &&
             ((volumeSource == alarmVolumeSrc ||
               volumeSource == ringVolumeSrc) ||
              (volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION)) ||
@@ -5761,31 +5831,33 @@
         if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
                 mLimitRingtoneVolume) {
             volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
-            audio_devices_t musicDevice =
+            DeviceTypeSet musicDevice =
                     mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
                                                            nullptr, true /*fromCache*/).types();
             auto &musicCurves = getVolumeCurves(AUDIO_STREAM_MUSIC);
-            float musicVolDb = computeVolume(musicCurves, musicVolumeSrc,
-                                             musicCurves.getVolumeIndex(musicDevice), musicDevice);
+            float musicVolDb = computeVolume(musicCurves,
+                                             musicVolumeSrc,
+                                             musicCurves.getVolumeIndex(musicDevice),
+                                             musicDevice);
             float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
                         musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
             if (volumeDb > minVolDb) {
                 volumeDb = minVolDb;
                 ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDb, musicVolDb);
             }
-            if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
-                          AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
+            if (!Intersection(deviceTypes, {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}).empty()) {
                 // on A2DP, also ensure notification volume is not too low compared to media when
                 // intended to be played
                 if ((volumeDb > -96.0f) &&
                         (musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
-                    ALOGV("%s increasing volume for volume source=%d device=0x%X from %f to %f",
-                          __func__, volumeSource, device, volumeDb,
+                    ALOGV("%s increasing volume for volume source=%d device=%s from %f to %f",
+                          __func__, volumeSource, dumpDeviceTypes(deviceTypes).c_str(), volumeDb,
                           musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
                     volumeDb = musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
                 }
             }
-        } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
+        } else if ((Volume::getDeviceForVolume(deviceTypes) != AUDIO_DEVICE_OUT_SPEAKER) ||
                    (!(volumeSource == alarmVolumeSrc || volumeSource == ringVolumeSrc))) {
             volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
         }
@@ -5824,7 +5896,7 @@
                                                VolumeSource volumeSource,
                                                int index,
                                                const sp<AudioOutputDescriptor>& outputDesc,
-                                               audio_devices_t device,
+                                               DeviceTypeSet deviceTypes,
                                                int delayMs,
                                                bool force)
 {
@@ -5850,17 +5922,20 @@
              volumeSource, forceUseForComm);
         return INVALID_OPERATION;
     }
-    if (device == AUDIO_DEVICE_NONE) {
-        device = outputDesc->devices().types();
+    if (deviceTypes.empty()) {
+        deviceTypes = outputDesc->devices().types();
     }
 
-    float volumeDb = computeVolume(curves, volumeSource, index, device);
-    if (outputDesc->isFixedVolume(device) ||
+    float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
+    if (outputDesc->isFixedVolume(deviceTypes) ||
             // Force VoIP volume to max for bluetooth SCO
-            ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
+
+            ((isVoiceVolSrc || isBtScoVolSrc) &&
+                    isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
         volumeDb = 0.0f;
     }
-    outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force);
+    outputDesc->setVolume(
+            volumeDb, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);
 
     if (isVoiceVolSrc || isBtScoVolSrc) {
         float voiceVolume;
@@ -5879,15 +5954,16 @@
 }
 
 void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
-                                                audio_devices_t device,
-                                                int delayMs,
-                                                bool force)
+                                            const DeviceTypeSet& deviceTypes,
+                                            int delayMs,
+                                            bool force)
 {
     ALOGVV("applyStreamVolumes() for device %08x", device);
     for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
         auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
         checkAndSetVolume(curves, toVolumeSource(volumeGroup),
-                          curves.getVolumeIndex(device), outputDesc, device, delayMs, force);
+                          curves.getVolumeIndex(deviceTypes),
+                          outputDesc, deviceTypes, delayMs, force);
     }
 }
 
@@ -5895,7 +5971,7 @@
                                          bool on,
                                          const sp<AudioOutputDescriptor>& outputDesc,
                                          int delayMs,
-                                         audio_devices_t device)
+                                         DeviceTypeSet deviceTypes)
 {
     std::vector<VolumeSource> sourcesToMute;
     for (auto attributes: mEngine->getAllAttributesForProductStrategy(strategy)) {
@@ -5907,7 +5983,7 @@
         }
     }
     for (auto source : sourcesToMute) {
-        setVolumeSourceMute(source, on, outputDesc, delayMs, device);
+        setVolumeSourceMute(source, on, outputDesc, delayMs, deviceTypes);
     }
 
 }
@@ -5916,10 +5992,10 @@
                                              bool on,
                                              const sp<AudioOutputDescriptor>& outputDesc,
                                              int delayMs,
-                                             audio_devices_t device)
+                                             DeviceTypeSet deviceTypes)
 {
-    if (device == AUDIO_DEVICE_NONE) {
-        device = outputDesc->devices().types();
+    if (deviceTypes.empty()) {
+        deviceTypes = outputDesc->devices().types();
     }
     auto &curves = getVolumeCurves(volumeSource);
     if (on) {
@@ -5928,7 +6004,7 @@
                     (volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
                      (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
                       AUDIO_POLICY_FORCE_NONE))) {
-                checkAndSetVolume(curves, volumeSource, 0, outputDesc, device, delayMs);
+                checkAndSetVolume(curves, volumeSource, 0, outputDesc, deviceTypes, delayMs);
             }
         }
         // increment mMuteCount after calling checkAndSetVolume() so that volume change is not
@@ -5941,9 +6017,9 @@
         }
         if (outputDesc->decMuteCount(volumeSource) == 0) {
             checkAndSetVolume(curves, volumeSource,
-                              curves.getVolumeIndex(device),
+                              curves.getVolumeIndex(deviceTypes),
                               outputDesc,
-                              device,
+                              deviceTypes,
                               delayMs);
         }
     }
@@ -6085,24 +6161,24 @@
         formatSet.insert(enforcedSurround.begin(), enforcedSurround.end());
     }
     for (const auto& format : formatSet) {
-        formatsPtr->push(format);
+        formatsPtr->push_back(format);
     }
 }
 
-void AudioPolicyManager::modifySurroundChannelMasks(ChannelsVector *channelMasksPtr) {
-    ChannelsVector &channelMasks = *channelMasksPtr;
+void AudioPolicyManager::modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr) {
+    ChannelMaskSet &channelMasks = *channelMasksPtr;
     audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
             AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
 
     // If NEVER, then remove support for channelMasks > stereo.
     if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
-        for (size_t maskIndex = 0; maskIndex < channelMasks.size(); ) {
-            audio_channel_mask_t channelMask = channelMasks[maskIndex];
+        for (auto it = channelMasks.begin(); it != channelMasks.end();) {
+            audio_channel_mask_t channelMask = *it;
             if (channelMask & ~AUDIO_CHANNEL_OUT_STEREO) {
                 ALOGI("%s: force NEVER, so remove channelMask 0x%08x", __FUNCTION__, channelMask);
-                channelMasks.removeAt(maskIndex);
+                it = channelMasks.erase(it);
             } else {
-                maskIndex++;
+                ++it;
             }
         }
     // If ALWAYS or MANUAL, then make sure we at least support 5.1
@@ -6118,7 +6194,7 @@
         }
         // If not then add 5.1 support.
         if (!supports5dot1) {
-            channelMasks.add(AUDIO_CHANNEL_OUT_5POINT1);
+            channelMasks.insert(AUDIO_CHANNEL_OUT_5POINT1);
             ALOGI("%s: force MANUAL or ALWAYS, so adding channelMask for 5.1 surround", __func__);
         }
     }
@@ -6147,12 +6223,12 @@
                 || isDeviceOfModule(devDesc, AUDIO_HARDWARE_MODULE_ID_MSD)) {
             modifySurroundFormats(devDesc, &formats);
         }
-        profiles.setFormats(formats);
+        addProfilesForFormats(profiles, formats);
     }
 
     for (audio_format_t format : profiles.getSupportedFormats()) {
-        ChannelsVector channelMasks;
-        SampleRateVector samplingRates;
+        ChannelMaskSet channelMasks;
+        SampleRateSet samplingRates;
         AudioParameter requestedParameters;
         requestedParameters.addInt(String8(AudioParameter::keyFormat), format);
 
@@ -6183,7 +6259,8 @@
                 }
             }
         }
-        profiles.addProfileFromHal(new AudioProfile(format, channelMasks, samplingRates));
+        addDynamicAudioProfileAndSort(
+                profiles, new AudioProfile(format, channelMasks, samplingRates));
     }
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 5f651cc..d516d7b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -31,15 +31,14 @@
 #include <utils/SortedVector.h>
 #include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
+#include <media/AudioProfile.h>
 #include <media/PatchBuilder.h>
 #include "AudioPolicyInterface.h"
 
 #include <AudioPolicyManagerObserver.h>
-#include <AudioGain.h>
 #include <AudioPolicyConfig.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <AudioPatch.h>
-#include <AudioProfile.h>
 #include <DeviceDescriptor.h>
 #include <IOProfile.h>
 #include <HwModule.h>
@@ -177,7 +176,7 @@
                                      IVolumeCurves &volumeCurves);
 
         status_t getVolumeIndex(const IVolumeCurves &curves, int &index,
-                                audio_devices_t device) const;
+                                const DeviceTypeSet& deviceTypes) const;
 
         // return the strategy corresponding to a given stream type
         virtual uint32_t getStrategyForStream(audio_stream_type_t stream)
@@ -259,6 +258,12 @@
                 const Vector<AudioDeviceTypeAddr>& devices);
         virtual status_t removeUidDeviceAffinities(uid_t uid);
 
+        virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   const AudioDeviceTypeAddr &device);
+        virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy);
+        virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   AudioDeviceTypeAddr &device);
+
         virtual status_t startAudioSource(const struct audio_port_config *source,
                                           const audio_attributes_t *attributes,
                                           audio_port_handle_t *portId,
@@ -423,7 +428,7 @@
         virtual float computeVolume(IVolumeCurves &curves,
                                     VolumeSource volumeSource,
                                     int index,
-                                    audio_devices_t device);
+                                    const DeviceTypeSet& deviceTypes);
 
         // rescale volume index from srcStream within range of dstStream
         int rescaleVolumeIndex(int srcIndex,
@@ -433,12 +438,13 @@
         virtual status_t checkAndSetVolume(IVolumeCurves &curves,
                                            VolumeSource volumeSource, int index,
                                            const sp<AudioOutputDescriptor>& outputDesc,
-                                           audio_devices_t device,
+                                           DeviceTypeSet deviceTypes,
                                            int delayMs = 0, bool force = false);
 
         // apply all stream volumes to the specified output and device
         void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
-                                audio_devices_t device, int delayMs = 0, bool force = false);
+                                const DeviceTypeSet& deviceTypes,
+                                int delayMs = 0, bool force = false);
 
         /**
          * @brief setStrategyMute Mute or unmute all active clients on the considered output
@@ -453,7 +459,7 @@
                              bool on,
                              const sp<AudioOutputDescriptor>& outputDesc,
                              int delayMs = 0,
-                             audio_devices_t device = AUDIO_DEVICE_NONE);
+                             DeviceTypeSet deviceTypes = DeviceTypeSet());
 
         /**
          * @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
@@ -468,7 +474,7 @@
                                  bool on,
                                  const sp<AudioOutputDescriptor>& outputDesc,
                                  int delayMs = 0,
-                                 audio_devices_t device = AUDIO_DEVICE_NONE);
+                                 DeviceTypeSet deviceTypes = DeviceTypeSet());
 
         audio_mode_t getPhoneState();
 
@@ -496,13 +502,19 @@
         // close an input.
         void closeInput(audio_io_handle_t input);
 
-        // runs all the checks required for accomodating changes in devices and outputs
+        // runs all the checks required for accommodating changes in devices and outputs
         // if 'onOutputsChecked' callback is provided, it is executed after the outputs
         // check via 'checkOutputForAllStrategies'. If the callback returns 'true',
         // A2DP suspend status is rechecked.
         void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked = nullptr);
 
         /**
+         * @brief updates routing for all outputs (including call if call in progress).
+         * @param delayMs delay for unmuting if required
+         */
+        void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0);
+
+        /**
          * @brief checkOutputForAttributes checks and if necessary changes outputs used for the
          * given audio attributes.
          * must be called every time a condition that affects the output choice for a given
@@ -647,16 +659,13 @@
         }
         String8 getFirstDeviceAddress(const DeviceVector &devices) const
         {
-            return (devices.size() > 0) ? devices.itemAt(0)->address() : String8("");
+            return (devices.size() > 0) ?
+                    String8(devices.itemAt(0)->address().c_str()) : String8("");
         }
 
         uint32_t updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs = 0);
         sp<AudioPatch> createTelephonyPatch(bool isRx, const sp<DeviceDescriptor> &device,
                                             uint32_t delayMs);
-        sp<DeviceDescriptor> findDevice(
-                const DeviceVector& devices, audio_devices_t device) const;
-        audio_devices_t getModuleDeviceTypes(
-                const DeviceVector& devices, const char *moduleId) const;
         bool isDeviceOfModule(const sp<DeviceDescriptor>& devDesc, const char *moduleId) const;
 
         status_t startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
@@ -763,7 +772,7 @@
 private:
         // Add or remove AC3 DTS encodings based on user preferences.
         void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
-        void modifySurroundChannelMasks(ChannelsVector *channelMasksPtr);
+        void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr);
 
         // Support for Multi-Stream Decoder (MSD) module
         sp<DeviceDescriptor> getMsdAudioInDevice() const;
diff --git a/services/audiopolicy/service/Android.mk b/services/audiopolicy/service/Android.mk
index c4f4c56..1144970 100644
--- a/services/audiopolicy/service/Android.mk
+++ b/services/audiopolicy/service/Android.mk
@@ -38,8 +38,6 @@
 LOCAL_STATIC_LIBRARIES := \
     libaudiopolicycomponents
 
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
 LOCAL_MODULE:= libaudiopolicyservice
 
 LOCAL_CFLAGS += -fvisibility=hidden
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index d51cc6e..6de0c80 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -39,8 +39,7 @@
 status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
                                                            audio_io_handle_t *output,
                                                            audio_config_t *config,
-                                                           audio_devices_t *devices,
-                                                           const String8& address,
+                                                           const sp<DeviceDescriptorBase>& device,
                                                            uint32_t *latencyMs,
                                                            audio_output_flags_t flags)
 {
@@ -49,7 +48,7 @@
         ALOGW("%s: could not get AudioFlinger", __func__);
         return PERMISSION_DENIED;
     }
-    return af->openOutput(module, output, config, devices, address, latencyMs, flags);
+    return af->openOutput(module, output, config, device, latencyMs, flags);
 }
 
 audio_io_handle_t AudioPolicyService::AudioPolicyClient::openDuplicateOutput(
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index fa8da89..47a103b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -1325,4 +1325,33 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyService::setPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   const AudioDeviceTypeAddr &device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->setPreferredDeviceForStrategy(strategy, device);
+}
+
+status_t AudioPolicyService::removePreferredDeviceForStrategy(product_strategy_t strategy)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->removePreferredDeviceForStrategy(strategy);
+}
+
+status_t AudioPolicyService::getPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   AudioDeviceTypeAddr &device)
+{
+    if (mAudioPolicyManager == NULL) {
+        return NO_INIT;
+    }
+    Mutex::Autolock _l(mLock);
+    return mAudioPolicyManager->getPreferredDeviceForStrategy(strategy, device);
+}
+
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index d1b59c1..90939ce 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -725,11 +725,11 @@
     if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
         return BAD_VALUE;
     }
-    if (args.size() == 3 && args[0] == String16("set-uid-state")) {
+    if (args.size() >= 3 && args[0] == String16("set-uid-state")) {
         return handleSetUidState(args, err);
-    } else if (args.size() == 2 && args[0] == String16("reset-uid-state")) {
+    } else if (args.size() >= 2 && args[0] == String16("reset-uid-state")) {
         return handleResetUidState(args, err);
-    } else if (args.size() == 2 && args[0] == String16("get-uid-state")) {
+    } else if (args.size() >= 2 && args[0] == String16("get-uid-state")) {
         return handleGetUidState(args, out, err);
     } else if (args.size() == 1 && args[0] == String16("help")) {
         printHelp(out);
@@ -739,14 +739,32 @@
     return BAD_VALUE;
 }
 
-status_t AudioPolicyService::handleSetUidState(Vector<String16>& args, int err) {
-    PermissionController pc;
-    int uid = pc.getPackageUid(args[1], 0);
-    if (uid <= 0) {
-        ALOGE("Unknown package: '%s'", String8(args[1]).string());
-        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+static status_t getUidForPackage(String16 packageName, int userId, /*inout*/uid_t& uid, int err) {
+    if (userId < 0) {
+        ALOGE("Invalid user: %d", userId);
+        dprintf(err, "Invalid user: %d\n", userId);
         return BAD_VALUE;
     }
+
+    PermissionController pc;
+    uid = pc.getPackageUid(packageName, 0);
+    if (uid <= 0) {
+        ALOGE("Unknown package: '%s'", String8(packageName).string());
+        dprintf(err, "Unknown package: '%s'\n", String8(packageName).string());
+        return BAD_VALUE;
+    }
+
+    uid = multiuser_get_uid(userId, uid);
+    return NO_ERROR;
+}
+
+status_t AudioPolicyService::handleSetUidState(Vector<String16>& args, int err) {
+    // Valid arg.size() is 3 or 5, args.size() is 5 with --user option.
+    if (!(args.size() == 3 || args.size() == 5)) {
+        printHelp(err);
+        return BAD_VALUE;
+    }
+
     bool active = false;
     if (args[2] == String16("active")) {
         active = true;
@@ -754,30 +772,59 @@
         ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
         return BAD_VALUE;
     }
+
+    int userId = 0;
+    if (args.size() >= 5 && args[3] == String16("--user")) {
+        userId = atoi(String8(args[4]));
+    }
+
+    uid_t uid;
+    if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
+        return BAD_VALUE;
+    }
+
     mUidPolicy->addOverrideUid(uid, active);
     return NO_ERROR;
 }
 
 status_t AudioPolicyService::handleResetUidState(Vector<String16>& args, int err) {
-    PermissionController pc;
-    int uid = pc.getPackageUid(args[1], 0);
-    if (uid < 0) {
-        ALOGE("Unknown package: '%s'", String8(args[1]).string());
-        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+    // Valid arg.size() is 2 or 4, args.size() is 4 with --user option.
+    if (!(args.size() == 2 || args.size() == 4)) {
+        printHelp(err);
         return BAD_VALUE;
     }
+
+    int userId = 0;
+    if (args.size() >= 4 && args[2] == String16("--user")) {
+        userId = atoi(String8(args[3]));
+    }
+
+    uid_t uid;
+    if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
+        return BAD_VALUE;
+    }
+
     mUidPolicy->removeOverrideUid(uid);
     return NO_ERROR;
 }
 
 status_t AudioPolicyService::handleGetUidState(Vector<String16>& args, int out, int err) {
-    PermissionController pc;
-    int uid = pc.getPackageUid(args[1], 0);
-    if (uid < 0) {
-        ALOGE("Unknown package: '%s'", String8(args[1]).string());
-        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+    // Valid arg.size() is 2 or 4, args.size() is 4 with --user option.
+    if (!(args.size() == 2 || args.size() == 4)) {
+        printHelp(err);
         return BAD_VALUE;
     }
+
+    int userId = 0;
+    if (args.size() >= 4 && args[2] == String16("--user")) {
+        userId = atoi(String8(args[3]));
+    }
+
+    uid_t uid;
+    if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
+        return BAD_VALUE;
+    }
+
     if (mUidPolicy->isUidActive(uid)) {
         return dprintf(out, "active\n");
     } else {
@@ -787,9 +834,9 @@
 
 status_t AudioPolicyService::printHelp(int out) {
     return dprintf(out, "Audio policy service commands:\n"
-        "  get-uid-state <PACKAGE> gets the uid state\n"
-        "  set-uid-state <PACKAGE> <active|idle> overrides the uid state\n"
-        "  reset-uid-state <PACKAGE> clears the uid state override\n"
+        "  get-uid-state <PACKAGE> [--user USER_ID] gets the uid state\n"
+        "  set-uid-state <PACKAGE> <active|idle> [--user USER_ID] overrides the uid state\n"
+        "  reset-uid-state <PACKAGE> [--user USER_ID] clears the uid state override\n"
         "  help print this message\n");
 }
 
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 74aea0d..7b72dc1 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -224,6 +224,15 @@
 
     virtual status_t removeUidDeviceAffinities(uid_t uid);
 
+    virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   const AudioDeviceTypeAddr &device);
+
+    virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy);
+
+
+    virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
+                                                   AudioDeviceTypeAddr &device);
+
     virtual status_t startAudioSource(const struct audio_port_config *source,
                                       const audio_attributes_t *attributes,
                                       audio_port_handle_t *portId);
@@ -622,8 +631,7 @@
         virtual status_t openOutput(audio_module_handle_t module,
                                     audio_io_handle_t *output,
                                     audio_config_t *config,
-                                    audio_devices_t *devices,
-                                    const String8& address,
+                                    const sp<DeviceDescriptorBase>& device,
                                     uint32_t *latencyMs,
                                     audio_output_flags_t flags);
         // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
new file mode 100644
index 0000000..efdb241
--- /dev/null
+++ b/services/audiopolicy/tests/Android.bp
@@ -0,0 +1,71 @@
+cc_test {
+    name: "audiopolicy_tests",
+
+    include_dirs: [
+        "frameworks/av/services/audiopolicy",
+    ],
+
+    shared_libs: [
+        "libaudioclient",
+        "libaudiofoundation",
+        "libaudiopolicy",
+        "libaudiopolicymanagerdefault",
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+        "libxml2",
+    ],
+
+    static_libs: ["libaudiopolicycomponents"],
+
+    header_libs: [
+        "libaudiopolicycommon",
+        "libaudiopolicyengine_interface_headers",
+        "libaudiopolicymanager_interface_headers",
+    ],
+
+    srcs: ["audiopolicymanager_tests.cpp"],
+
+    data: [":audiopolicytest_configuration_files",],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+
+}
+
+
+cc_test {
+    name: "audio_health_tests",
+
+    shared_libs: [
+        "libaudiofoundation",
+        "libaudioclient",
+        "libaudiopolicymanagerdefault",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+    ],
+
+    static_libs: ["libaudiopolicycomponents"],
+
+    header_libs: [
+        "libaudiopolicyengine_interface_headers",
+        "libaudiopolicymanager_interface_headers",
+    ],
+
+    srcs: ["audio_health_tests.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+
+}
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
deleted file mode 100644
index ab9f78b..0000000
--- a/services/audiopolicy/tests/Android.mk
+++ /dev/null
@@ -1,65 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
-  frameworks/av/services/audiopolicy \
-  $(call include-path-for, audio-utils) \
-
-LOCAL_SHARED_LIBRARIES := \
-  libaudiopolicymanagerdefault \
-  libbase \
-  liblog \
-  libmedia_helper \
-  libutils \
-
-LOCAL_STATIC_LIBRARIES := \
-  libaudiopolicycomponents \
-
-LOCAL_HEADER_LIBRARIES := \
-    libaudiopolicycommon \
-    libaudiopolicyengine_interface_headers \
-    libaudiopolicymanager_interface_headers
-
-LOCAL_SRC_FILES := \
-  audiopolicymanager_tests.cpp \
-
-LOCAL_MODULE := audiopolicy_tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_NATIVE_TEST)
-
-# system/audio.h utilities test
-
-include $(CLEAR_VARS)
-
-LOCAL_SHARED_LIBRARIES := \
-  libbase \
-  liblog \
-  libmedia_helper \
-  libutils
-
-LOCAL_HEADER_LIBRARIES := \
-  libmedia_headers
-
-LOCAL_SRC_FILES := \
-  systemaudio_tests.cpp \
-
-LOCAL_MODULE := systemaudio_tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
new file mode 100644
index 0000000..c2a92d7
--- /dev/null
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#include <map>
+
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioPolicyTestClient.h"
+
+namespace android {
+
+class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
+public:
+    // AudioPolicyClientInterface implementation
+    audio_module_handle_t loadHwModule(const char * /*name*/) override {
+        return mNextModuleHandle++;
+    }
+
+    status_t openOutput(audio_module_handle_t module,
+                        audio_io_handle_t *output,
+                        audio_config_t * /*config*/,
+                        const sp<DeviceDescriptorBase>& /*device*/,
+                        uint32_t * /*latencyMs*/,
+                        audio_output_flags_t /*flags*/) override {
+        if (module >= mNextModuleHandle) {
+            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+                  __func__, module, mNextModuleHandle);
+            return BAD_VALUE;
+        }
+        *output = mNextIoHandle++;
+        return NO_ERROR;
+    }
+
+    audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
+                                          audio_io_handle_t /*output2*/) override {
+        audio_io_handle_t id = mNextIoHandle++;
+        return id;
+    }
+
+    status_t openInput(audio_module_handle_t module,
+                       audio_io_handle_t *input,
+                       audio_config_t * /*config*/,
+                       audio_devices_t * /*device*/,
+                       const String8 & /*address*/,
+                       audio_source_t /*source*/,
+                       audio_input_flags_t /*flags*/) override {
+        if (module >= mNextModuleHandle) {
+            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+                  __func__, module, mNextModuleHandle);
+            return BAD_VALUE;
+        }
+        *input = mNextIoHandle++;
+        return NO_ERROR;
+    }
+
+    status_t createAudioPatch(const struct audio_patch *patch,
+                              audio_patch_handle_t *handle,
+                              int /*delayMs*/) override {
+        *handle = mNextPatchHandle++;
+        mActivePatches.insert(std::make_pair(*handle, *patch));
+        return NO_ERROR;
+    }
+
+    status_t releaseAudioPatch(audio_patch_handle_t handle,
+                               int /*delayMs*/) override {
+        if (mActivePatches.erase(handle) != 1) {
+            if (handle >= mNextPatchHandle) {
+                ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
+                      __func__, handle, mNextPatchHandle);
+            } else {
+                ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
+            }
+            return BAD_VALUE;
+        }
+        return NO_ERROR;
+    }
+
+    // Helper methods for tests
+    size_t getActivePatchesCount() const { return mActivePatches.size(); }
+
+    const struct audio_patch *getLastAddedPatch() const {
+        if (mActivePatches.empty()) {
+            return nullptr;
+        }
+        auto it = --mActivePatches.end();
+        return &it->second;
+    };
+
+private:
+    audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
+    audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
+    audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
+    std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index e4c64e5..b92a2e6 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -31,8 +31,7 @@
     status_t openOutput(audio_module_handle_t /*module*/,
                         audio_io_handle_t* /*output*/,
                         audio_config_t* /*config*/,
-                        audio_devices_t* /*devices*/,
-                        const String8& /*address*/,
+                        const sp<DeviceDescriptorBase>& /*device*/,
                         uint32_t* /*latencyMs*/,
                         audio_output_flags_t /*flags*/) override { return NO_INIT; }
     audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index fe543a6..c77dcdc 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -24,6 +24,7 @@
     explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
             : AudioPolicyManager(clientInterface, true /*forTesting*/) { }
     using AudioPolicyManager::getConfig;
+    using AudioPolicyManager::loadConfig;
     using AudioPolicyManager::initialize;
 };
 
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
new file mode 100644
index 0000000..8736cf1
--- /dev/null
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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_TAG "AudioPolicy_Boot_Test"
+
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#include <media/AudioSystem.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include "AudioPolicyManagerTestClient.h"
+#include "AudioPolicyTestManager.h"
+
+using namespace android;
+
+TEST(AudioHealthTest, AttachedDeviceFound) {
+    unsigned int numPorts;
+    unsigned int generation1;
+    unsigned int generation;
+    struct audio_port *audioPorts = NULL;
+    int attempts = 10;
+    do {
+        if (attempts-- < 0) {
+            free(audioPorts);
+            GTEST_FAIL() << "Query audio ports time out";
+        }
+        numPorts = 0;
+        ASSERT_EQ(NO_ERROR, AudioSystem::listAudioPorts(
+                AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, NULL, &generation1));
+        if (numPorts == 0) {
+            free(audioPorts);
+            GTEST_FAIL() << "Number of audio ports should not be zero";
+        }
+
+        audioPorts = (struct audio_port *)realloc(audioPorts, numPorts * sizeof(struct audio_port));
+        status_t status = AudioSystem::listAudioPorts(
+                AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, audioPorts, &generation);
+        if (status != NO_ERROR) {
+            free(audioPorts);
+            GTEST_FAIL() << "Query audio ports failed";
+        }
+    } while (generation1 != generation);
+    std::unordered_set<audio_devices_t> attachedDevices;
+    for (int i = 0 ; i < numPorts; i++) {
+        attachedDevices.insert(audioPorts[i].ext.device.type);
+    }
+    free(audioPorts);
+
+    AudioPolicyManagerTestClient client;
+    AudioPolicyTestManager manager(&client);
+    manager.loadConfig();
+    ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+
+    for (auto desc : manager.getConfig().getAvailableInputDevices()) {
+        ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+    }
+    for (auto desc : manager.getConfig().getAvailableOutputDevices()) {
+        ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+    }
+}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index e10a716..299a50f 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -15,16 +15,23 @@
  */
 
 #include <memory>
-#include <set>
+#include <string>
 #include <sys/wait.h>
 #include <unistd.h>
 
 #include <gtest/gtest.h>
 
 #define LOG_TAG "APM_Test"
-#include <log/log.h>
+#include <Serializer.h>
+#include <android-base/file.h>
+#include <media/AudioPolicy.h>
 #include <media/PatchBuilder.h>
+#include <media/RecordingActivityTracker.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
 
+#include "AudioPolicyInterface.h"
+#include "AudioPolicyManagerTestClient.h"
 #include "AudioPolicyTestClient.h"
 #include "AudioPolicyTestManager.h"
 
@@ -50,77 +57,6 @@
 }
 
 
-class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
-  public:
-    // AudioPolicyClientInterface implementation
-    audio_module_handle_t loadHwModule(const char* /*name*/) override {
-        return mNextModuleHandle++;
-    }
-
-    status_t openOutput(audio_module_handle_t module,
-                        audio_io_handle_t* output,
-                        audio_config_t* /*config*/,
-                        audio_devices_t* /*devices*/,
-                        const String8& /*address*/,
-                        uint32_t* /*latencyMs*/,
-                        audio_output_flags_t /*flags*/) override {
-        if (module >= mNextModuleHandle) {
-            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
-                    __func__, module, mNextModuleHandle);
-            return BAD_VALUE;
-        }
-        *output = mNextIoHandle++;
-        return NO_ERROR;
-    }
-
-    status_t openInput(audio_module_handle_t module,
-                       audio_io_handle_t* input,
-                       audio_config_t* /*config*/,
-                       audio_devices_t* /*device*/,
-                       const String8& /*address*/,
-                       audio_source_t /*source*/,
-                       audio_input_flags_t /*flags*/) override {
-        if (module >= mNextModuleHandle) {
-            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
-                    __func__, module, mNextModuleHandle);
-            return BAD_VALUE;
-        }
-        *input = mNextIoHandle++;
-        return NO_ERROR;
-    }
-
-    status_t createAudioPatch(const struct audio_patch* /*patch*/,
-                              audio_patch_handle_t* handle,
-                              int /*delayMs*/) override {
-        *handle = mNextPatchHandle++;
-        mActivePatches.insert(*handle);
-        return NO_ERROR;
-    }
-
-    status_t releaseAudioPatch(audio_patch_handle_t handle,
-                               int /*delayMs*/) override {
-        if (mActivePatches.erase(handle) != 1) {
-            if (handle >= mNextPatchHandle) {
-                ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
-                        __func__, handle, mNextPatchHandle);
-            } else {
-                ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
-            }
-            return BAD_VALUE;
-        }
-        return NO_ERROR;
-    }
-
-    // Helper methods for tests
-    size_t getActivePatchesCount() const { return mActivePatches.size(); }
-
-  private:
-    audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
-    audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
-    audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
-    std::set<audio_patch_handle_t> mActivePatches;
-};
-
 class PatchCountCheck {
   public:
     explicit PatchCountCheck(AudioPolicyManagerTestClient *client)
@@ -143,18 +79,34 @@
   protected:
     void SetUp() override;
     void TearDown() override;
-    virtual void SetUpConfig(AudioPolicyConfig *config) { (void)config; }
+    virtual void SetUpManagerConfig();
 
     void dumpToLog();
+    // When explicitly routing is needed, selectedDeviceId need to be set as the wanted port
+    // id. Otherwise, selectedDeviceId need to be initialized as AUDIO_PORT_HANDLE_NONE.
     void getOutputForAttr(
             audio_port_handle_t *selectedDeviceId,
             audio_format_t format,
             int channelMask,
             int sampleRate,
             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+            audio_port_handle_t *portId = nullptr,
+            audio_attributes_t attr = {});
+    void getInputForAttr(
+            const audio_attributes_t &attr,
+            audio_unique_id_t riid,
+            audio_port_handle_t *selectedDeviceId,
+            audio_format_t format,
+            int channelMask,
+            int sampleRate,
+            audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
             audio_port_handle_t *portId = nullptr);
     PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
 
+    void findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
+            const std::string &address, audio_port &foundPort);
+    static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch* patch);
+
     std::unique_ptr<AudioPolicyManagerTestClient> mClient;
     std::unique_ptr<AudioPolicyTestManager> mManager;
 };
@@ -162,8 +114,7 @@
 void AudioPolicyManagerTest::SetUp() {
     mClient.reset(new AudioPolicyManagerTestClient);
     mManager.reset(new AudioPolicyTestManager(mClient.get()));
-    mManager->getConfig().setDefault();
-    SetUpConfig(&mManager->getConfig());  // Subclasses may want to customize the config.
+    SetUpManagerConfig();  // Subclasses may want to customize the config.
     ASSERT_EQ(NO_ERROR, mManager->initialize());
     ASSERT_EQ(NO_ERROR, mManager->initCheck());
 }
@@ -173,6 +124,10 @@
     mClient.reset();
 }
 
+void AudioPolicyManagerTest::SetUpManagerConfig() {
+    mManager->getConfig().setDefault();
+}
+
 void AudioPolicyManagerTest::dumpToLog() {
     int pipefd[2];
     ASSERT_NE(-1, pipe(pipefd));
@@ -209,15 +164,14 @@
         int channelMask,
         int sampleRate,
         audio_output_flags_t flags,
-        audio_port_handle_t *portId) {
-    audio_attributes_t attr = {};
+        audio_port_handle_t *portId,
+        audio_attributes_t attr) {
     audio_io_handle_t output = AUDIO_PORT_HANDLE_NONE;
     audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
     config.sample_rate = sampleRate;
     config.channel_mask = channelMask;
     config.format = format;
-    *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     audio_port_handle_t localPortId;
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
@@ -227,6 +181,71 @@
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
 }
 
+void AudioPolicyManagerTest::getInputForAttr(
+        const audio_attributes_t &attr,
+        audio_unique_id_t riid,
+        audio_port_handle_t *selectedDeviceId,
+        audio_format_t format,
+        int channelMask,
+        int sampleRate,
+        audio_input_flags_t flags,
+        audio_port_handle_t *portId) {
+    audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
+    audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
+    config.sample_rate = sampleRate;
+    config.channel_mask = channelMask;
+    config.format = format;
+    audio_port_handle_t localPortId;
+    if (!portId) portId = &localPortId;
+    *portId = AUDIO_PORT_HANDLE_NONE;
+    AudioPolicyInterface::input_type_t inputType;
+    ASSERT_EQ(OK, mManager->getInputForAttr(
+            &attr, &input, riid, AUDIO_SESSION_NONE, 0 /*uid*/, &config, flags,
+            selectedDeviceId, &inputType, portId));
+    ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+}
+
+void AudioPolicyManagerTest::findDevicePort(audio_port_role_t role,
+        audio_devices_t deviceType, const std::string &address, audio_port &foundPort) {
+    uint32_t numPorts = 0;
+    uint32_t generation1;
+    status_t ret;
+
+    ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, nullptr, &generation1);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    uint32_t generation2;
+    struct audio_port ports[numPorts];
+    ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, ports, &generation2);
+    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_EQ(generation1, generation2);
+
+    for (const auto &port : ports) {
+        if (port.role == role && port.ext.device.type == deviceType &&
+                (strncmp(port.ext.device.address, address.c_str(),
+                         AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+            foundPort = port;
+            return;
+        }
+    }
+    GTEST_FAIL();
+}
+
+audio_port_handle_t AudioPolicyManagerTest::getDeviceIdFromPatch(
+        const struct audio_patch* patch) {
+    // The logic here is the same as the one in AudioIoDescriptor.
+    // Note this function is aim to get routed device id for test.
+    // In that case, device to device patch is not expected here.
+    if (patch->num_sources != 0 && patch->num_sinks != 0) {
+        if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
+            return patch->sinks[0].id;
+        } else {
+            return patch->sources[0].id;
+        }
+    }
+    return AUDIO_PORT_HANDLE_NONE;
+}
+
 
 TEST_F(AudioPolicyManagerTest, InitSuccess) {
     // SetUp must finish with no assertions.
@@ -286,15 +305,17 @@
 
 class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest {
   protected:
-    void SetUpConfig(AudioPolicyConfig *config) override;
+    void SetUpManagerConfig() override;
     void TearDown() override;
 
     sp<DeviceDescriptor> mMsdOutputDevice;
     sp<DeviceDescriptor> mMsdInputDevice;
 };
 
-void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
+void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
     // TODO: Consider using Serializer to load part of the config from a string.
+    AudioPolicyManagerTest::SetUpManagerConfig();
+    AudioPolicyConfig& config = mManager->getConfig();
     mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
     sp<AudioProfile> pcmOutputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
@@ -307,22 +328,21 @@
     sp<AudioProfile> pcmInputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
     mMsdInputDevice->addAudioProfile(pcmInputProfile);
-    config->addAvailableDevice(mMsdOutputDevice);
-    config->addAvailableDevice(mMsdInputDevice);
+    config.addAvailableDevice(mMsdOutputDevice);
+    config.addAvailableDevice(mMsdInputDevice);
 
     sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
-    HwModuleCollection modules = config->getHwModules();
+    HwModuleCollection modules = config.getHwModules();
     modules.add(msdModule);
-    config->setHwModules(modules);
+    config.setHwModules(modules);
     mMsdOutputDevice->attach(msdModule);
     mMsdInputDevice->attach(msdModule);
 
-    sp<OutputProfile> msdOutputProfile = new OutputProfile(String8("msd input"));
+    sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
     msdOutputProfile->addAudioProfile(pcmOutputProfile);
     msdOutputProfile->addSupportedDevice(mMsdOutputDevice);
     msdModule->addOutputProfile(msdOutputProfile);
-    sp<OutputProfile> msdCompressedOutputProfile =
-            new OutputProfile(String8("msd compressed input"));
+    sp<OutputProfile> msdCompressedOutputProfile = new OutputProfile("msd compressed input");
     msdCompressedOutputProfile->addAudioProfile(ac3OutputProfile);
     msdCompressedOutputProfile->setFlags(
             AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
@@ -330,7 +350,7 @@
     msdCompressedOutputProfile->addSupportedDevice(mMsdOutputDevice);
     msdModule->addOutputProfile(msdCompressedOutputProfile);
 
-    sp<InputProfile> msdInputProfile = new InputProfile(String8("msd output"));
+    sp<InputProfile> msdInputProfile = new InputProfile("msd output");
     msdInputProfile->addAudioProfile(pcmInputProfile);
     msdInputProfile->addSupportedDevice(mMsdInputDevice);
     msdModule->addInputProfile(msdInputProfile);
@@ -339,12 +359,12 @@
     // of streams that are not supported by MSD.
     sp<AudioProfile> dtsOutputProfile = new AudioProfile(
             AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000);
-    config->getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
-    sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile(String8("encoded"));
+    config.getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
+    sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile("encoded");
     primaryEncodedOutputProfile->addAudioProfile(dtsOutputProfile);
     primaryEncodedOutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
-    primaryEncodedOutputProfile->addSupportedDevice(config->getDefaultOutputDevice());
-    config->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+    primaryEncodedOutputProfile->addSupportedDevice(config.getDefaultOutputDevice());
+    config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
             addOutputProfile(primaryEncodedOutputProfile);
 }
 
@@ -372,7 +392,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -381,7 +401,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -390,7 +410,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -403,7 +423,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
@@ -414,7 +434,8 @@
     // Switch between formats that are supported and not supported by MSD.
     {
         const PatchCountCheck patchCount = snapshotPatchCount();
-        audio_port_handle_t selectedDeviceId, portId;
+        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+        audio_port_handle_t portId;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                 &portId);
@@ -425,7 +446,8 @@
     }
     {
         const PatchCountCheck patchCount = snapshotPatchCount();
-        audio_port_handle_t selectedDeviceId, portId;
+        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+        audio_port_handle_t portId;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                 &portId);
@@ -436,10 +458,599 @@
     }
     {
         const PatchCountCheck patchCount = snapshotPatchCount();
-        audio_port_handle_t selectedDeviceId;
+        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
         ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
         ASSERT_EQ(0, patchCount.deltaFromSnapshot());
     }
 }
+
+class AudioPolicyManagerTestWithConfigurationFile : public AudioPolicyManagerTest {
+protected:
+    void SetUpManagerConfig() override;
+    virtual std::string getConfigFile() { return sDefaultConfig; }
+
+    static const std::string sExecutableDir;
+    static const std::string sDefaultConfig;
+};
+
+const std::string AudioPolicyManagerTestWithConfigurationFile::sExecutableDir =
+        base::GetExecutableDirectory() + "/";
+
+const std::string AudioPolicyManagerTestWithConfigurationFile::sDefaultConfig =
+        sExecutableDir + "test_audio_policy_configuration.xml";
+
+void AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig() {
+    status_t status = deserializeAudioPolicyFile(getConfigFile().c_str(), &mManager->getConfig());
+    ASSERT_EQ(NO_ERROR, status);
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, Dump) {
+    dumpToLog();
+}
+
+using PolicyMixTuple = std::tuple<audio_usage_t, audio_source_t, uint32_t>;
+
+class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+    void TearDown() override;
+
+    status_t addPolicyMix(int mixType, int mixFlag, audio_devices_t deviceType,
+            std::string mixAddress, const audio_config_t& audioConfig,
+            const std::vector<PolicyMixTuple>& rules);
+    void clearPolicyMix();
+
+    Vector<AudioMix> mAudioMixes;
+    const std::string mMixAddress = "remote_submix_media";
+};
+
+void AudioPolicyManagerTestDynamicPolicy::TearDown() {
+    mManager->unregisterPolicyMixes(mAudioMixes);
+    AudioPolicyManagerTestWithConfigurationFile::TearDown();
+}
+
+status_t AudioPolicyManagerTestDynamicPolicy::addPolicyMix(int mixType, int mixFlag,
+        audio_devices_t deviceType, std::string mixAddress, const audio_config_t& audioConfig,
+        const std::vector<PolicyMixTuple>& rules) {
+    Vector<AudioMixMatchCriterion> myMixMatchCriteria;
+
+    for(const auto &rule: rules) {
+        myMixMatchCriteria.add(AudioMixMatchCriterion(
+                std::get<0>(rule), std::get<1>(rule), std::get<2>(rule)));
+    }
+
+    AudioMix myAudioMix(myMixMatchCriteria, mixType, audioConfig, mixFlag,
+            String8(mixAddress.c_str()), 0);
+    myAudioMix.mDeviceType = deviceType;
+    // Clear mAudioMix before add new one to make sure we don't add already exist mixes.
+    mAudioMixes.clear();
+    mAudioMixes.add(myAudioMix);
+
+    // As the policy mixes registration may fail at some case,
+    // caller need to check the returned status.
+    status_t ret = mManager->registerPolicyMixes(mAudioMixes);
+    return ret;
+}
+
+void AudioPolicyManagerTestDynamicPolicy::clearPolicyMix() {
+    if (mManager != nullptr) {
+        mManager->unregisterPolicyMixes(mAudioMixes);
+    }
+    mAudioMixes.clear();
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, InitSuccess) {
+    // SetUp must finish with no assertions
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, Dump) {
+    dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, RegisterPolicyMixes) {
+    status_t ret;
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+
+    // Only capture of playback is allowed in LOOP_BACK &RENDER mode
+    ret = addPolicyMix(MIX_TYPE_RECORDERS, MIX_ROUTE_FLAG_LOOP_BACK_AND_RENDER,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // Fail due to the device is already connected.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // The first time to register policy mixes with valid parameter should succeed.
+    clearPolicyMix();
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig,
+            std::vector<PolicyMixTuple>());
+    ASSERT_EQ(NO_ERROR, ret);
+    // Registering the same policy mixes should fail.
+    ret = mManager->registerPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // Registration should fail due to device not found.
+    // Note that earpiece is not present in the test configuration file.
+    // This will need to be updated if earpiece is added in the test configuration file.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+            AUDIO_DEVICE_OUT_EARPIECE, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // Registration should fail due to output not found.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // The first time to register valid policy mixes should succeed.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+            AUDIO_DEVICE_OUT_SPEAKER, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(NO_ERROR, ret);
+    // Registering the same policy mixes should fail.
+    ret = mManager->registerPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, UnregisterPolicyMixes) {
+    status_t ret;
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig,
+            std::vector<PolicyMixTuple>());
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // After successfully registering policy mixes, it should be able to unregister.
+    ret = mManager->unregisterPolicyMixes(mAudioMixes);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // After unregistering policy mixes successfully, it should fail unregistering
+    // the same policy mixes as they are not registered.
+    ret = mManager->unregisterPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+class AudioPolicyManagerTestDPNoRemoteSubmixModule : public AudioPolicyManagerTestDynamicPolicy {
+protected:
+    std::string getConfigFile() override { return sPrimaryOnlyConfig; }
+
+    static const std::string sPrimaryOnlyConfig;
+};
+
+const std::string AudioPolicyManagerTestDPNoRemoteSubmixModule::sPrimaryOnlyConfig =
+        sExecutableDir + "test_audio_policy_primary_only_configuration.xml";
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, Dump) {
+    dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, RegistrationFailure) {
+    // Registration/Unregistration should fail due to module for remote submix not found.
+    status_t ret;
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    ret = mManager->unregisterPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+class AudioPolicyManagerTestDPPlaybackReRouting : public AudioPolicyManagerTestDynamicPolicy,
+        public testing::WithParamInterface<audio_attributes_t> {
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    std::unique_ptr<RecordingActivityTracker> mTracker;
+
+    std::vector<PolicyMixTuple> mUsageRules = {
+            {AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, RULE_MATCH_ATTRIBUTE_USAGE},
+            {AUDIO_USAGE_ALARM, AUDIO_SOURCE_DEFAULT, RULE_MATCH_ATTRIBUTE_USAGE}
+    };
+
+    struct audio_port mInjectionPort;
+    audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
+};
+
+void AudioPolicyManagerTestDPPlaybackReRouting::SetUp() {
+    AudioPolicyManagerTestDynamicPolicy::SetUp();
+
+    mTracker.reset(new RecordingActivityTracker());
+
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, mUsageRules);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    struct audio_port extractionPort;
+    findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+            mMixAddress, extractionPort);
+
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
+    audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, 0, ""};
+    std::string tags = "addr=" + mMixAddress;
+    strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+    getInputForAttr(attr, mTracker->getRiid(), &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
+            AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE, &mPortId);
+    ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
+    ASSERT_EQ(extractionPort.id, selectedDeviceId);
+
+    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+            mMixAddress, mInjectionPort);
+}
+
+void AudioPolicyManagerTestDPPlaybackReRouting::TearDown() {
+    mManager->stopInput(mPortId);
+    AudioPolicyManagerTestDynamicPolicy::TearDown();
+}
+
+TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, InitSuccess) {
+    // SetUp must finish with no assertions
+}
+
+TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, Dump) {
+    dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDPPlaybackReRouting, PlaybackReRouting) {
+    const audio_attributes_t attr = GetParam();
+    const audio_usage_t usage = attr.usage;
+
+    audio_port_handle_t playbackRoutedPortId = AUDIO_PORT_HANDLE_NONE;
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+    getOutputForAttr(&playbackRoutedPortId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE, &portId, attr);
+    if (std::find_if(begin(mUsageRules), end(mUsageRules), [&usage](const auto &usageRule) {
+            return (std::get<0>(usageRule) == usage) &&
+            (std::get<2>(usageRule) == RULE_MATCH_ATTRIBUTE_USAGE);}) != end(mUsageRules) ||
+            (strncmp(attr.tags, "addr=", strlen("addr=")) == 0 &&
+                    strncmp(attr.tags + strlen("addr="), mMixAddress.c_str(),
+                    AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0)) {
+        EXPECT_EQ(mInjectionPort.id, playbackRoutedPortId);
+    } else {
+        EXPECT_NE(mInjectionPort.id, playbackRoutedPortId);
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(
+        PlaybackReroutingUsageMatch,
+        AudioPolicyManagerTestDPPlaybackReRouting,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""}
+                )
+        );
+
+INSTANTIATE_TEST_CASE_P(
+        PlaybackReroutingAddressPriorityMatch,
+        AudioPolicyManagerTestDPPlaybackReRouting,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (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"}
+                )
+        );
+
+INSTANTIATE_TEST_CASE_P(
+        PlaybackReroutingUnHandledUsages,
+        AudioPolicyManagerTestDPPlaybackReRouting,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (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, ""}
+                )
+        );
+
+class AudioPolicyManagerTestDPMixRecordInjection : public AudioPolicyManagerTestDynamicPolicy,
+        public testing::WithParamInterface<audio_attributes_t> {
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    std::unique_ptr<RecordingActivityTracker> mTracker;
+
+    std::vector<PolicyMixTuple> mSourceRules = {
+        {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_CAMCORDER, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET},
+        {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_MIC, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET},
+        {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_VOICE_COMMUNICATION, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}
+    };
+
+    struct audio_port mExtractionPort;
+    audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
+};
+
+void AudioPolicyManagerTestDPMixRecordInjection::SetUp() {
+    AudioPolicyManagerTestDynamicPolicy::SetUp();
+
+    mTracker.reset(new RecordingActivityTracker());
+
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+    audioConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    status_t ret = addPolicyMix(MIX_TYPE_RECORDERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_IN_REMOTE_SUBMIX, mMixAddress, audioConfig, mSourceRules);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    struct audio_port injectionPort;
+    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+            mMixAddress, injectionPort);
+
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_usage_t usage = AUDIO_USAGE_VIRTUAL_SOURCE;
+    audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, usage, AUDIO_SOURCE_DEFAULT, 0, ""};
+    std::string tags = std::string("addr=") + mMixAddress;
+    strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+    getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE, &mPortId, attr);
+    ASSERT_EQ(NO_ERROR, mManager->startOutput(mPortId));
+    ASSERT_EQ(injectionPort.id, getDeviceIdFromPatch(mClient->getLastAddedPatch()));
+
+    findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+            mMixAddress, mExtractionPort);
+}
+
+void AudioPolicyManagerTestDPMixRecordInjection::TearDown() {
+    mManager->stopOutput(mPortId);
+    AudioPolicyManagerTestDynamicPolicy::TearDown();
+}
+
+TEST_F(AudioPolicyManagerTestDPMixRecordInjection, InitSuccess) {
+    // SetUp mush finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDPMixRecordInjection, Dump) {
+    dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDPMixRecordInjection, RecordingInjection) {
+    const audio_attributes_t attr = GetParam();
+    const audio_source_t source = attr.source;
+
+    audio_port_handle_t captureRoutedPortId = AUDIO_PORT_HANDLE_NONE;
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+    getInputForAttr(attr, mTracker->getRiid(), &captureRoutedPortId, AUDIO_FORMAT_PCM_16_BIT,
+            AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE, &portId);
+    if (std::find_if(begin(mSourceRules), end(mSourceRules), [&source](const auto &sourceRule) {
+            return (std::get<1>(sourceRule) == source) &&
+            (std::get<2>(sourceRule) == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET);})
+            != end(mSourceRules)) {
+        EXPECT_EQ(mExtractionPort.id, captureRoutedPortId);
+    } else {
+        EXPECT_NE(mExtractionPort.id, captureRoutedPortId);
+    }
+}
+
+// No address priority rule for remote recording, address is a "don't care"
+INSTANTIATE_TEST_CASE_P(
+        RecordInjectionSourceMatch,
+        AudioPolicyManagerTestDPMixRecordInjection,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_CAMCORDER, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_CAMCORDER, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_MIC, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_MIC, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_COMMUNICATION, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_COMMUNICATION, 0,
+                                     "addr=remote_submix_media"}
+                )
+        );
+
+// No address priority rule for remote recording
+INSTANTIATE_TEST_CASE_P(
+        RecordInjectionSourceNotMatch,
+        AudioPolicyManagerTestDPMixRecordInjection,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_RECOGNITION, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_HOTWORD, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_RECOGNITION, 0,
+                                     "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_HOTWORD, 0, "addr=remote_submix_media"}
+                )
+        );
+
+using DeviceConnectionTestParams =
+        std::tuple<audio_devices_t /*type*/, std::string /*name*/, std::string /*address*/>;
+
+class AudioPolicyManagerTestDeviceConnection : public AudioPolicyManagerTestWithConfigurationFile,
+        public testing::WithParamInterface<DeviceConnectionTestParams> {
+};
+
+TEST_F(AudioPolicyManagerTestDeviceConnection, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDeviceConnection, Dump) {
+    dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDeviceConnection, SetDeviceConnectionState) {
+    const audio_devices_t type = std::get<0>(GetParam());
+    const std::string name = std::get<1>(GetParam());
+    const std::string address = std::get<2>(GetParam());
+
+    if (type == AUDIO_DEVICE_OUT_HDMI) {
+        // Set device connection state failed due to no device descriptor found
+        // For HDMI case, it is easier to simulate device descriptor not found error
+        // by using a undeclared encoded format.
+        ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+                type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                address.c_str(), name.c_str(), AUDIO_FORMAT_MAT_2_1));
+    }
+    // Connect with valid parameters should succeed
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Try to connect with the same device again should fail
+    ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Disconnect the connected device should succeed
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Disconnect device that is not connected should fail
+    ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Try to set device connection state  with a invalid connection state should fail
+    ASSERT_EQ(BAD_VALUE, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_CNT,
+            "", "", AUDIO_FORMAT_DEFAULT));
+}
+
+TEST_P(AudioPolicyManagerTestDeviceConnection, ExplicitlyRoutingAfterConnection) {
+    const audio_devices_t type = std::get<0>(GetParam());
+    const std::string name = std::get<1>(GetParam());
+    const std::string address = std::get<2>(GetParam());
+
+    // Connect device to do explicitly routing test
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+
+    audio_port devicePort;
+    const audio_port_role_t role = audio_is_output_device(type)
+            ? AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+    findDevicePort(role, type, address, devicePort);
+
+    audio_port_handle_t routedPortId = devicePort.id;
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+    // Try start input or output according to the device type
+    if (audio_is_output_devices(type)) {
+        getOutputForAttr(&routedPortId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+                48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE, &portId);
+    } else if (audio_is_input_device(type)) {
+        RecordingActivityTracker tracker;
+        getInputForAttr({}, tracker.getRiid(), &routedPortId, AUDIO_FORMAT_PCM_16_BIT,
+                AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE, &portId);
+    }
+    ASSERT_EQ(devicePort.id, routedPortId);
+
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+}
+
+INSTANTIATE_TEST_CASE_P(
+        DeviceConnectionState,
+        AudioPolicyManagerTestDeviceConnection,
+        testing::Values(
+                DeviceConnectionTestParams({AUDIO_DEVICE_IN_HDMI, "test_in_hdmi",
+                                            "audio_policy_test_in_hdmi"}),
+                DeviceConnectionTestParams({AUDIO_DEVICE_OUT_HDMI, "test_out_hdmi",
+                                            "audio_policy_test_out_hdmi"}),
+                DeviceConnectionTestParams({AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "bt_hfp_in",
+                                            "hfp_client_in"}),
+                DeviceConnectionTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "bt_hfp_out",
+                                            "hfp_client_out"})
+                )
+        );
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
new file mode 100644
index 0000000..41f5ee1
--- /dev/null
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -0,0 +1,7 @@
+filegroup {
+    name: "audiopolicytest_configuration_files",
+    srcs: [
+        "test_audio_policy_configuration.xml",
+        "test_audio_policy_primary_only_configuration.xml",
+    ],
+}
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
new file mode 100644
index 0000000..87f0ab9
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <globalConfiguration speaker_drc_enabled="true"/>
+
+    <modules>
+        <!-- Primary module -->
+        <module name="primary" halVersion="2.0">
+            <attachedDevices>
+                <item>Speaker</item>
+                <item>Built-In Mic</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="primary input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000"
+                             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+                <mixPort name="mixport_bt_hfp_output" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="mixport_bt_hfp_input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,16000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_MONO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+                </devicePort>
+                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+                </devicePort>
+                <devicePort tagName="Hdmi" type="AUDIO_DEVICE_OUT_HDMI" role="sink">
+                </devicePort>
+                <devicePort tagName="Hdmi-In Mic" type="AUDIO_DEVICE_IN_HDMI" role="source">
+                </devicePort>
+                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"
+                            role="sink" address="hfp_client_out">
+                </devicePort>
+                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"
+                            role="source" address="hfp_client_in">
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="Speaker"
+                       sources="primary output"/>
+                <route type="mix" sink="primary input"
+                       sources="Built-In Mic,Hdmi-In Mic"/>
+                <route type="mix" sink="Hdmi"
+                       sources="primary output"/>
+                <route type="mix" sink="BT SCO"
+                       sources="mixport_bt_hfp_output"/>
+                <route type="mix" sink="mixport_bt_hfp_input"
+                       sources="BT SCO Headset Mic"/>
+            </routes>
+        </module>
+
+        <!-- Remote Submix module -->
+        <module name="r_submix" halVersion="2.0">
+            <attachedDevices>
+                <item>Remote Submix In</item>
+            </attachedDevices>
+            <mixPorts>
+                <mixPort name="r_submix output" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="r_submix input" role="sink">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+           </mixPorts>
+           <devicePorts>
+               <devicePort tagName="Remote Submix Out" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"  role="sink">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+               </devicePort>
+               <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX"  role="source">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="Remote Submix Out"
+                       sources="r_submix output"/>
+                <route type="mix" sink="r_submix input"
+                       sources="Remote Submix In"/>
+            </routes>
+        </module>
+    </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml
new file mode 100644
index 0000000..edc0adb
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <globalConfiguration speaker_drc_enabled="true"/>
+
+    <modules>
+        <!-- Primary module -->
+        <module name="primary" halVersion="2.0">
+            <attachedDevices>
+                <item>Speaker</item>
+                <item>Built-In Mic</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="primary input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000"
+                             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+                </devicePort>
+                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="Speaker"
+                       sources="primary output"/>
+                <route type="mix" sink="primary input"
+                       sources="Built-In Mic"/>
+            </routes>
+        </module>
+    </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/systemaudio_tests.cpp b/services/audiopolicy/tests/systemaudio_tests.cpp
deleted file mode 100644
index abaae52..0000000
--- a/services/audiopolicy/tests/systemaudio_tests.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-#include <gtest/gtest.h>
-
-#define LOG_TAG "SysAudio_Test"
-#include <log/log.h>
-#include <media/PatchBuilder.h>
-#include <system/audio.h>
-
-using namespace android;
-
-TEST(SystemAudioTest, PatchInvalid) {
-    audio_patch patch{};
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-    patch.num_sources = AUDIO_PATCH_PORTS_MAX + 1;
-    patch.num_sinks = 1;
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-    patch.num_sources = 1;
-    patch.num_sinks = AUDIO_PATCH_PORTS_MAX + 1;
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-    patch.num_sources = 0;
-    patch.num_sinks = 1;
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-}
-
-TEST(SystemAudioTest, PatchValid) {
-    const audio_port_config src = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
-    // It's OK not to have sinks.
-    ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).patch()));
-    const audio_port_config sink = {
-        .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patch_is_valid(
-                    (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patch_is_valid(
-                    (PatchBuilder{}).addSource(src).addSink(sink).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patch_is_valid(
-                    (PatchBuilder{}).addSource(src).addSource(src).
-                    addSink(sink).addSink(sink).patch()));
-}
-
-TEST(SystemAudioTest, PatchHwAvSync) {
-    audio_port_config device_src_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-    device_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-    device_src_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-
-    audio_port_config device_sink_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-    device_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-    device_sink_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-
-    audio_port_config mix_sink_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_MIX };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-    mix_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-    mix_sink_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-
-    audio_port_config mix_src_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_MIX };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-    mix_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-    mix_src_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-}
-
-TEST(SystemAudioTest, PatchEqual) {
-    const audio_patch patch1{}, patch2{};
-    // Invalid patches are not equal.
-    ASSERT_FALSE(audio_patches_are_equal(&patch1, &patch2));
-    const audio_port_config src = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
-    const audio_port_config sink = {
-        .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_FALSE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch()));
-    ASSERT_FALSE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
-                    (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
-    audio_port_config sink_hw_av_sync = sink;
-    sink_hw_av_sync.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    sink_hw_av_sync.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
-    ASSERT_FALSE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
-    ASSERT_TRUE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
-}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c70513c..850b275 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -153,8 +153,6 @@
         mInitialized = true;
     }
 
-    CameraService::pingCameraServiceProxy();
-
     mUidPolicy = new UidPolicy(this);
     mUidPolicy->registerSelf();
     mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
@@ -164,6 +162,11 @@
         ALOGE("%s: Failed to register default android.frameworks.cameraservice.service@1.0",
               __FUNCTION__);
     }
+
+    // This needs to be last call in this function, so that it's as close to
+    // ServiceManager::addService() as possible.
+    CameraService::pingCameraServiceProxy();
+    ALOGI("CameraService pinged cameraservice proxy");
 }
 
 status_t CameraService::enumerateProviders() {
@@ -3271,9 +3274,21 @@
         return;
     }
     bool isHidden = isPublicallyHiddenSecureCamera(cameraId);
+    bool supportsHAL3 = false;
+    // supportsCameraApi also holds mInterfaceMutex, we can't call it in the
+    // HIDL onStatusChanged wrapper call (we'll hold mStatusListenerLock and
+    // mInterfaceMutex together, which can lead to deadlocks)
+    binder::Status sRet =
+            supportsCameraApi(String16(cameraId), hardware::ICameraService::API_VERSION_2,
+                    &supportsHAL3);
+    if (!sRet.isOk()) {
+        ALOGW("%s: Failed to determine if device supports HAL3 %s, supportsCameraApi call failed",
+                __FUNCTION__, cameraId.string());
+        return;
+    }
     // Update the status for this camera state, then send the onStatusChangedCallbacks to each
     // of the listeners with both the mStatusStatus and mStatusListenerLock held
-    state->updateStatus(status, cameraId, rejectSourceStates, [this,&isHidden]
+    state->updateStatus(status, cameraId, rejectSourceStates, [this, &isHidden, &supportsHAL3]
             (const String8& cameraId, StatusInternal status) {
 
             if (status != StatusInternal::ENUMERATING) {
@@ -3295,8 +3310,8 @@
             Mutex::Autolock lock(mStatusListenerLock);
 
             for (auto& listener : mListenerList) {
-                if (!listener.first &&  isHidden) {
-                    ALOGV("Skipping camera discovery callback for system-only camera %s",
+                if (!listener.first &&  (isHidden || !supportsHAL3)) {
+                    ALOGV("Skipping camera discovery callback for system-only / HAL1 camera %s",
                           cameraId.c_str());
                     continue;
                 }
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 3d1235e..d21641c 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -1671,8 +1671,13 @@
                          ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
                          break;
                      }
-
-                     parent->onHeicFormatChanged(format);
+                     // Here format is MediaCodec's internal copy of output format.
+                     // Make a copy since onHeicFormatChanged() might modify it.
+                     sp<AMessage> formatCopy;
+                     if (format != nullptr) {
+                         formatCopy = format->dup();
+                     }
+                     parent->onHeicFormatChanged(formatCopy);
                      break;
                  }
 
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index cb2c324..fdb5657 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -29,6 +29,7 @@
 #include <future>
 #include <inttypes.h>
 #include <hardware/camera_common.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
 #include <functional>
 #include <camera_metadata_hidden.h>
@@ -47,10 +48,6 @@
 using std::literals::chrono_literals::operator""s;
 
 namespace {
-// Hardcoded name for the passthrough HAL implementation, since it can't be discovered via the
-// service manager
-const std::string kLegacyProviderName("legacy/0");
-const std::string kExternalProviderName("external/0");
 const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
 } // anonymous namespace
 
@@ -62,6 +59,19 @@
 CameraProviderManager::~CameraProviderManager() {
 }
 
+hardware::hidl_vec<hardware::hidl_string>
+CameraProviderManager::HardwareServiceInteractionProxy::listServices() {
+    hardware::hidl_vec<hardware::hidl_string> ret;
+    auto manager = hardware::defaultServiceManager1_2();
+    if (manager != nullptr) {
+        manager->listManifestByInterface(provider::V2_4::ICameraProvider::descriptor,
+                [&ret](const hardware::hidl_vec<hardware::hidl_string> &registered) {
+                    ret = registered;
+                });
+    }
+    return ret;
+}
+
 status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,
         ServiceInteractionProxy* proxy) {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -84,9 +94,10 @@
         return INVALID_OPERATION;
     }
 
-    // See if there's a passthrough HAL, but let's not complain if there's not
-    addProviderLocked(kLegacyProviderName, /*expected*/ false);
-    addProviderLocked(kExternalProviderName, /*expected*/ false);
+
+    for (const auto& instance : mServiceProxy->listServices()) {
+        this->addProviderLocked(instance);
+    }
 
     IPCThreadState::self()->flushCommands();
 
@@ -1116,7 +1127,7 @@
     return falseRet;
 }
 
-status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {
+status_t CameraProviderManager::addProviderLocked(const std::string& newProvider) {
     for (const auto& providerInfo : mProviders) {
         if (providerInfo->mProviderName == newProvider) {
             ALOGW("%s: Camera provider HAL with name '%s' already registered", __FUNCTION__,
@@ -1129,13 +1140,9 @@
     interface = mServiceProxy->getService(newProvider);
 
     if (interface == nullptr) {
-        if (expected) {
-            ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
-                    newProvider.c_str());
-            return BAD_VALUE;
-        } else {
-            return OK;
-        }
+        ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
+                newProvider.c_str());
+        return BAD_VALUE;
     }
 
     sp<ProviderInfo> providerInfo = new ProviderInfo(newProvider, this);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index cd283b3..954c0d9 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -78,6 +78,7 @@
                 &notification) = 0;
         virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
                 const std::string &serviceName) = 0;
+        virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
         virtual ~ServiceInteractionProxy() {}
     };
 
@@ -95,6 +96,8 @@
                 const std::string &serviceName) override {
             return hardware::camera::provider::V2_4::ICameraProvider::getService(serviceName);
         }
+
+        virtual hardware::hidl_vec<hardware::hidl_string> listServices() override;
     };
 
     /**
@@ -270,6 +273,7 @@
     bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
 
     bool isPublicallyHiddenSecureCamera(const std::string& id) const;
+
     bool isHiddenPhysicalCamera(const std::string& cameraId) const;
 
     static const float kDepthARTolerance;
@@ -567,7 +571,7 @@
             hardware::hidl_version minVersion = hardware::hidl_version{0,0},
             hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
 
-    status_t addProviderLocked(const std::string& newProvider, bool expected = true);
+    status_t addProviderLocked(const std::string& newProvider);
 
     status_t removeProvider(const std::string& provider);
     sp<StatusListener> getStatusListener() const;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 84c2ec7..3089181 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -139,7 +139,9 @@
     mOutputSlots.clear();
     mConsumerBufferCount.clear();
 
-    mConsumer->consumerDisconnect();
+    if (mConsumer.get() != nullptr) {
+        mConsumer->consumerDisconnect();
+    }
 
     if (mBuffers.size() > 0) {
         SP_LOGW("%zu buffers still being tracked", mBuffers.size());
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 74cfe42..1daa035 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -191,6 +191,14 @@
       _hidl_cb(status, {});
       return Void();
     }
+    cameraStatusAndIds.erase(std::remove_if(cameraStatusAndIds.begin(), cameraStatusAndIds.end(),
+            [this](const hardware::CameraStatus& s) {
+              bool supportsHAL3 = false;
+              binder::Status sRet =
+                            mAidlICameraService->supportsCameraApi(String16(s.cameraId),
+                                    hardware::ICameraService::API_VERSION_2, &supportsHAL3);
+              return !sRet.isOk() || !supportsHAL3;
+            }), cameraStatusAndIds.end());
     hidl_vec<HCameraStatusAndId> hCameraStatusAndIds;
     //Convert cameraStatusAndIds to HIDL and call callback
     convertToHidl(cameraStatusAndIds, &hCameraStatusAndIds);
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index f47e5a5..78d737d 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -205,6 +205,11 @@
         return mTestCameraProvider;
     }
 
+    virtual hardware::hidl_vec<hardware::hidl_string> listServices() override {
+        hardware::hidl_vec<hardware::hidl_string> ret = {"test/0"};
+        return ret;
+    }
+
 };
 
 struct TestStatusListener : public CameraProviderManager::StatusListener {
@@ -231,37 +236,24 @@
             vendorSection);
     serviceProxy.setProvider(provider);
 
+    int numProviders = static_cast<int>(serviceProxy.listServices().size());
+
     res = providerManager->initialize(statusListener, &serviceProxy);
     ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
     // Check that both "legacy" and "external" providers (really the same object) are called
     // once for all the init methods
-    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], 2) <<
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], numProviders) <<
             "Only one call to setCallback per provider expected during init";
-    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], 2) <<
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], numProviders) <<
             "Only one call to getVendorTags per provider expected during init";
-    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED], 2) <<
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED],
+            numProviders) <<
             "Only one call to isSetTorchModeSupported per provider expected during init";
-    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], 2) <<
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], numProviders) <<
             "Only one call to getCameraIdList per provider expected during init";
-    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], 2) <<
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], numProviders) <<
             "Only one call to notifyDeviceState per provider expected during init";
 
-    std::string legacyInstanceName = "legacy/0";
-    std::string externalInstanceName = "external/0";
-    bool gotLegacy = false;
-    bool gotExternal = false;
-    EXPECT_EQ(2u, serviceProxy.mLastRequestedServiceNames.size()) <<
-            "Only two service queries expected to be seen by hardware service manager";
-
-    for (auto& serviceName : serviceProxy.mLastRequestedServiceNames) {
-        if (serviceName == legacyInstanceName) gotLegacy = true;
-        if (serviceName == externalInstanceName) gotExternal = true;
-    }
-    ASSERT_TRUE(gotLegacy) <<
-            "Legacy instance not requested from service manager";
-    ASSERT_TRUE(gotExternal) <<
-            "External instance not requested from service manager";
-
     hardware::hidl_string testProviderFqInterfaceName =
             "android.hardware.camera.provider@2.4::ICameraProvider";
     hardware::hidl_string testProviderInstanceName = "test/0";
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index 17c2e02..fa5bc4a 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -42,7 +42,8 @@
         "libcodec2_soft_opusenc",
         "libcodec2_soft_vp8dec",
         "libcodec2_soft_vp9dec",
-        "libcodec2_soft_av1dec",
+        // "libcodec2_soft_av1dec_aom",  // replaced by the gav1 implementation
+        "libcodec2_soft_av1dec_gav1",
         "libcodec2_soft_vp8enc",
         "libcodec2_soft_vp9enc",
         "libcodec2_soft_rawdec",
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 28bfd3f..bdcd5e4 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -21,8 +21,11 @@
 
 #include <binder/IMediaResourceMonitor.h>
 #include <binder/IServiceManager.h>
+#include <cutils/sched_policy.h>
 #include <dirent.h>
 #include <media/stagefright/ProcessInfo.h>
+#include <mediautils/BatteryNotifier.h>
+#include <mediautils/SchedulingPolicyService.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -31,8 +34,7 @@
 
 #include "ResourceManagerService.h"
 #include "ServiceLog.h"
-#include "mediautils/SchedulingPolicyService.h"
-#include <cutils/sched_policy.h>
+
 namespace android {
 
 namespace {
@@ -69,9 +71,9 @@
     return itemsStr;
 }
 
-static bool hasResourceType(MediaResource::Type type, const Vector<MediaResource>& resources) {
-    for (size_t i = 0; i < resources.size(); ++i) {
-        if (resources[i].mType == type) {
+static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
+    for (auto it = resources.begin(); it != resources.end(); it++) {
+        if (it->second.mType == type) {
             return true;
         }
     }
@@ -101,20 +103,22 @@
 }
 
 static ResourceInfo& getResourceInfoForEdit(
+        uid_t uid,
         int64_t clientId,
         const sp<IResourceManagerClient>& client,
         ResourceInfos& infos) {
-    for (size_t i = 0; i < infos.size(); ++i) {
-        if (infos[i].clientId == clientId) {
-            return infos.editItemAt(i);
-        }
+    ssize_t index = infos.indexOfKey(clientId);
+
+    if (index < 0) {
+        ResourceInfo info;
+        info.uid = uid;
+        info.clientId = clientId;
+        info.client = client;
+
+        index = infos.add(clientId, info);
     }
-    ResourceInfo info;
-    info.clientId = clientId;
-    info.client = client;
-    info.cpuBoost = false;
-    infos.push_back(info);
-    return infos.editItemAt(infos.size() - 1);
+
+    return infos.editValueAt(index);
 }
 
 static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
@@ -181,10 +185,10 @@
             snprintf(buffer, SIZE, "        Name: %s\n", infos[j].client->getName().string());
             result.append(buffer);
 
-            Vector<MediaResource> resources = infos[j].resources;
+            const ResourceList &resources = infos[j].resources;
             result.append("        Resources:\n");
-            for (size_t k = 0; k < resources.size(); ++k) {
-                snprintf(buffer, SIZE, "          %s\n", resources[k].toString().string());
+            for (auto it = resources.begin(); it != resources.end(); it++) {
+                snprintf(buffer, SIZE, "          %s\n", it->second.toString().string());
                 result.append(buffer);
             }
         }
@@ -196,15 +200,45 @@
     return OK;
 }
 
-ResourceManagerService::ResourceManagerService()
-    : ResourceManagerService(new ProcessInfo()) {}
+struct SystemCallbackImpl :
+        public ResourceManagerService::SystemCallbackInterface {
+    SystemCallbackImpl() {}
 
-ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
+    virtual void noteStartVideo(int uid) override {
+        BatteryNotifier::getInstance().noteStartVideo(uid);
+    }
+    virtual void noteStopVideo(int uid) override {
+        BatteryNotifier::getInstance().noteStopVideo(uid);
+    }
+    virtual void noteResetVideo() override {
+        BatteryNotifier::getInstance().noteResetVideo();
+    }
+    virtual bool requestCpusetBoost(
+            bool enable, const sp<IInterface> &client) override {
+        return android::requestCpusetBoost(enable, client);
+    }
+
+protected:
+    virtual ~SystemCallbackImpl() {}
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(SystemCallbackImpl);
+};
+
+ResourceManagerService::ResourceManagerService()
+    : ResourceManagerService(new ProcessInfo(), new SystemCallbackImpl()) {}
+
+ResourceManagerService::ResourceManagerService(
+        const sp<ProcessInfoInterface> &processInfo,
+        const sp<SystemCallbackInterface> &systemResource)
     : mProcessInfo(processInfo),
+      mSystemCB(systemResource),
       mServiceLog(new ServiceLog()),
       mSupportsMultipleSecureCodecs(true),
       mSupportsSecureWithNonSecureCodec(true),
-      mCpuBoostCount(0) {}
+      mCpuBoostCount(0) {
+    mSystemCB->noteResetVideo();
+}
 
 ResourceManagerService::~ResourceManagerService() {}
 
@@ -224,8 +258,41 @@
     }
 }
 
+void ResourceManagerService::onFirstAdded(
+        const MediaResource& resource, const ResourceInfo& clientInfo) {
+    // first time added
+    if (resource.mType == MediaResource::kCpuBoost
+     && resource.mSubType == MediaResource::kUnspecifiedSubType) {
+        // Request it on every new instance of kCpuBoost, as the media.codec
+        // could have died, if we only do it the first time subsequent instances
+        // never gets the boost.
+        if (mSystemCB->requestCpusetBoost(true, this) != OK) {
+            ALOGW("couldn't request cpuset boost");
+        }
+        mCpuBoostCount++;
+    } else if (resource.mType == MediaResource::kBattery
+            && resource.mSubType == MediaResource::kVideoCodec) {
+        mSystemCB->noteStartVideo(clientInfo.uid);
+    }
+}
+
+void ResourceManagerService::onLastRemoved(
+        const MediaResource& resource, const ResourceInfo& clientInfo) {
+    if (resource.mType == MediaResource::kCpuBoost
+            && resource.mSubType == MediaResource::kUnspecifiedSubType
+            && mCpuBoostCount > 0) {
+        if (--mCpuBoostCount == 0) {
+            mSystemCB->requestCpusetBoost(false, this);
+        }
+    } else if (resource.mType == MediaResource::kBattery
+            && resource.mSubType == MediaResource::kVideoCodec) {
+        mSystemCB->noteStopVideo(clientInfo.uid);
+    }
+}
+
 void ResourceManagerService::addResource(
         int pid,
+        int uid,
         int64_t clientId,
         const sp<IResourceManagerClient> client,
         const Vector<MediaResource> &resources) {
@@ -239,20 +306,15 @@
         return;
     }
     ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
-    ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
-    // TODO: do the merge instead of append.
-    info.resources.appendVector(resources);
+    ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
 
     for (size_t i = 0; i < resources.size(); ++i) {
-        if (resources[i].mType == MediaResource::kCpuBoost && !info.cpuBoost) {
-            info.cpuBoost = true;
-            // Request it on every new instance of kCpuBoost, as the media.codec
-            // could have died, if we only do it the first time subsequent instances
-            // never gets the boost.
-            if (requestCpusetBoost(true, this) != OK) {
-                ALOGW("couldn't request cpuset boost");
-            }
-            mCpuBoostCount++;
+        const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+        if (info.resources.find(resType) == info.resources.end()) {
+            onFirstAdded(resources[i], info);
+            info.resources[resType] = resources[i];
+        } else {
+            info.resources[resType].mValue += resources[i].mValue;
         }
     }
     if (info.deathNotifier == nullptr) {
@@ -262,7 +324,48 @@
     notifyResourceGranted(pid, resources);
 }
 
-void ResourceManagerService::removeResource(int pid, int64_t clientId) {
+void ResourceManagerService::removeResource(int pid, int64_t clientId,
+        const Vector<MediaResource> &resources) {
+    String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
+            pid, (long long) clientId, getString(resources).string());
+    mServiceLog->add(log);
+
+    Mutex::Autolock lock(mLock);
+    if (!mProcessInfo->isValidPid(pid)) {
+        ALOGE("Rejected removeResource call with invalid pid.");
+        return;
+    }
+    ssize_t index = mMap.indexOfKey(pid);
+    if (index < 0) {
+        ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
+        return;
+    }
+    ResourceInfos &infos = mMap.editValueAt(index);
+
+    index = infos.indexOfKey(clientId);
+    if (index < 0) {
+        ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
+        return;
+    }
+
+    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);
+        // 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;
+            } else {
+                onLastRemoved(resources[i], info);
+                info.resources.erase(resType);
+            }
+        }
+    }
+}
+
+void ResourceManagerService::removeClient(int pid, int64_t clientId) {
     removeResource(pid, clientId, true);
 }
 
@@ -282,24 +385,22 @@
         ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
         return;
     }
-    bool found = false;
     ResourceInfos &infos = mMap.editValueAt(index);
-    for (size_t j = 0; j < infos.size(); ++j) {
-        if (infos[j].clientId == clientId) {
-            if (infos[j].cpuBoost && mCpuBoostCount > 0) {
-                if (--mCpuBoostCount == 0) {
-                    requestCpusetBoost(false, this);
-                }
-            }
-            IInterface::asBinder(infos[j].client)->unlinkToDeath(infos[j].deathNotifier);
-            j = infos.removeAt(j);
-            found = true;
-            break;
-        }
+
+    index = infos.indexOfKey(clientId);
+    if (index < 0) {
+        ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
+        return;
     }
-    if (!found) {
-        ALOGV("didn't find client");
+
+    const ResourceInfo &info = infos[index];
+    for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
+        onLastRemoved(it->second, info);
     }
+
+    IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);
+
+    infos.removeItemsAt(index);
 }
 
 void ResourceManagerService::getClientForResource_l(
@@ -410,7 +511,7 @@
             ResourceInfos &infos = mMap.editValueAt(i);
             for (size_t j = 0; j < infos.size();) {
                 if (infos[j].client == failedClient) {
-                    j = infos.removeAt(j);
+                    j = infos.removeItemsAt(j);
                     found = true;
                 } else {
                     ++j;
@@ -538,11 +639,12 @@
     uint64_t largestValue = 0;
     const ResourceInfos &infos = mMap.valueAt(index);
     for (size_t i = 0; i < infos.size(); ++i) {
-        Vector<MediaResource> resources = infos[i].resources;
-        for (size_t j = 0; j < resources.size(); ++j) {
-            if (resources[j].mType == type) {
-                if (resources[j].mValue > largestValue) {
-                    largestValue = resources[j].mValue;
+        const ResourceList &resources = infos[i].resources;
+        for (auto it = resources.begin(); it != resources.end(); it++) {
+            const MediaResource &resource = it->second;
+            if (resource.mType == type) {
+                if (resource.mValue > largestValue) {
+                    largestValue = resource.mValue;
                     clientTemp = infos[i].client;
                 }
             }
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 82d2a0b..f086dc3 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -33,15 +33,17 @@
 class ServiceLog;
 struct ProcessInfoInterface;
 
+typedef std::map<std::pair<MediaResource::Type, MediaResource::SubType>, MediaResource> ResourceList;
 struct ResourceInfo {
     int64_t clientId;
+    uid_t uid;
     sp<IResourceManagerClient> client;
     sp<IBinder::DeathRecipient> deathNotifier;
-    Vector<MediaResource> resources;
-    bool cpuBoost;
+    ResourceList resources;
 };
 
-typedef Vector<ResourceInfo> ResourceInfos;
+// TODO: convert these to std::map
+typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
 typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
 
 class ResourceManagerService
@@ -49,23 +51,37 @@
       public BnResourceManagerService
 {
 public:
+    struct SystemCallbackInterface : public RefBase {
+        virtual void noteStartVideo(int uid) = 0;
+        virtual void noteStopVideo(int uid) = 0;
+        virtual void noteResetVideo() = 0;
+        virtual bool requestCpusetBoost(
+                bool enable, const sp<IInterface> &client) = 0;
+    };
+
     static char const *getServiceName() { return "media.resource_manager"; }
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
     ResourceManagerService();
-    explicit ResourceManagerService(sp<ProcessInfoInterface> processInfo);
+    explicit ResourceManagerService(
+            const sp<ProcessInfoInterface> &processInfo,
+            const sp<SystemCallbackInterface> &systemResource);
 
     // IResourceManagerService interface
     virtual void config(const Vector<MediaResourcePolicy> &policies);
 
     virtual void addResource(
             int pid,
+            int uid,
             int64_t clientId,
             const sp<IResourceManagerClient> client,
             const Vector<MediaResource> &resources);
 
-    virtual void removeResource(int pid, int64_t clientId);
+    virtual void removeResource(int pid, int64_t clientId,
+            const Vector<MediaResource> &resources);
+
+    virtual void removeClient(int pid, int64_t clientId);
 
     // Tries to reclaim resource from processes with lower priority than the calling process
     // according to the requested resources.
@@ -107,8 +123,12 @@
     void getClientForResource_l(
         int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients);
 
+    void onFirstAdded(const MediaResource& res, const ResourceInfo& clientInfo);
+    void onLastRemoved(const MediaResource& res, const ResourceInfo& clientInfo);
+
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
+    sp<SystemCallbackInterface> mSystemCB;
     sp<ServiceLog> mServiceLog;
     PidResourceInfosMap mMap;
     bool mSupportsMultipleSecureCodecs;
diff --git a/services/mediaresourcemanager/TEST_MAPPING b/services/mediaresourcemanager/TEST_MAPPING
new file mode 100644
index 0000000..418b159
--- /dev/null
+++ b/services/mediaresourcemanager/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+       "name": "ResourceManagerService_test"
+    },
+    {
+       "name": "ServiceLog_test"
+    }
+  ]
+}
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 70e8833..543c87c 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -2,6 +2,7 @@
 cc_test {
     name: "ResourceManagerService_test",
     srcs: ["ResourceManagerService_test.cpp"],
+    test_suites: ["device-tests"],
     shared_libs: [
         "libbinder",
         "liblog",
@@ -23,6 +24,7 @@
 cc_test {
     name: "ServiceLog_test",
     srcs: ["ServiceLog_test.cpp"],
+    test_suites: ["device-tests"],
     shared_libs: [
         "liblog",
         "libmedia",
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ed0b0ef..ae97ec8 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -52,13 +52,69 @@
     DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
 };
 
+struct TestSystemCallback :
+        public ResourceManagerService::SystemCallbackInterface {
+    TestSystemCallback() :
+        mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
+
+    enum EventType {
+        INVALID          = -1,
+        VIDEO_ON         = 0,
+        VIDEO_OFF        = 1,
+        VIDEO_RESET      = 2,
+        CPUSET_ENABLE    = 3,
+        CPUSET_DISABLE   = 4,
+    };
+
+    struct EventEntry {
+        EventType type;
+        int arg;
+    };
+
+    virtual void noteStartVideo(int uid) override {
+        mLastEvent = {EventType::VIDEO_ON, uid};
+        mEventCount++;
+    }
+
+    virtual void noteStopVideo(int uid) override {
+        mLastEvent = {EventType::VIDEO_OFF, uid};
+        mEventCount++;
+    }
+
+    virtual void noteResetVideo() override {
+        mLastEvent = {EventType::VIDEO_RESET, 0};
+        mEventCount++;
+    }
+
+    virtual bool requestCpusetBoost(
+            bool enable, const sp<IInterface> &/*client*/) override {
+        mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
+        mEventCount++;
+        return true;
+    }
+
+    size_t eventCount() { return mEventCount; }
+    EventType lastEventType() { return mLastEvent.type; }
+    EventEntry lastEvent() { return mLastEvent; }
+
+protected:
+    virtual ~TestSystemCallback() {}
+
+private:
+    EventEntry mLastEvent;
+    size_t mEventCount;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
+};
+
+
 struct TestClient : public BnResourceManagerClient {
     TestClient(int pid, sp<ResourceManagerService> service)
         : mReclaimed(false), mPid(pid), mService(service) {}
 
     virtual bool reclaimResource() {
         sp<IResourceManagerClient> client(this);
-        mService->removeResource(mPid, (int64_t) client.get());
+        mService->removeClient(mPid, (int64_t) client.get());
         mReclaimed = true;
         return true;
     }
@@ -86,16 +142,26 @@
 };
 
 static const int kTestPid1 = 30;
+static const int kTestUid1 = 1010;
+
 static const int kTestPid2 = 20;
+static const int kTestUid2 = 1011;
 
 static const int kLowPriorityPid = 40;
 static const int kMidPriorityPid = 25;
 static const int kHighPriorityPid = 10;
 
+using EventType = TestSystemCallback::EventType;
+using EventEntry = TestSystemCallback::EventEntry;
+bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
+    return lhs.type == rhs.type && lhs.arg == rhs.arg;
+}
+
 class ResourceManagerServiceTest : public ::testing::Test {
 public:
     ResourceManagerServiceTest()
-        : mService(new ResourceManagerService(new TestProcessInfo)),
+        : mSystemCB(new TestSystemCallback()),
+          mService(new ResourceManagerService(new TestProcessInfo, mSystemCB)),
           mTestClient1(new TestClient(kTestPid1, mService)),
           mTestClient2(new TestClient(kTestPid2, mService)),
           mTestClient3(new TestClient(kTestPid2, mService)) {
@@ -103,20 +169,21 @@
 
 protected:
     static bool isEqualResources(const Vector<MediaResource> &resources1,
-            const Vector<MediaResource> &resources2) {
-        if (resources1.size() != resources2.size()) {
-            return false;
-        }
+            const ResourceList &resources2) {
+        // convert resource1 to ResourceList
+        ResourceList r1;
         for (size_t i = 0; i < resources1.size(); ++i) {
-            if (resources1[i] != resources2[i]) {
-                return false;
-            }
+            const auto resType = std::make_pair(resources1[i].mType, resources1[i].mSubType);
+            r1[resType] = resources1[i];
         }
-        return true;
+        return r1 == resources2;
     }
 
-    static void expectEqResourceInfo(const ResourceInfo &info, sp<IResourceManagerClient> client,
+    static void expectEqResourceInfo(const ResourceInfo &info,
+            int uid,
+            sp<IResourceManagerClient> client,
             const Vector<MediaResource> &resources) {
+        EXPECT_EQ(uid, info.uid);
         EXPECT_EQ(client, info.client);
         EXPECT_TRUE(isEqualResources(resources, info.resources));
     }
@@ -153,24 +220,24 @@
         // kTestPid1 mTestClient1
         Vector<MediaResource> resources1;
         resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
-        mService->addResource(kTestPid1, getId(mTestClient1), mTestClient1, resources1);
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
         resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
         Vector<MediaResource> resources11;
         resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
-        mService->addResource(kTestPid1, getId(mTestClient1), mTestClient1, resources11);
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
 
         // kTestPid2 mTestClient2
         Vector<MediaResource> resources2;
         resources2.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
         resources2.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
-        mService->addResource(kTestPid2, getId(mTestClient2), mTestClient2, resources2);
+        mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
 
         // kTestPid2 mTestClient3
         Vector<MediaResource> resources3;
-        mService->addResource(kTestPid2, getId(mTestClient3), mTestClient3, resources3);
+        mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
         resources3.push_back(MediaResource(MediaResource::kSecureCodec, 1));
         resources3.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
-        mService->addResource(kTestPid2, getId(mTestClient3), mTestClient3, resources3);
+        mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
 
         const PidResourceInfosMap &map = mService->mMap;
         EXPECT_EQ(2u, map.size());
@@ -178,14 +245,14 @@
         ASSERT_GE(index1, 0);
         const ResourceInfos &infos1 = map[index1];
         EXPECT_EQ(1u, infos1.size());
-        expectEqResourceInfo(infos1[0], mTestClient1, resources1);
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, resources1);
 
         ssize_t index2 = map.indexOfKey(kTestPid2);
         ASSERT_GE(index2, 0);
         const ResourceInfos &infos2 = map[index2];
         EXPECT_EQ(2u, infos2.size());
-        expectEqResourceInfo(infos2[0], mTestClient2, resources2);
-        expectEqResourceInfo(infos2[1], mTestClient3, resources3);
+        expectEqResourceInfo(infos2.valueFor(getId(mTestClient2)), kTestUid2, mTestClient2, resources2);
+        expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
     }
 
     void testConfig() {
@@ -219,10 +286,84 @@
         EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
     }
 
+    void testCombineResource() {
+        // kTestPid1 mTestClient1
+        Vector<MediaResource> resources1;
+        resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+        Vector<MediaResource> resources11;
+        resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
+
+        const PidResourceInfosMap &map = mService->mMap;
+        EXPECT_EQ(1u, map.size());
+        ssize_t index1 = map.indexOfKey(kTestPid1);
+        ASSERT_GE(index1, 0);
+        const ResourceInfos &infos1 = map[index1];
+        EXPECT_EQ(1u, infos1.size());
+
+        // test adding existing types to combine values
+        resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+        Vector<MediaResource> expected;
+        expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
+        expected.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+        // test adding new types (including types that differs only in subType)
+        resources11.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
+        resources11.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
+
+        expected.clear();
+        expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
+        expected.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
+        expected.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
+        expected.push_back(MediaResource(MediaResource::kGraphicMemory, 500));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+    }
+
     void testRemoveResource() {
+        // kTestPid1 mTestClient1
+        Vector<MediaResource> resources1;
+        resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+        Vector<MediaResource> resources11;
+        resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
+
+        const PidResourceInfosMap &map = mService->mMap;
+        EXPECT_EQ(1u, map.size());
+        ssize_t index1 = map.indexOfKey(kTestPid1);
+        ASSERT_GE(index1, 0);
+        const ResourceInfos &infos1 = map[index1];
+        EXPECT_EQ(1u, infos1.size());
+
+        // test partial removal
+        resources11.editItemAt(0).mValue = 100;
+        mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
+
+        Vector<MediaResource> expected;
+        expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        expected.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+        // test complete removal with overshoot value
+        resources11.editItemAt(0).mValue = 1000;
+        mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
+
+        expected.clear();
+        expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+    }
+
+    void testRemoveClient() {
         addResource();
 
-        mService->removeResource(kTestPid2, getId(mTestClient2));
+        mService->removeClient(kTestPid2, getId(mTestClient2));
 
         const PidResourceInfosMap &map = mService->mMap;
         EXPECT_EQ(2u, map.size());
@@ -231,6 +372,7 @@
         EXPECT_EQ(1u, infos1.size());
         EXPECT_EQ(1u, infos2.size());
         // mTestClient2 has been removed.
+        // (OK to use infos2[0] as there is only 1 entry)
         EXPECT_EQ(mTestClient3, infos2[0].client);
     }
 
@@ -246,6 +388,7 @@
         EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, &clients));
 
         EXPECT_EQ(2u, clients.size());
+        // (OK to require ordering in clients[], as the pid map is sorted)
         EXPECT_EQ(mTestClient3, clients[0]);
         EXPECT_EQ(mTestClient1, clients[1]);
     }
@@ -438,7 +581,7 @@
             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
 
             // clean up client 3 which still left
-            mService->removeResource(kTestPid2, getId(mTestClient3));
+            mService->removeClient(kTestPid2, getId(mTestClient3));
         }
     }
 
@@ -498,6 +641,84 @@
         EXPECT_TRUE(mService->isCallingPriorityHigher_l(99, 100));
     }
 
+    void testBatteryStats() {
+        // reset should always be called when ResourceManagerService is created (restarted)
+        EXPECT_EQ(1u, mSystemCB->eventCount());
+        EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
+
+        // new client request should cause VIDEO_ON
+        Vector<MediaResource> resources1;
+        resources1.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+        EXPECT_EQ(2u, mSystemCB->eventCount());
+        EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid1}), mSystemCB->lastEvent());
+
+        // each client should only cause 1 VIDEO_ON
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+        EXPECT_EQ(2u, mSystemCB->eventCount());
+
+        // new client request should cause VIDEO_ON
+        Vector<MediaResource> resources2;
+        resources2.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 2));
+        mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
+        EXPECT_EQ(3u, mSystemCB->eventCount());
+        EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid2}), mSystemCB->lastEvent());
+
+        // partially remove mTestClient1's request, shouldn't be any VIDEO_OFF
+        mService->removeResource(kTestPid1, getId(mTestClient1), resources1);
+        EXPECT_EQ(3u, mSystemCB->eventCount());
+
+        // remove mTestClient1's request, should be VIDEO_OFF for kTestUid1
+        // (use resource2 to test removing more instances than previously requested)
+        mService->removeResource(kTestPid1, getId(mTestClient1), resources2);
+        EXPECT_EQ(4u, mSystemCB->eventCount());
+        EXPECT_EQ(EventEntry({EventType::VIDEO_OFF, kTestUid1}), mSystemCB->lastEvent());
+
+        // remove mTestClient2, should be VIDEO_OFF for kTestUid2
+        mService->removeClient(kTestPid2, getId(mTestClient2));
+        EXPECT_EQ(5u, mSystemCB->eventCount());
+        EXPECT_EQ(EventEntry({EventType::VIDEO_OFF, kTestUid2}), mSystemCB->lastEvent());
+    }
+
+    void testCpusetBoost() {
+        // reset should always be called when ResourceManagerService is created (restarted)
+        EXPECT_EQ(1u, mSystemCB->eventCount());
+        EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
+
+        // new client request should cause CPUSET_ENABLE
+        Vector<MediaResource> resources1;
+        resources1.push_back(MediaResource(MediaResource::kCpuBoost, 1));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+        EXPECT_EQ(2u, mSystemCB->eventCount());
+        EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
+
+        // each client should only cause 1 CPUSET_ENABLE
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+        EXPECT_EQ(2u, mSystemCB->eventCount());
+
+        // new client request should cause CPUSET_ENABLE
+        Vector<MediaResource> resources2;
+        resources2.push_back(MediaResource(MediaResource::kCpuBoost, 2));
+        mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
+        EXPECT_EQ(3u, mSystemCB->eventCount());
+        EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
+
+        // remove mTestClient2 should not cause CPUSET_DISABLE, mTestClient1 still active
+        mService->removeClient(kTestPid2, getId(mTestClient2));
+        EXPECT_EQ(3u, mSystemCB->eventCount());
+
+        // remove 1 cpuboost from mTestClient1, should not be CPUSET_DISABLE (still 1 left)
+        mService->removeResource(kTestPid1, getId(mTestClient1), resources1);
+        EXPECT_EQ(3u, mSystemCB->eventCount());
+
+        // remove 2 cpuboost from mTestClient1, should be CPUSET_DISABLE
+        // (use resource2 to test removing more than previously requested)
+        mService->removeResource(kTestPid1, getId(mTestClient1), resources2);
+        EXPECT_EQ(4u, mSystemCB->eventCount());
+        EXPECT_EQ(EventType::CPUSET_DISABLE, mSystemCB->lastEventType());
+    }
+
+    sp<TestSystemCallback> mSystemCB;
     sp<ResourceManagerService> mService;
     sp<IResourceManagerClient> mTestClient1;
     sp<IResourceManagerClient> mTestClient2;
@@ -512,10 +733,18 @@
     addResource();
 }
 
+TEST_F(ResourceManagerServiceTest, combineResource) {
+    testCombineResource();
+}
+
 TEST_F(ResourceManagerServiceTest, removeResource) {
     testRemoveResource();
 }
 
+TEST_F(ResourceManagerServiceTest, removeClient) {
+    testRemoveClient();
+}
+
 TEST_F(ResourceManagerServiceTest, reclaimResource) {
     testReclaimResourceSecure();
     testReclaimResourceNonSecure();
@@ -541,4 +770,12 @@
     testIsCallingPriorityHigher();
 }
 
+TEST_F(ResourceManagerServiceTest, testBatteryStats) {
+    testBatteryStats();
+}
+
+TEST_F(ResourceManagerServiceTest, testCpusetBoost) {
+    testCpusetBoost();
+}
+
 } // namespace android
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 8572561..6e14434 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -75,10 +75,10 @@
 
     std::lock_guard<std::mutex> lock(mLock);
     if (mNotificationClients.count(pid) == 0) {
-        sp<NotificationClient> notificationClient = new NotificationClient(pid);
+        sp<IBinder> binder = IInterface::asBinder(client);
+        sp<NotificationClient> notificationClient = new NotificationClient(pid, binder);
         mNotificationClients[pid] = notificationClient;
 
-        sp<IBinder> binder = IInterface::asBinder(client);
         status_t status = binder->linkToDeath(notificationClient);
         ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
         return AAudioConvert_androidToAAudioResult(status);
@@ -113,7 +113,7 @@
     if (notificationClient == 0) {
         // This will get called the first time the audio server registers an internal stream.
         ALOGV("registerClientStream(%d,) unrecognized pid\n", pid);
-        notificationClient = new NotificationClient(pid);
+        notificationClient = new NotificationClient(pid, nullptr);
         mNotificationClients[pid] = notificationClient;
     }
     notificationClient->registerClientStream(serviceStream);
@@ -136,8 +136,8 @@
     return AAUDIO_OK;
 }
 
-AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
-        : mProcessId(pid) {
+AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid, const sp<IBinder>& binder)
+        : mProcessId(pid), mBinder(binder) {
 }
 
 AAudioClientTracker::NotificationClient::~NotificationClient() {
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index accf1a7..00ff467 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -73,7 +73,7 @@
      */
     class NotificationClient : public IBinder::DeathRecipient {
     public:
-        NotificationClient(pid_t pid);
+        NotificationClient(pid_t pid, const android::sp<IBinder>& binder);
         virtual ~NotificationClient();
 
         int32_t getStreamCount();
@@ -91,6 +91,8 @@
         mutable std::mutex                              mLock;
         const pid_t                                     mProcessId;
         std::set<android::sp<AAudioServiceStreamBase>>  mStreams;
+        // hold onto binder to receive death notifications
+        android::sp<IBinder>                            mBinder;
     };
 
     mutable std::mutex                               mLock;
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
index 5e4cd39..96ccebc 100644
--- a/services/oboeservice/Android.mk
+++ b/services/oboeservice/Android.mk
@@ -39,8 +39,6 @@
     TimestampScheduler.cpp \
     AAudioThread.cpp
 
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
 # LOCAL_CFLAGS += -fvisibility=hidden
 LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wall -Werror