Merge "Revert "Add isUidActiveOrForeground() for camera/audio to use."" into rvc-dev
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 8620f36..487b8b0 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -143,6 +143,11 @@
             if (data.dataAvail() > 0) {
                 metadata = new camera_frame_metadata_t;
                 metadata->number_of_faces = data.readInt32();
+                if (metadata->number_of_faces <= 0 ||
+                        metadata->number_of_faces > (int32_t)(INT32_MAX / sizeof(camera_face_t))) {
+                    ALOGE("%s: Too large face count: %d", __FUNCTION__, metadata->number_of_faces);
+                    return BAD_VALUE;
+                }
                 metadata->faces = (camera_face_t *) data.readInplace(
                         sizeof(camera_face_t) * metadata->number_of_faces);
             }
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index a9aae0b..8f51458 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -3,5 +3,5 @@
     user cameraserver
     group audio camera input drmrpc
     ioprio rt 4
-    writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
+    task_profiles CameraServiceCapacity MaxPerformance
     rlimit rtprio 10 10
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index f408b6a..b58ebe2 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -35,6 +35,7 @@
 const char* CameraManagerGlobal::kPhysicalCameraIdKey   = "PhysicalCameraId";
 const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
 const char* CameraManagerGlobal::kContextKey    = "CallbackContext";
+const nsecs_t CameraManagerGlobal::kCallbackDrainTimeout = 5000000; // 5 ms
 Mutex                CameraManagerGlobal::sLock;
 CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
 
@@ -117,7 +118,7 @@
                 return nullptr;
             }
             if (mHandler == nullptr) {
-                mHandler = new CallbackHandler();
+                mHandler = new CallbackHandler(this);
             }
             mCbLooper->registerHandler(mHandler);
         }
@@ -211,6 +212,9 @@
 void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
         const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
     Mutex::Autolock _l(mLock);
+
+    drainPendingCallbacksLocked();
+
     Callback cb(callback);
     mCallbacks.erase(cb);
 }
@@ -223,10 +227,32 @@
 void CameraManagerGlobal::unregisterAvailabilityCallback(
         const ACameraManager_AvailabilityCallbacks *callback) {
     Mutex::Autolock _l(mLock);
+
+    drainPendingCallbacksLocked();
+
     Callback cb(callback);
     mCallbacks.erase(cb);
 }
 
+void CameraManagerGlobal::onCallbackCalled() {
+    Mutex::Autolock _l(mLock);
+    if (mPendingCallbackCnt > 0) {
+        mPendingCallbackCnt--;
+    }
+    mCallbacksCond.signal();
+}
+
+void CameraManagerGlobal::drainPendingCallbacksLocked() {
+    while (mPendingCallbackCnt > 0) {
+        auto res = mCallbacksCond.waitRelative(mLock, kCallbackDrainTimeout);
+        if (res != NO_ERROR) {
+            ALOGE("%s: Error waiting to drain callbacks: %s(%d)",
+                    __FUNCTION__, strerror(-res), res);
+            break;
+        }
+    }
+}
+
 template<class T>
 void CameraManagerGlobal::registerAvailCallback(const T *callback) {
     Mutex::Autolock _l(mLock);
@@ -250,6 +276,7 @@
             msg->setPointer(kCallbackFpKey, (void *) cbFunc);
             msg->setPointer(kContextKey, cb.mContext);
             msg->setString(kCameraIdKey, AString(cameraId));
+            mPendingCallbackCnt++;
             msg->post();
 
             // Physical camera unavailable callback
@@ -263,6 +290,7 @@
                 msg->setPointer(kContextKey, cb.mContext);
                 msg->setString(kCameraIdKey, AString(cameraId));
                 msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId));
+                mPendingCallbackCnt++;
                 msg->post();
             }
         }
@@ -323,6 +351,16 @@
 }
 
 void CameraManagerGlobal::CallbackHandler::onMessageReceived(
+      const sp<AMessage> &msg) {
+    onMessageReceivedInternal(msg);
+    if (msg->what() == kWhatSendSingleCallback ||
+            msg->what() == kWhatSendSingleAccessCallback ||
+            msg->what() == kWhatSendSinglePhysicalCameraCallback) {
+        notifyParent();
+    }
+}
+
+void CameraManagerGlobal::CallbackHandler::onMessageReceivedInternal(
         const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatSendSingleCallback:
@@ -405,6 +443,13 @@
     }
 }
 
+void CameraManagerGlobal::CallbackHandler::notifyParent() {
+    sp<CameraManagerGlobal> parent = mParent.promote();
+    if (parent != nullptr) {
+        parent->onCallbackCalled();
+    }
+}
+
 binder::Status CameraManagerGlobal::CameraServiceListener::onCameraAccessPrioritiesChanged() {
     sp<CameraManagerGlobal> cm = mCameraManager.promote();
     if (cm != nullptr) {
@@ -445,6 +490,7 @@
         if (cbFp != nullptr) {
             msg->setPointer(kCallbackFpKey, (void *) cbFp);
             msg->setPointer(kContextKey, cb.mContext);
+            mPendingCallbackCnt++;
             msg->post();
         }
     }
@@ -491,6 +537,7 @@
             msg->setPointer(kCallbackFpKey, (void *) cbFp);
             msg->setPointer(kContextKey, cb.mContext);
             msg->setString(kCameraIdKey, AString(cameraId));
+            mPendingCallbackCnt++;
             msg->post();
         }
     }
@@ -545,6 +592,7 @@
             msg->setPointer(kContextKey, cb.mContext);
             msg->setString(kCameraIdKey, AString(cameraId));
             msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId));
+            mPendingCallbackCnt++;
             msg->post();
         }
     }
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index 7fba188..ccbfaa9 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -163,6 +163,12 @@
         ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamUnavailable;
         void*                               mContext;
     };
+
+    android::Condition mCallbacksCond;
+    size_t mPendingCallbackCnt = 0;
+    void onCallbackCalled();
+    void drainPendingCallbacksLocked();
+
     std::set<Callback> mCallbacks;
 
     // definition of handler and message
@@ -175,10 +181,16 @@
     static const char* kPhysicalCameraIdKey;
     static const char* kCallbackFpKey;
     static const char* kContextKey;
+    static const nsecs_t kCallbackDrainTimeout;
     class CallbackHandler : public AHandler {
       public:
-        CallbackHandler() {}
+        CallbackHandler(wp<CameraManagerGlobal> parent) : mParent(parent) {}
         void onMessageReceived(const sp<AMessage> &msg) override;
+
+      private:
+        wp<CameraManagerGlobal> mParent;
+        void notifyParent();
+        void onMessageReceivedInternal(const sp<AMessage> &msg);
     };
     sp<CallbackHandler> mHandler;
     sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
diff --git a/camera/ndk/include/camera/NdkCameraManager.h b/camera/ndk/include/camera/NdkCameraManager.h
index e2b71bf..0a2ee57 100644
--- a/camera/ndk/include/camera/NdkCameraManager.h
+++ b/camera/ndk/include/camera/NdkCameraManager.h
@@ -191,6 +191,9 @@
  *
  * <p>Removing a callback that isn't registered has no effect.</p>
  *
+ * <p>This function must not be called with a mutex lock also held by
+ * the availability callbacks.</p>
+ *
  * @param manager the {@link ACameraManager} of interest.
  * @param callback the {@link ACameraManager_AvailabilityCallbacks} to be unregistered.
  *
@@ -382,6 +385,9 @@
  *
  * <p>Removing a callback that isn't registered has no effect.</p>
  *
+ * <p>This function must not be called with a mutex lock also held by
+ * the extended availability callbacks.</p>
+ *
  * @param manager the {@link ACameraManager} of interest.
  * @param callback the {@link ACameraManager_ExtendedAvailabilityCallbacks} to be unregistered.
  *
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 4f9b0d1..16457ac 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -1895,27 +1895,66 @@
      * ACAMERA_SCALER_CROP_REGION can still be used to specify the horizontal or vertical
      * crop to achieve aspect ratios different than the native camera sensor.</p>
      * <p>By using this control, the application gains a simpler way to control zoom, which can
-     * be a combination of optical and digital zoom. More specifically, for a logical
-     * multi-camera with more than one focal length, using a floating point zoom ratio offers
-     * more zoom precision when a telephoto lens is used, as well as allowing zoom ratio of
-     * less than 1.0 to zoom out to a wide field of view.</p>
-     * <p>Note that the coordinate system of cropRegion, AE/AWB/AF regions, and faces now changes
-     * to the effective after-zoom field-of-view represented by rectangle of (0, 0,
-     * activeArrayWidth, activeArrayHeight).</p>
-     * <p>For example, if ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE is 4032*3024, and the preview stream
-     * is configured to the same 4:3 aspect ratio, the application can achieve 2.0x zoom in
-     * one of two ways:</p>
+     * be a combination of optical and digital zoom. For example, a multi-camera system may
+     * contain more than one lens with different focal lengths, and the user can use optical
+     * zoom by switching between lenses. Using zoomRatio has benefits in the scenarios below:
+     * <em> Zooming in from a wide-angle lens to a telephoto lens: A floating-point ratio provides
+     *   better precision compared to an integer value of ACAMERA_SCALER_CROP_REGION.
+     * </em> Zooming out from a wide lens to an ultrawide lens: zoomRatio supports zoom-out whereas
+     *   ACAMERA_SCALER_CROP_REGION doesn't.</p>
+     * <p>To illustrate, here are several scenarios of different zoom ratios, crop regions,
+     * and output streams, for a hypothetical camera device with an active array of size
+     * <code>(2000,1500)</code>.</p>
      * <ul>
-     * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 4032, 3024)</li>
-     * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (1008, 756, 3024, 2268)</li>
+     * <li>Camera Configuration:<ul>
+     * <li>Active array size: <code>2000x1500</code> (3 MP, 4:3 aspect ratio)</li>
+     * <li>Output stream #1: <code>640x480</code> (VGA, 4:3 aspect ratio)</li>
+     * <li>Output stream #2: <code>1280x720</code> (720p, 16:9 aspect ratio)</li>
      * </ul>
-     * <p>If the application intends to set aeRegions to be top-left quarter of the preview
-     * field-of-view, the ACAMERA_CONTROL_AE_REGIONS should be set to (0, 0, 2016, 1512) with
+     * </li>
+     * <li>Case #1: 4:3 crop region with 2.0x zoom ratio<ul>
+     * <li>Zoomed field of view: 1/4 of original field of view</li>
+     * <li>Crop region: <code>Rect(0, 0, 2000, 1500) // (left, top, right, bottom)</code> (post zoom)</li>
+     * </ul>
+     * </li>
+     * <li><img alt="4:3 aspect ratio crop diagram" src="../images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-43.png" /><ul>
+     * <li><code>640x480</code> stream source area: <code>(0, 0, 2000, 1500)</code> (equal to crop region)</li>
+     * <li><code>1280x720</code> stream source area: <code>(0, 187, 2000, 1312)</code> (letterboxed)</li>
+     * </ul>
+     * </li>
+     * <li>Case #2: 16:9 crop region with 2.0x zoom.<ul>
+     * <li>Zoomed field of view: 1/4 of original field of view</li>
+     * <li>Crop region: <code>Rect(0, 187, 2000, 1312)</code></li>
+     * <li><img alt="16:9 aspect ratio crop diagram" src="../images/camera2/metadata/android.control.zoomRatio/zoom-ratio-2-crop-169.png" /></li>
+     * <li><code>640x480</code> stream source area: <code>(250, 187, 1750, 1312)</code> (pillarboxed)</li>
+     * <li><code>1280x720</code> stream source area: <code>(0, 187, 2000, 1312)</code> (equal to crop region)</li>
+     * </ul>
+     * </li>
+     * <li>Case #3: 1:1 crop region with 0.5x zoom out to ultrawide lens.<ul>
+     * <li>Zoomed field of view: 4x of original field of view (switched from wide lens to ultrawide lens)</li>
+     * <li>Crop region: <code>Rect(250, 0, 1750, 1500)</code></li>
+     * <li><img alt="1:1 aspect ratio crop diagram" src="../images/camera2/metadata/android.control.zoomRatio/zoom-ratio-0.5-crop-11.png" /></li>
+     * <li><code>640x480</code> stream source area: <code>(250, 187, 1750, 1312)</code> (letterboxed)</li>
+     * <li><code>1280x720</code> stream source area: <code>(250, 328, 1750, 1172)</code> (letterboxed)</li>
+     * </ul>
+     * </li>
+     * </ul>
+     * <p>As seen from the graphs above, the coordinate system of cropRegion now changes to the
+     * effective after-zoom field-of-view, and is represented by the rectangle of (0, 0,
+     * activeArrayWith, activeArrayHeight). The same applies to AE/AWB/AF regions, and faces.
+     * This coordinate system change isn't applicable to RAW capture and its related
+     * metadata such as intrinsicCalibration and lensShadingMap.</p>
+     * <p>Using the same hypothetical example above, and assuming output stream #1 (640x480) is
+     * the viewfinder stream, the application can achieve 2.0x zoom in one of two ways:</p>
+     * <ul>
+     * <li>zoomRatio = 2.0, scaler.cropRegion = (0, 0, 2000, 1500)</li>
+     * <li>zoomRatio = 1.0 (default), scaler.cropRegion = (500, 375, 1500, 1125)</li>
+     * </ul>
+     * <p>If the application intends to set aeRegions to be top-left quarter of the viewfinder
+     * field-of-view, the ACAMERA_CONTROL_AE_REGIONS should be set to (0, 0, 1000, 750) with
      * zoomRatio set to 2.0. Alternatively, the application can set aeRegions to the equivalent
-     * region of (1008, 756, 2016, 1512) for zoomRatio of 1.0. If the application doesn't
+     * region of (500, 375, 1000, 750) for zoomRatio of 1.0. If the application doesn't
      * explicitly set ACAMERA_CONTROL_ZOOM_RATIO, its value defaults to 1.0.</p>
-     * <p>This coordinate system change isn't applicable to RAW capture and its related metadata
-     * such as intrinsicCalibration and lensShadingMap.</p>
      * <p>One limitation of controlling zoom using zoomRatio is that the ACAMERA_SCALER_CROP_REGION
      * must only be used for letterboxing or pillarboxing of the sensor active array, and no
      * FREEFORM cropping can be used with ACAMERA_CONTROL_ZOOM_RATIO other than 1.0.</p>
@@ -1923,7 +1962,6 @@
      * @see ACAMERA_CONTROL_AE_REGIONS
      * @see ACAMERA_CONTROL_ZOOM_RATIO
      * @see ACAMERA_SCALER_CROP_REGION
-     * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
      */
     ACAMERA_CONTROL_ZOOM_RATIO =                                // float
             ACAMERA_CONTROL_START + 47,
@@ -2395,8 +2433,11 @@
      * frames before the lens can change to the requested focal length.
      * While the focal length is still changing, ACAMERA_LENS_STATE will
      * be set to MOVING.</p>
-     * <p>Optical zoom will not be supported on most devices.</p>
+     * <p>Optical zoom via this control will not be supported on most devices. Starting from API
+     * level 30, the camera device may combine optical and digital zoom through the
+     * ACAMERA_CONTROL_ZOOM_RATIO control.</p>
      *
+     * @see ACAMERA_CONTROL_ZOOM_RATIO
      * @see ACAMERA_LENS_APERTURE
      * @see ACAMERA_LENS_FOCUS_DISTANCE
      * @see ACAMERA_LENS_STATE
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index e2097b5..5aa9c46 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -45,6 +45,7 @@
 const char* CameraManagerGlobal::kPhysicalCameraIdKey   = "PhysicalCameraId";
 const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
 const char* CameraManagerGlobal::kContextKey    = "CallbackContext";
+const nsecs_t CameraManagerGlobal::kCallbackDrainTimeout = 5000000; // 5 ms
 Mutex                CameraManagerGlobal::sLock;
 CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
 
@@ -249,7 +250,7 @@
                 return nullptr;
             }
             if (mHandler == nullptr) {
-                mHandler = new CallbackHandler();
+                mHandler = new CallbackHandler(this);
             }
             mCbLooper->registerHandler(mHandler);
         }
@@ -317,6 +318,7 @@
 void CameraManagerGlobal::unregisterAvailabilityCallback(
         const ACameraManager_AvailabilityCallbacks *callback) {
     Mutex::Autolock _l(mLock);
+    drainPendingCallbacksLocked();
     Callback cb(callback);
     mCallbacks.erase(cb);
 }
@@ -329,10 +331,30 @@
 void CameraManagerGlobal::unregisterExtendedAvailabilityCallback(
         const ACameraManager_ExtendedAvailabilityCallbacks *callback) {
     Mutex::Autolock _l(mLock);
+    drainPendingCallbacksLocked();
     Callback cb(callback);
     mCallbacks.erase(cb);
 }
 
+void CameraManagerGlobal::onCallbackCalled() {
+    Mutex::Autolock _l(mLock);
+    if (mPendingCallbackCnt > 0) {
+        mPendingCallbackCnt--;
+    }
+    mCallbacksCond.signal();
+}
+
+void CameraManagerGlobal::drainPendingCallbacksLocked() {
+    while (mPendingCallbackCnt > 0) {
+        auto res = mCallbacksCond.waitRelative(mLock, kCallbackDrainTimeout);
+        if (res != NO_ERROR) {
+            ALOGE("%s: Error waiting to drain callbacks: %s(%d)",
+                    __FUNCTION__, strerror(-res), res);
+            break;
+        }
+    }
+}
+
 template <class T>
 void CameraManagerGlobal::registerAvailCallback(const T *callback) {
     Mutex::Autolock _l(mLock);
@@ -351,6 +373,7 @@
             msg->setPointer(kCallbackFpKey, (void *) cbFunc);
             msg->setPointer(kContextKey, cb.mContext);
             msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+            mPendingCallbackCnt++;
             msg->post();
 
             // Physical camera unavailable callback
@@ -363,6 +386,7 @@
                 msg->setPointer(kContextKey, cb.mContext);
                 msg->setString(kCameraIdKey, AString(cameraId.c_str()));
                 msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
+                mPendingCallbackCnt++;
                 msg->post();
             }
         }
@@ -406,6 +430,15 @@
 }
 
 void CameraManagerGlobal::CallbackHandler::onMessageReceived(
+      const sp<AMessage> &msg) {
+    onMessageReceivedInternal(msg);
+    if (msg->what() == kWhatSendSingleCallback ||
+            msg->what() == kWhatSendSinglePhysicalCameraCallback) {
+        notifyParent();
+    }
+}
+
+void CameraManagerGlobal::CallbackHandler::onMessageReceivedInternal(
         const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatSendSingleCallback:
@@ -466,6 +499,13 @@
     }
 }
 
+void CameraManagerGlobal::CallbackHandler::notifyParent() {
+    sp<CameraManagerGlobal> parent = mParent.promote();
+    if (parent != nullptr) {
+        parent->onCallbackCalled();
+    }
+}
+
 hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onStatusChanged(
         const CameraStatusAndId &statusAndId) {
     sp<CameraManagerGlobal> cm = mCameraManager.promote();
@@ -512,6 +552,7 @@
         msg->setPointer(kCallbackFpKey, (void *) cbFp);
         msg->setPointer(kContextKey, cb.mContext);
         msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+        mPendingCallbackCnt++;
         msg->post();
     }
     if (status == CameraDeviceStatus::STATUS_NOT_PRESENT) {
@@ -577,6 +618,7 @@
             msg->setPointer(kContextKey, cb.mContext);
             msg->setString(kCameraIdKey, AString(cameraId.c_str()));
             msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
+            mPendingCallbackCnt++;
             msg->post();
         }
     }
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 36c8e2b..85da3e9 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -156,6 +156,12 @@
         ACameraManager_PhysicalCameraAvailabilityCallback mPhysicalCamUnavailable;
         void*                               mContext;
     };
+
+    android::Condition mCallbacksCond;
+    size_t mPendingCallbackCnt = 0;
+    void onCallbackCalled();
+    void drainPendingCallbacksLocked();
+
     std::set<Callback> mCallbacks;
 
     // definition of handler and message
@@ -167,10 +173,15 @@
     static const char* kPhysicalCameraIdKey;
     static const char* kCallbackFpKey;
     static const char* kContextKey;
+    static const nsecs_t kCallbackDrainTimeout;
     class CallbackHandler : public AHandler {
       public:
-        CallbackHandler() {}
+        CallbackHandler(wp<CameraManagerGlobal> parent) : mParent(parent) {}
         void onMessageReceived(const sp<AMessage> &msg) override;
+      private:
+        wp<CameraManagerGlobal> mParent;
+        void notifyParent();
+        void onMessageReceivedInternal(const sp<AMessage> &msg);
     };
     sp<CallbackHandler> mHandler;
     sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp
index f427834..b68e6c2 100644
--- a/drm/drmserver/Android.bp
+++ b/drm/drmserver/Android.bp
@@ -24,8 +24,8 @@
     ],
 
     shared_libs: [
-        "libmedia",
         "libmediametrics",
+        "libmediautils",
         "libcutils",
         "libutils",
         "liblog",
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 4b8b3f6..c830c6e 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -19,7 +19,7 @@
 #include <utils/Log.h>
 
 #include <private/android_filesystem_config.h>
-#include <media/MemoryLeakTrackUtil.h>
+#include <mediautils/MemoryLeakTrackUtil.h>
 
 #include <errno.h>
 #include <utils/threads.h>
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index 51c2e24..d85fa61 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -27,7 +27,7 @@
 #include <android/hardware/drm/1.2/IDrmFactory.h>
 #include <android/hardware/drm/1.3/ICryptoFactory.h>
 #include <android/hardware/drm/1.3/IDrmFactory.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/HidlSupport.h>
 
 #include <utils/Errors.h>
@@ -41,7 +41,7 @@
 #include <mediadrm/ICrypto.h>
 #include <mediadrm/IDrm.h>
 
-using HServiceManager = ::android::hidl::manager::V1_0::IServiceManager;
+using HServiceManager = ::android::hidl::manager::V1_2::IServiceManager;
 using ::android::hardware::hidl_array;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
@@ -72,7 +72,7 @@
         exit(-1);
     }
 
-    serviceManager->listByInterface(Hal::descriptor, [&](const hidl_vec<hidl_string> &registered) {
+    serviceManager->listManifestByInterface(Hal::descriptor, [&](const hidl_vec<hidl_string> &registered) {
         for (const auto &instance : registered) {
             auto factory = Hal::getService(instance);
             if (factory != nullptr) {
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
index ccc73b6..1ce8269 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmFactory.cpp
@@ -91,6 +91,19 @@
     return Void();
 }
 
+Return<void> DrmFactory::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    FILE* out = fdopen(dup(fd->data[0]), "w");
+    uint32_t currentSessions = SessionLibrary::get()->numOpenSessions();
+    fprintf(out, "current open sessions: %u\n", currentSessions);
+    fclose(out);
+    return Void();
+}
+
 } // namespace clearkey
 } // namespace V1_3
 } // namespace drm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 546eb3e..f87f830 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -139,8 +139,13 @@
     std::vector<uint8_t> sessionId = session->sessionId();
 
     Status status = setSecurityLevel(sessionId, securityLevel);
+    if (status == Status::OK) {
+        mOpenSessionOkCount++;
+    } else {
+        mSessionLibrary->destroySession(session);
+        sessionId.clear();
+    }
     _hidl_cb(status, toHidlVec(sessionId));
-    mOpenSessionOkCount++;
     return Void();
 }
 
@@ -151,12 +156,12 @@
 
     sp<Session> session = mSessionLibrary->findSession(toVector(sessionId));
     if (session.get()) {
+        mSessionLibrary->destroySession(session);
         if (session->getMockError() != Status_V1_2::OK) {
             sendSessionLostState(sessionId);
             return Status::ERROR_DRM_INVALID_STATE;
         }
         mCloseSessionOkCount++;
-        mSessionLibrary->destroySession(session);
         return Status::OK;
     }
     mCloseSessionNotOpenedCount++;
@@ -356,6 +361,11 @@
 
     Status status = Status::OK;
     bool isOfflineLicense = responseString.find(kOfflineLicense) != std::string::npos;
+    if (scopeId.size() < kKeySetIdPrefix.size()) {
+        android_errorWriteLog(0x534e4554, "144507096");
+        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>());
+        return Void();
+    }
     bool isRelease = (memcmp(scopeId.data(), kKeySetIdPrefix.data(), kKeySetIdPrefix.size()) == 0);
     if (isRelease) {
         keySetId.assign(scopeId.begin(), scopeId.end());
@@ -382,6 +392,7 @@
         if (isOfflineLicense) {
             if (isRelease) {
                 mFileHandle.DeleteLicense(keySetId);
+                mSessionLibrary->destroySession(session);
             } else {
                 if (!makeKeySetId(&keySetId)) {
                     _hidl_cb(Status::ERROR_DRM_UNKNOWN, hidl_vec<uint8_t>());
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
index 403a8ec..63234cf 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmFactory.h
@@ -30,6 +30,7 @@
 
 using ::android::hardware::drm::V1_1::SecurityLevel;
 using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::Return;
 
@@ -55,6 +56,8 @@
     Return<void> getSupportedCryptoSchemes(
             getSupportedCryptoSchemes_cb _hidl_cb) override;
 
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args);
+
 private:
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN(DrmFactory);
 };
diff --git a/include/media/MmapStreamInterface.h b/include/media/MmapStreamInterface.h
index 0196a0c..b3bf16d 100644
--- a/include/media/MmapStreamInterface.h
+++ b/include/media/MmapStreamInterface.h
@@ -107,12 +107,15 @@
      * createMmapBuffer() must be called before calling start()
      *
      * \param[in] client a AudioClient struct describing the client starting on this stream.
+     * \param[in] attr audio attributes provided by the client.
      * \param[out] handle unique handle for this instance. Used with stop().
      * \return OK in case of success.
      *         NO_INIT in case of initialization error
      *         INVALID_OPERATION if called out of sequence
      */
-    virtual status_t start(const AudioClient& client, audio_port_handle_t *handle) = 0;
+    virtual status_t start(const AudioClient& client,
+                           const audio_attributes_t *attr,
+                           audio_port_handle_t *handle) = 0;
 
     /**
      * Stop a stream operating in mmap mode.
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 79afd6c..fe519bb 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -132,7 +132,7 @@
             , mDurationMs(1000.) {
         }
 
-        explicit Configuration(const Configuration &configuration)
+        Configuration(const Configuration &configuration)
             : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
             , RefBase()
             , mType(configuration.mType)
@@ -361,7 +361,7 @@
             : Operation(flags, replaceId, std::numeric_limits<S>::quiet_NaN() /* xOffset */) {
         }
 
-        explicit Operation(const Operation &operation)
+        Operation(const Operation &operation)
             : Operation(operation.mFlags, operation.mReplaceId, operation.mXOffset) {
         }
 
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 8aec80d..9cabd8b 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -614,6 +614,8 @@
     // and thus which resulted in an underrun.
     virtual uint32_t    getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
 
+    virtual uint32_t    getUnderrunCount() const { return mCblk->u.mStreaming.mUnderrunCount; }
+
     // Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
     AudioPlaybackRate getPlaybackRate();
 
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
new file mode 100644
index 0000000..a6dfb21
--- /dev/null
+++ b/media/TEST_MAPPING
@@ -0,0 +1,32 @@
+{
+  "presubmit": [
+    {
+      "name": "GtsMediaTestCases",
+      "options" : [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+        }
+      ]
+    },
+    {
+      "name": "GtsExoPlayerTestCases",
+      "options" : [
+        {
+          "include-annotation": "android.platform.test.annotations.SocPresubmit"
+        },
+        {
+          "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+        }
+      ]
+    }
+  ],
+  "imports": [
+    {
+      "path": "frameworks/av/drm/mediadrm/plugins"
+    }
+  ]
+}
+
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index f44f0d5..cf1c14c 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -39,7 +39,7 @@
 	frameworks/av/media/libaaudio/include \
 	frameworks/av/media/libaaudio/src \
 	frameworks/av/media/libaaudio/src/binding \
-	frameworks/av/media/libmedia \
+	frameworks/av/media/libmedia/include \
 	external/sonic \
 
 LOCAL_MODULE := audioserver
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 5484613..6cb0c73 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -5,17 +5,37 @@
     group audio camera drmrpc media mediadrm net_bt net_bt_admin net_bw_acct wakelock
     capabilities BLOCK_SUSPEND
     ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
-    onrestart restart vendor.audio-hal
-    onrestart restart vendor.audio-hal-4-0-msd
-    # Keep the original service names for backward compatibility
-    onrestart restart vendor.audio-hal-2-0
-    onrestart restart audio-hal-2-0
+    task_profiles ProcessCapacityHigh HighPerformance
+
+    onrestart setprop sys.audio.restart.hal 1
 
 on property:vts.native_server.on=1
     stop audioserver
 on property:vts.native_server.on=0
     start audioserver
 
+on property:init.svc.audioserver=stopped
+    stop vendor.audio-hal
+    stop vendor.audio-hal-4-0-msd
+    # Keep the original service names for backward compatibility
+    stop vendor.audio-hal-2-0
+    stop audio-hal-2-0
+
+on property:init.svc.audioserver=running
+    start vendor.audio-hal
+    start vendor.audio-hal-4-0-msd
+    # Keep the original service names for backward compatibility
+    start vendor.audio-hal-2-0
+    start audio-hal-2-0
+
+on property:sys.audio.restart.hal=1
+    restart vendor.audio-hal
+    restart vendor.audio-hal-4-0-msd
+    # Keep the original service names for backward compatibility
+    restart vendor.audio-hal-2-0
+    restart audio-hal-2-0
+    # reset the property
+    setprop sys.audio.restart.hal 0
+
 on init
     mkdir /dev/socket/audioserver 0775 audioserver audioserver
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index 4a2ac1d..f9f4f31 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -26,6 +26,7 @@
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
 #include <hidl/HidlTransportSupport.h>
+#include <mediautils/LimitProcessMemory.h>
 #include <utils/Log.h>
 
 // from LOCAL_C_INCLUDES
@@ -35,7 +36,6 @@
 #include "AAudioService.h"
 #include "utility/AAudioUtilities.h"
 #include "MediaLogService.h"
-#include "MediaUtils.h"
 
 using namespace android;
 
diff --git a/media/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
index 57b4609..e05b12a 100644
--- a/media/bufferpool/2.0/Accessor.cpp
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -117,6 +117,10 @@
     Accessor::Impl::createInvalidator();
 }
 
+void Accessor::createEvictor() {
+    Accessor::Impl::createEvictor();
+}
+
 // Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
 Return<void> Accessor::connect(
         const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer,
diff --git a/media/bufferpool/2.0/Accessor.h b/media/bufferpool/2.0/Accessor.h
index 8d02519..8b43301 100644
--- a/media/bufferpool/2.0/Accessor.h
+++ b/media/bufferpool/2.0/Accessor.h
@@ -187,6 +187,8 @@
 
     static void createInvalidator();
 
+    static void createEvictor();
+
 private:
     class Impl;
     std::shared_ptr<Impl> mImpl;
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 1947656..6111fea 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -39,6 +39,9 @@
 
     static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
     static constexpr size_t kMinBufferCountForEviction = 25;
+
+    static constexpr nsecs_t kEvictGranularityNs = 1000000000; // 1 sec
+    static constexpr nsecs_t kEvictDurationNs = 5000000000; // 5 secs
 }
 
 // Buffer structure in bufferpool process
@@ -135,11 +138,18 @@
     return false;
 }
 
-uint32_t Accessor::Impl::sSeqId = time(nullptr);
+#ifdef __ANDROID_VNDK__
+static constexpr uint32_t kSeqIdVndkBit = 1U << 31;
+#else
+static constexpr uint32_t kSeqIdVndkBit = 0;
+#endif
+
+static constexpr uint32_t kSeqIdMax = 0x7fffffff;
+uint32_t Accessor::Impl::sSeqId = time(nullptr) & kSeqIdMax;
 
 Accessor::Impl::Impl(
         const std::shared_ptr<BufferPoolAllocator> &allocator)
-        : mAllocator(allocator) {}
+        : mAllocator(allocator), mScheduleEvictTs(0) {}
 
 Accessor::Impl::~Impl() {
 }
@@ -157,7 +167,7 @@
         std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
         if (newConnection) {
             int32_t pid = getpid();
-            ConnectionId id = (int64_t)pid << 32 | sSeqId;
+            ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
             status = mBufferPool.mObserver.open(id, statusDescPtr);
             if (status == ResultStatus::OK) {
                 newConnection->initialize(accessor, id);
@@ -167,7 +177,7 @@
                 mBufferPool.mConnectionIds.insert(id);
                 mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
                 mBufferPool.mInvalidation.onConnect(id, observer);
-                if (sSeqId == UINT32_MAX) {
+                if (sSeqId == kSeqIdMax) {
                    sSeqId = 0;
                 } else {
                     ++sSeqId;
@@ -177,6 +187,7 @@
         }
         mBufferPool.processStatusMessages();
         mBufferPool.cleanUp();
+        scheduleEvictIfNeeded();
     }
     return status;
 }
@@ -191,6 +202,7 @@
     // Since close# will be called after all works are finished, it is OK to
     // evict unused buffers.
     mBufferPool.cleanUp(true);
+    scheduleEvictIfNeeded();
     return ResultStatus::OK;
 }
 
@@ -217,6 +229,7 @@
         mBufferPool.handleOwnBuffer(connectionId, *bufferId);
     }
     mBufferPool.cleanUp();
+    scheduleEvictIfNeeded();
     return status;
 }
 
@@ -242,6 +255,7 @@
         }
     }
     mBufferPool.cleanUp();
+    scheduleEvictIfNeeded();
     return ResultStatus::CRITICAL_ERROR;
 }
 
@@ -884,6 +898,88 @@
     }
 }
 
+void Accessor::Impl::evictorThread(
+        std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv) {
+    std::list<const std::weak_ptr<Accessor::Impl>> evictList;
+    while (true) {
+        int expired = 0;
+        int evicted = 0;
+        {
+            nsecs_t now = systemTime();
+            std::unique_lock<std::mutex> lock(mutex);
+            if (accessors.size() == 0) {
+                cv.wait(lock);
+            }
+            auto it = accessors.begin();
+            while (it != accessors.end()) {
+                if (now > (it->second + kEvictDurationNs)) {
+                    ++expired;
+                    evictList.push_back(it->first);
+                    it = accessors.erase(it);
+                } else {
+                    ++it;
+                }
+            }
+        }
+        // evict idle accessors;
+        for (auto it = evictList.begin(); it != evictList.end(); ++it) {
+            const std::shared_ptr<Accessor::Impl> accessor = it->lock();
+            if (accessor) {
+                accessor->cleanUp(true);
+                ++evicted;
+            }
+        }
+        if (expired > 0) {
+            ALOGD("evictor expired: %d, evicted: %d", expired, evicted);
+        }
+        evictList.clear();
+        ::usleep(kEvictGranularityNs / 1000);
+    }
+}
+
+Accessor::Impl::AccessorEvictor::AccessorEvictor() {
+    std::thread evictor(
+            evictorThread,
+            std::ref(mAccessors),
+            std::ref(mMutex),
+            std::ref(mCv));
+    evictor.detach();
+}
+
+void Accessor::Impl::AccessorEvictor::addAccessor(
+        const std::weak_ptr<Accessor::Impl> &impl, nsecs_t ts) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    bool notify = mAccessors.empty();
+    auto it = mAccessors.find(impl);
+    if (it == mAccessors.end()) {
+        mAccessors.emplace(impl, ts);
+    } else {
+        it->second = ts;
+    }
+    if (notify) {
+        mCv.notify_one();
+    }
+}
+
+std::unique_ptr<Accessor::Impl::AccessorEvictor> Accessor::Impl::sEvictor;
+
+void Accessor::Impl::createEvictor() {
+    if (!sEvictor) {
+        sEvictor = std::make_unique<Accessor::Impl::AccessorEvictor>();
+    }
+}
+
+void Accessor::Impl::scheduleEvictIfNeeded() {
+    nsecs_t now = systemTime();
+
+    if (now > (mScheduleEvictTs + kEvictGranularityNs)) {
+        mScheduleEvictTs = now;
+        sEvictor->addAccessor(shared_from_this(), now);
+    }
+}
+
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace bufferpool
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index 9888be5..cd1b4d0 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -20,6 +20,7 @@
 #include <map>
 #include <set>
 #include <condition_variable>
+#include <utils/Timers.h>
 #include "Accessor.h"
 
 namespace android {
@@ -71,6 +72,8 @@
 
     static void createInvalidator();
 
+    static void createEvictor();
+
 private:
     // ConnectionId = pid : (timestamp_created + seqId)
     // in order to guarantee uniqueness for each connection
@@ -78,6 +81,8 @@
 
     const std::shared_ptr<BufferPoolAllocator> mAllocator;
 
+    nsecs_t mScheduleEvictTs;
+
     /**
      * Buffer pool implementation.
      *
@@ -389,6 +394,25 @@
         std::mutex &mutex,
         std::condition_variable &cv,
         bool &ready);
+
+    struct AccessorEvictor {
+        std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> mAccessors;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+
+        AccessorEvictor();
+        void addAccessor(const std::weak_ptr<Accessor::Impl> &impl, nsecs_t ts);
+    };
+
+    static std::unique_ptr<AccessorEvictor> sEvictor;
+
+    static void evictorThread(
+        std::map<const std::weak_ptr<Accessor::Impl>, nsecs_t, std::owner_less<>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv);
+
+    void scheduleEvictIfNeeded();
+
 };
 
 }  // namespace implementation
diff --git a/media/bufferpool/2.0/ClientManager.cpp b/media/bufferpool/2.0/ClientManager.cpp
index 87ee4e8..54a20b9 100644
--- a/media/bufferpool/2.0/ClientManager.cpp
+++ b/media/bufferpool/2.0/ClientManager.cpp
@@ -484,6 +484,7 @@
         sInstance = new ClientManager();
     }
     Accessor::createInvalidator();
+    Accessor::createEvictor();
     return sInstance;
 }
 
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 56813c4..d7b9e12 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -35,6 +35,7 @@
 constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
 constexpr uint32_t kDefaultOutputDelay = 8;
 constexpr uint32_t kMaxOutputDelay = 16;
+constexpr uint32_t kMinInputBytes = 4;
 }  // namespace
 
 class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -501,7 +502,7 @@
 status_t C2SoftAvcDec::initDecoder() {
     if (OK != createDecoder()) return UNKNOWN_ERROR;
     mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
-    mStride = ALIGN128(mWidth);
+    mStride = ALIGN32(mWidth);
     mSignalledError = false;
     resetPlugin();
     (void) setNumCores();
@@ -519,10 +520,20 @@
                                  size_t inSize,
                                  uint32_t tsMarker) {
     uint32_t displayStride = mStride;
+    if (outBuffer) {
+        C2PlanarLayout layout;
+        layout = outBuffer->layout();
+        displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
+    }
     uint32_t displayHeight = mHeight;
     size_t lumaSize = displayStride * displayHeight;
     size_t chromaSize = lumaSize >> 2;
 
+    if (mStride != displayStride) {
+        mStride = displayStride;
+        if (OK != setParams(mStride, IVD_DECODE_FRAME)) return false;
+    }
+
     ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
     ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
     if (inBuffer) {
@@ -538,7 +549,7 @@
     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
     if (outBuffer) {
-        if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) {
+        if (outBuffer->height() < displayHeight) {
             ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
                   outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
             return false;
@@ -756,24 +767,21 @@
         ALOGE("not supposed to be here, invalid decoder context");
         return C2_CORRUPTED;
     }
-    if (mStride != ALIGN128(mWidth)) {
-        mStride = ALIGN128(mWidth);
-        if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
-    }
     if (mOutBlock &&
-            (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
+            (mOutBlock->width() != ALIGN32(mWidth) || mOutBlock->height() != mHeight)) {
         mOutBlock.reset();
     }
     if (!mOutBlock) {
         uint32_t format = HAL_PIXEL_FORMAT_YV12;
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock);
+        c2_status_t err =
+            pool->fetchGraphicBlock(ALIGN32(mWidth), mHeight, format, usage, &mOutBlock);
         if (err != C2_OK) {
             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
             return err;
         }
         ALOGV("provided (%dx%d) required (%dx%d)",
-              mOutBlock->width(), mOutBlock->height(), mStride, mHeight);
+              mOutBlock->width(), mOutBlock->height(), ALIGN32(mWidth), mHeight);
     }
 
     return C2_OK;
@@ -817,7 +825,7 @@
           inSize, (int)work->input.ordinal.timestamp.peeku(),
           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
     size_t inPos = 0;
-    while (inPos < inSize) {
+    while (inPos < inSize && inSize - inPos >= kMinInputBytes) {
         if (C2_OK != ensureDecoderState(pool)) {
             mSignalledError = true;
             work->workletsProcessed = 1u;
@@ -904,12 +912,12 @@
                 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;
-                setParams(ALIGN128(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+                mStride = ALIGN32(s_decode_op.u4_pic_wd);
+                setParams(mStride, IVD_DECODE_FRAME);
             }
             if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
                 mWidth = s_decode_op.u4_pic_wd;
@@ -937,16 +945,7 @@
         if (s_decode_op.u4_output_present) {
             finishWork(s_decode_op.u4_ts, work);
         }
-        if (0 == s_decode_op.u4_num_bytes_consumed) {
-            ALOGD("Bytes consumed is zero. Ignoring remaining bytes");
-            break;
-        }
         inPos += s_decode_op.u4_num_bytes_consumed;
-        if (hasPicture && (inSize - inPos)) {
-            ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
-                  (int)inSize - (int)inPos);
-            break;
-        }
     }
     if (eos) {
         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index ed27493..bd84de0 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -39,8 +39,7 @@
 #define ivdext_ctl_set_num_cores_op_t   ih264d_ctl_set_num_cores_op_t
 #define ivdext_ctl_get_vui_params_ip_t  ih264d_ctl_get_vui_params_ip_t
 #define ivdext_ctl_get_vui_params_op_t  ih264d_ctl_get_vui_params_op_t
-#define ALIGN64(x)                      ((((x) + 63) >> 6) << 6)
-#define ALIGN128(x)                     ((((x) + 127) >> 7) << 7)
+#define ALIGN32(x)                      ((((x) + 31) >> 5) << 5)
 #define MAX_NUM_CORES                   4
 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
         (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index e3d419c..ab93ce3 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -103,7 +103,7 @@
 
         addParameter(
                 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
-                .withDefault(new C2StreamPictureSizeInfo::input(0u, 320, 240))
+                .withDefault(new C2StreamPictureSizeInfo::input(0u, 16, 16))
                 .withFields({
                     C2F(mSize, width).inRange(2, 2560, 2),
                     C2F(mSize, height).inRange(2, 2560, 2),
@@ -129,7 +129,7 @@
 
         addParameter(
                 DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
-                .withDefault(new C2StreamFrameRateInfo::output(0u, 30.))
+                .withDefault(new C2StreamFrameRateInfo::output(0u, 1.))
                 // TODO: More restriction?
                 .withFields({C2F(mFrameRate, value).greaterThan(0.)})
                 .withSetter(Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
diff --git a/media/codec2/components/base/SimpleC2Interface.cpp b/media/codec2/components/base/SimpleC2Interface.cpp
index c849a4e..5c019f3 100644
--- a/media/codec2/components/base/SimpleC2Interface.cpp
+++ b/media/codec2/components/base/SimpleC2Interface.cpp
@@ -21,6 +21,7 @@
 // use MediaDefs here vs. MediaCodecConstants as this is not MediaCodec specific/dependent
 #include <media/stagefright/foundation/MediaDefs.h>
 
+#include <C2PlatformSupport.h>
 #include <SimpleC2Interface.h>
 
 namespace android {
@@ -85,22 +86,24 @@
     C2Allocator::id_t rawAllocator = C2AllocatorStore::DEFAULT_LINEAR;
     C2BlockPool::local_id_t rawPoolId = C2BlockPool::BASIC_LINEAR;
     C2BufferData::type_t codedBufferType = C2BufferData::LINEAR;
-    C2Allocator::id_t codedAllocator = C2AllocatorStore::DEFAULT_LINEAR;
+    int poolMask = GetCodec2PoolMask();
+    C2Allocator::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
+    C2Allocator::id_t codedAllocator = preferredLinearId;
     C2BlockPool::local_id_t codedPoolId = C2BlockPool::BASIC_LINEAR;
 
     switch (domain) {
-        case C2Component::DOMAIN_IMAGE:
+        case C2Component::DOMAIN_IMAGE: [[fallthrough]];
         case C2Component::DOMAIN_VIDEO:
             // TODO: should we define raw image? The only difference is timestamp handling
             rawBufferType = C2BufferData::GRAPHIC;
             rawMediaType = MEDIA_MIMETYPE_VIDEO_RAW;
-            rawAllocator = C2AllocatorStore::DEFAULT_GRAPHIC;
+            rawAllocator = C2PlatformAllocatorStore::GRALLOC;
             rawPoolId = C2BlockPool::BASIC_GRAPHIC;
             break;
         case C2Component::DOMAIN_AUDIO:
             rawBufferType = C2BufferData::LINEAR;
             rawMediaType = MEDIA_MIMETYPE_AUDIO_RAW;
-            rawAllocator = C2AllocatorStore::DEFAULT_LINEAR;
+            rawAllocator = preferredLinearId;
             rawPoolId = C2BlockPool::BASIC_LINEAR;
             break;
         default:
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 6db4387..23104dc 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -497,7 +497,7 @@
 status_t C2SoftHevcDec::initDecoder() {
     if (OK != createDecoder()) return UNKNOWN_ERROR;
     mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
-    mStride = ALIGN128(mWidth);
+    mStride = ALIGN32(mWidth);
     mSignalledError = false;
     resetPlugin();
     (void) setNumCores();
@@ -515,10 +515,20 @@
                                   size_t inSize,
                                   uint32_t tsMarker) {
     uint32_t displayStride = mStride;
+    if (outBuffer) {
+        C2PlanarLayout layout;
+        layout = outBuffer->layout();
+        displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
+    }
     uint32_t displayHeight = mHeight;
     size_t lumaSize = displayStride * displayHeight;
     size_t chromaSize = lumaSize >> 2;
 
+    if (mStride != displayStride) {
+        mStride = displayStride;
+        if (OK != setParams(mStride, IVD_DECODE_FRAME)) return false;
+    }
+
     ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
     ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
     if (inBuffer) {
@@ -534,7 +544,7 @@
     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
     if (outBuffer) {
-        if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) {
+        if (outBuffer->height() < displayHeight) {
             ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
                   outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
             return false;
@@ -752,24 +762,21 @@
         ALOGE("not supposed to be here, invalid decoder context");
         return C2_CORRUPTED;
     }
-    if (mStride != ALIGN128(mWidth)) {
-        mStride = ALIGN128(mWidth);
-        if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
-    }
     if (mOutBlock &&
-            (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
+            (mOutBlock->width() != ALIGN32(mWidth) || mOutBlock->height() != mHeight)) {
         mOutBlock.reset();
     }
     if (!mOutBlock) {
         uint32_t format = HAL_PIXEL_FORMAT_YV12;
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock);
+        c2_status_t err =
+            pool->fetchGraphicBlock(ALIGN32(mWidth), mHeight, format, usage, &mOutBlock);
         if (err != C2_OK) {
             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
             return err;
         }
         ALOGV("provided (%dx%d) required (%dx%d)",
-              mOutBlock->width(), mOutBlock->height(), mStride, mHeight);
+              mOutBlock->width(), mOutBlock->height(), ALIGN32(mWidth), mHeight);
     }
 
     return C2_OK;
@@ -904,7 +911,7 @@
         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
             if (mHeaderDecoded == false) {
                 mHeaderDecoded = true;
-                setParams(ALIGN128(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
+                setParams(ALIGN32(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
             }
             if (s_decode_op.u4_pic_wd != mWidth ||  s_decode_op.u4_pic_ht != mHeight) {
                 mWidth = s_decode_op.u4_pic_wd;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.h b/media/codec2/components/hevc/C2SoftHevcDec.h
index aecd101..600d7c1 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.h
+++ b/media/codec2/components/hevc/C2SoftHevcDec.h
@@ -37,8 +37,7 @@
 #define ivdext_ctl_set_num_cores_op_t   ihevcd_cxa_ctl_set_num_cores_op_t
 #define ivdext_ctl_get_vui_params_ip_t  ihevcd_cxa_ctl_get_vui_params_ip_t
 #define ivdext_ctl_get_vui_params_op_t  ihevcd_cxa_ctl_get_vui_params_op_t
-#define ALIGN64(x)                      ((((x) + 63) >> 6) << 6)
-#define ALIGN128(x)                     ((((x) + 127) >> 7) << 7)
+#define ALIGN32(x)                      ((((x) + 31) >> 5) << 5)
 #define MAX_NUM_CORES                   4
 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
         (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 19ccbf9..c2d2540 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -628,6 +628,7 @@
         mComplexity = mIntf->getComplexity_l();
         mQuality = mIntf->getQuality_l();
         mGop = mIntf->getGop_l();
+        mRequestSync = mIntf->getRequestSync_l();
     }
 
     c2_status_t status = initEncParams();
@@ -956,7 +957,7 @@
         }
     }
 
-    // handle dynamic config parameters
+    // handle dynamic bitrate change
     {
         IntfImpl::Lock lock = mIntf->lock();
         std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
@@ -983,6 +984,26 @@
         work->workletsProcessed = 1u;
         return;
     }
+    // handle request key frame
+    {
+        IntfImpl::Lock lock = mIntf->lock();
+        std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync;
+        requestSync = mIntf->getRequestSync_l();
+        lock.unlock();
+        if (requestSync != mRequestSync) {
+            // we can handle IDR immediately
+            if (requestSync->value) {
+                // unset request
+                C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
+                std::vector<std::unique_ptr<C2SettingResult>> failures;
+                mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
+                ALOGV("Got sync request");
+                //Force this as an IDR frame
+                s_encode_ip.i4_force_idr_flag = 1;
+            }
+            mRequestSync = requestSync;
+        }
+    }
 
     uint64_t timeDelay = 0;
     uint64_t timeTaken = 0;
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index 140b4a9..5ea4602 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -88,6 +88,7 @@
     std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
     std::shared_ptr<C2StreamQualityTuning::output> mQuality;
     std::shared_ptr<C2StreamGopTuning::output> mGop;
+    std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
 #ifdef FILE_DUMP_ENABLE
     char mInFile[200];
     char mOutFile[200];
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index e0365fc..55dd475 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -571,7 +571,7 @@
     if (OK != createDecoder()) return UNKNOWN_ERROR;
 
     mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
-    mStride = ALIGN64(mWidth);
+    mStride = ALIGN32(mWidth);
     mSignalledError = false;
     resetPlugin();
     (void) setNumCores();
@@ -589,10 +589,20 @@
                                    size_t inSize,
                                    uint32_t tsMarker) {
     uint32_t displayStride = mStride;
+    if (outBuffer) {
+        C2PlanarLayout layout;
+        layout = outBuffer->layout();
+        displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
+    }
     uint32_t displayHeight = mHeight;
     size_t lumaSize = displayStride * displayHeight;
     size_t chromaSize = lumaSize >> 2;
 
+    if (mStride != displayStride) {
+        mStride = displayStride;
+        if (OK != setParams(mStride)) return false;
+    }
+
     ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
     ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
     if (inBuffer) {
@@ -608,7 +618,7 @@
     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
     if (outBuffer) {
-        if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) {
+        if (outBuffer->height() < displayHeight) {
             ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
                   outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
             return false;
@@ -833,24 +843,21 @@
         ALOGE("not supposed to be here, invalid decoder context");
         return C2_CORRUPTED;
     }
-    if (mStride != ALIGN64(mWidth)) {
-        mStride = ALIGN64(mWidth);
-        if (OK != setParams(mStride)) return C2_CORRUPTED;
-    }
     if (mOutBlock &&
-            (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
+            (mOutBlock->width() != ALIGN32(mWidth) || mOutBlock->height() != mHeight)) {
         mOutBlock.reset();
     }
     if (!mOutBlock) {
         uint32_t format = HAL_PIXEL_FORMAT_YV12;
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock);
+        c2_status_t err =
+            pool->fetchGraphicBlock(ALIGN32(mWidth), mHeight, format, usage, &mOutBlock);
         if (err != C2_OK) {
             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
             return err;
         }
         ALOGV("provided (%dx%d) required (%dx%d)",
-              mOutBlock->width(), mOutBlock->height(), mStride, mHeight);
+              mOutBlock->width(), mOutBlock->height(), ALIGN32(mWidth), mHeight);
     }
 
     return C2_OK;
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
index 65d3b87..fd66304a 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.h
@@ -37,7 +37,7 @@
 #define ivdext_ctl_set_num_cores_op_t   impeg2d_ctl_set_num_cores_op_t
 #define ivdext_ctl_get_seq_info_ip_t    impeg2d_ctl_get_seq_info_ip_t
 #define ivdext_ctl_get_seq_info_op_t    impeg2d_ctl_get_seq_info_op_t
-#define ALIGN64(x)                      ((((x) + 63) >> 6) << 6)
+#define ALIGN32(x)                      ((((x) + 31) >> 5) << 5)
 #define MAX_NUM_CORES                   4
 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
         (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index c7d73f4..3eef1e3 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -784,7 +784,13 @@
         }
 
     }
-    CHECK(img->fmt == VPX_IMG_FMT_I420 || img->fmt == VPX_IMG_FMT_I42016);
+    if(img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_I42016) {
+        ALOGE("img->fmt %d not supported", img->fmt);
+        mSignalledError = true;
+        work->workletsProcessed = 1u;
+        work->result = C2_CORRUPTED;
+        return false;
+    }
 
     std::shared_ptr<C2GraphicBlock> block;
     uint32_t format = HAL_PIXEL_FORMAT_YV12;
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index ebc7a8f..74e105e 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -67,8 +67,9 @@
       mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
       mSignalledOutputEos(false),
       mSignalledError(false) {
-    memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
-    mTemporalLayerBitrateRatio[0] = 100;
+    for (int i = 0; i < MAXTEMPORALLAYERS; i++) {
+        mTemporalLayerBitrateRatio[i] = 1.0f;
+    }
 }
 
 C2SoftVpxEnc::~C2SoftVpxEnc() {
@@ -123,7 +124,8 @@
         mFrameRate = mIntf->getFrameRate_l();
         mIntraRefresh = mIntf->getIntraRefresh_l();
         mRequestSync = mIntf->getRequestSync_l();
-        mTemporalLayers = mIntf->getTemporalLayers_l()->m.layerCount;
+        mLayering = mIntf->getTemporalLayers_l();
+        mTemporalLayers = mLayering->m.layerCount;
     }
 
     switch (mBitrateMode->value) {
@@ -225,6 +227,7 @@
             mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
             mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
             mTemporalPattern[7] = kTemporalUpdateNone;
+            mTemporalLayerBitrateRatio[0] = mLayering->m.bitrateRatios[0];
             mTemporalPatternLength = 8;
             break;
         case 3:
@@ -245,6 +248,8 @@
             mTemporalPattern[5] = kTemporalUpdateNone;
             mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
             mTemporalPattern[7] = kTemporalUpdateNone;
+            mTemporalLayerBitrateRatio[0] = mLayering->m.bitrateRatios[0];
+            mTemporalLayerBitrateRatio[1] = mLayering->m.bitrateRatios[1];
             mTemporalPatternLength = 8;
             break;
         default:
@@ -255,7 +260,7 @@
     for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
         mCodecConfiguration->ts_target_bitrate[i] =
             mCodecConfiguration->rc_target_bitrate *
-            mTemporalLayerBitrateRatio[i] / 100;
+            mTemporalLayerBitrateRatio[i];
     }
     if (mIntf->getSyncFramePeriod() >= 0) {
         mCodecConfiguration->kf_max_dist = mIntf->getSyncFramePeriod();
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.h b/media/codec2/components/vpx/C2SoftVpxEnc.h
index 62ccd1b..5e34b8a 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.h
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.h
@@ -180,7 +180,7 @@
      size_t mTemporalLayers;
 
      // Temporal layer bitrare ratio in percentage
-     uint32_t mTemporalLayerBitrateRatio[MAXTEMPORALLAYERS];
+     float_t mTemporalLayerBitrateRatio[MAXTEMPORALLAYERS];
 
      // Temporal pattern type
      TemporalPatternType mTemporalPatternType;
@@ -218,6 +218,7 @@
     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
     std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
     std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
+    std::shared_ptr<C2StreamTemporalLayeringTuning::output> mLayering;
 
      C2_DO_NOT_COPY(C2SoftVpxEnc);
 };
diff --git a/media/codec2/hidl/1.0/vts/OWNERS b/media/codec2/hidl/1.0/vts/OWNERS
index 6733e0c..dbe89cf 100644
--- a/media/codec2/hidl/1.0/vts/OWNERS
+++ b/media/codec2/hidl/1.0/vts/OWNERS
@@ -5,5 +5,4 @@
 wonsik@google.com
 
 # VTS team
-yim@google.com
-zhuoyao@google.com
+dshi@google.com
diff --git a/media/codec2/hidl/1.0/vts/functional/Android.bp b/media/codec2/hidl/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..cd3be81
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/Android.bp
@@ -0,0 +1,103 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+filegroup {
+    name: "media_c2_v1_audio_decode_res",
+    path: "res",
+    srcs: [
+        "res/bbb_aac_stereo_128kbps_48000hz.aac",
+        "res/bbb_aac_stereo_128kbps_48000hz.info",
+        "res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info",
+        "res/bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+        "res/bbb_amrwb_1ch_14kbps_16000hz.info",
+        "res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info",
+        "res/bbb_flac_stereo_680kbps_48000hz.flac",
+        "res/bbb_flac_stereo_680kbps_48000hz.info",
+        "res/bbb_g711alaw_1ch_8khz.info",
+        "res/bbb_g711alaw_1ch_8khz.raw",
+        "res/bbb_g711mulaw_1ch_8khz.info",
+        "res/bbb_g711mulaw_1ch_8khz.raw",
+        "res/bbb_gsm_1ch_8khz_13kbps.info",
+        "res/bbb_gsm_1ch_8khz_13kbps.raw",
+        "res/bbb_mp3_stereo_192kbps_48000hz.info",
+        "res/bbb_mp3_stereo_192kbps_48000hz.mp3",
+        "res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info",
+        "res/bbb_opus_stereo_128kbps_48000hz.info",
+        "res/bbb_opus_stereo_128kbps_48000hz.opus",
+        "res/bbb_raw_1ch_8khz_s32le.info",
+        "res/bbb_raw_1ch_8khz_s32le.raw",
+        "res/bbb_vorbis_stereo_128kbps_48000hz.info",
+        "res/bbb_vorbis_stereo_128kbps_48000hz.vorbis",
+        "res/sine_amrnb_1ch_12kbps_8000hz.amrnb",
+        "res/sine_amrnb_1ch_12kbps_8000hz.info",
+        "res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info",
+    ],
+}
+
+filegroup {
+    name: "media_c2_v1_audio_encode_res",
+    path: "res",
+    srcs: [
+        "res/bbb_raw_2ch_48khz_s16le.raw",
+        "res/bbb_raw_1ch_8khz_s16le.raw",
+        "res/bbb_raw_1ch_16khz_s16le.raw",
+    ],
+}
+
+filegroup {
+    name: "media_c2_v1_video_decode_res",
+    path: "res",
+    srcs: [
+        "res/bbb_avc_176x144_300kbps_60fps.h264",
+        "res/bbb_avc_640x360_768kbps_30fps.h264",
+        "res/bbb_avc_176x144_300kbps_60fps.info",
+        "res/bbb_avc_640x360_768kbps_30fps.info",
+        "res/bbb_hevc_176x144_176kbps_60fps.hevc",
+        "res/bbb_hevc_640x360_1600kbps_30fps.hevc",
+        "res/bbb_hevc_176x144_176kbps_60fps.info",
+        "res/bbb_hevc_640x360_1600kbps_30fps.info",
+        "res/bbb_mpeg2_176x144_105kbps_25fps.m2v",
+        "res/bbb_mpeg2_352x288_1mbps_60fps.m2v",
+        "res/bbb_mpeg2_176x144_105kbps_25fps.info",
+        "res/bbb_mpeg2_352x288_1mbps_60fps.info",
+        "res/bbb_h263_352x288_300kbps_12fps.h263",
+        "res/bbb_h263_352x288_300kbps_12fps.info",
+        "res/bbb_mpeg4_352x288_512kbps_30fps.m4v",
+        "res/bbb_mpeg4_352x288_512kbps_30fps.info",
+        "res/bbb_vp8_176x144_240kbps_60fps.vp8",
+        "res/bbb_vp8_640x360_2mbps_30fps.vp8",
+        "res/bbb_vp8_176x144_240kbps_60fps.info",
+        "res/bbb_vp8_640x360_2mbps_30fps.info",
+        "res/bbb_vp9_176x144_285kbps_60fps.vp9",
+        "res/bbb_vp9_640x360_1600kbps_30fps.vp9",
+        "res/bbb_vp9_176x144_285kbps_60fps.info",
+        "res/bbb_vp9_640x360_1600kbps_30fps.info",
+        "res/bbb_av1_640_360.av1",
+        "res/bbb_av1_176_144.av1",
+        "res/bbb_av1_640_360.info",
+        "res/bbb_av1_176_144.info",
+        "res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9",
+        "res/bbb_vp9_704x480_280kbps_24fps_altref_2.info",
+    ],
+}
+
+filegroup {
+    name: "media_c2_v1_video_encode_res",
+    path: "res",
+    srcs: [
+        "res/bbb_352x288_420p_30fps_32frames.yuv",
+    ],
+}
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/Android.bp b/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
index 65f0d09..014cbe9 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
@@ -16,18 +16,22 @@
 
 cc_test {
     name: "VtsHalMediaC2V1_0TargetAudioDecTest",
+    stem: "vts_media_c2_v1_0_audio_dec_test",
     defaults: ["VtsHalMediaC2V1_0Defaults"],
     srcs: [
         "VtsHalMediaC2V1_0TargetAudioDecTest.cpp",
-        //"media_audio_hidl_test_common.cpp"
     ],
+    data: [":media_c2_v1_audio_decode_res"],
+    test_config: "VtsHalMediaC2V1_0TargetAudioDecTest.xml",
 }
 
 cc_test {
     name: "VtsHalMediaC2V1_0TargetAudioEncTest",
+    stem: "vts_media_c2_v1_0_audio_enc_test",
     defaults: ["VtsHalMediaC2V1_0Defaults"],
     srcs: [
         "VtsHalMediaC2V1_0TargetAudioEncTest.cpp",
-        //"media_audio_hidl_test_common.cpp"
     ],
+    data: [":media_c2_v1_audio_encode_res"],
+    test_config: "VtsHalMediaC2V1_0TargetAudioEncTest.xml",
 }
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 20f4665..264abba 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
@@ -19,21 +19,20 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
-#include <algorithm>
+#include <hidl/GtestPrinter.h>
 #include <stdio.h>
+#include <algorithm>
 #include <fstream>
 
-#include <codec2/hidl/client.h>
 #include <C2AllocatorIon.h>
-#include <C2Config.h>
-#include <C2Debug.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <codec2/hidl/client.h>
 
 using android::C2AllocatorIon;
 
-#include <VtsHalHidlTargetTestBase.h>
-#include "media_c2_audio_hidl_test_common.h"
 #include "media_c2_hidl_test_common.h"
 
 struct FrameInfo {
@@ -42,57 +41,44 @@
     int64_t timestamp;
 };
 
-class LinearBuffer : public C2Buffer {
-   public:
-    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
-        : C2Buffer(
-              {block->share(block->offset(), block->size(), ::C2Fence())}) {}
-};
+static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
+        kDecodeTestParameters;
 
-static ComponentTestEnvironment* gEnv = nullptr;
+// Resource directory
+static std::string sResourceDir = "";
+
+class LinearBuffer : public C2Buffer {
+  public:
+    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
+        : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
+};
 
 namespace {
 
-class Codec2AudioDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
-    typedef ::testing::VtsHalHidlTargetTestBase Super;
-
-   public:
-    ::std::string getTestCaseInfo() const override {
-        return ::std::string() +
-                "Component: " + gEnv->getComponent().c_str() + " | " +
-                "Instance: " + gEnv->getInstance().c_str() + " | " +
-                "Res: " + gEnv->getRes().c_str();
-    }
-
+class Codec2AudioDecHidlTestBase : public ::testing::Test {
+  public:
     // google.codec2 Audio test setup
     virtual void SetUp() override {
-        Super::SetUp();
+        getParams();
         mDisableTest = false;
         ALOGV("Codec2AudioDecHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str(),
-            !bool(android::Codec2Client::CreateFromService("default", true)));
+                mInstanceName.c_str(),
+                !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
-        mListener.reset(new CodecListener(
-            [this](std::list<std::unique_ptr<C2Work>>& workItems) {
-                handleWorkDone(workItems);
-            }));
+        mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
+            handleWorkDone(workItems);
+        }));
         ASSERT_NE(mListener, nullptr);
         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
             mWorkQueue.emplace_back(new C2Work);
         }
-        mClient->createComponent(gEnv->getComponent().c_str(), mListener,
-                                 &mComponent);
+        mClient->createComponent(mComponentName, mListener, &mComponent);
         ASSERT_NE(mComponent, nullptr);
 
-        std::shared_ptr<C2AllocatorStore> store =
-            android::GetCodec2PlatformAllocatorStore();
-        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR,
-                                       &mLinearAllocator),
-                 C2_OK);
-        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
-                                                          mBlockPoolId++);
+        std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
+        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
         ASSERT_NE(mLinearPool, nullptr);
 
         mCompName = unknown_comp;
@@ -101,27 +87,17 @@
             standardComp CompName;
         };
         const StringToName kStringToName[] = {
-            {"xaac", xaac},
-            {"mp3", mp3},
-            {"amrnb", amrnb},
-            {"amrwb", amrwb},
-            {"aac", aac},
-            {"vorbis", vorbis},
-            {"opus", opus},
-            {"pcm", pcm},
-            {"g711.alaw", g711alaw},
-            {"g711.mlaw", g711mlaw},
-            {"gsm", gsm},
-            {"raw", raw},
-            {"flac", flac},
+                {"xaac", xaac},          {"mp3", mp3}, {"amrnb", amrnb},
+                {"amrwb", amrwb},        {"aac", aac}, {"vorbis", vorbis},
+                {"opus", opus},          {"pcm", pcm}, {"g711.alaw", g711alaw},
+                {"g711.mlaw", g711mlaw}, {"gsm", gsm}, {"raw", raw},
+                {"flac", flac},
         };
-        const size_t kNumStringToName =
-            sizeof(kStringToName) / sizeof(kStringToName[0]);
+        const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
 
         // Find the component type
-        std::string comp = std::string(gEnv->getComponent());
         for (size_t i = 0; i < kNumStringToName; ++i) {
-            if (strcasestr(comp.c_str(), kStringToName[i].Name)) {
+            if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
                 mCompName = kStringToName[i].CompName;
                 break;
             }
@@ -140,9 +116,11 @@
             mComponent->release();
             mComponent = nullptr;
         }
-        Super::TearDown();
     }
 
+    // Get the test parameters from GetParam call.
+    virtual void getParams() {}
+
     struct outputMetaData {
         uint64_t timestampUs;
         uint32_t rangeLength;
@@ -155,25 +133,27 @@
                 // previous timestamp
                 bool codecConfig = ((work->worklets.front()->output.flags &
                                      C2FrameData::FLAG_CODEC_CONFIG) != 0);
-                if (!codecConfig &&
-                    !work->worklets.front()->output.buffers.empty()) {
+                if (!codecConfig && !work->worklets.front()->output.buffers.empty()) {
                     EXPECT_GE(work->worklets.front()->output.ordinal.timestamp.peeku(),
-                        mTimestampUs);
-                    mTimestampUs =
-                        work->worklets.front()->output.ordinal.timestamp.peeku();
-                    uint32_t rangeLength =
-                        work->worklets.front()->output.buffers[0]->data()
-                        .linearBlocks().front().map().get().capacity();
-                    //List of timestamp values and output size to calculate timestamp
+                              mTimestampUs);
+                    mTimestampUs = work->worklets.front()->output.ordinal.timestamp.peeku();
+                    uint32_t rangeLength = work->worklets.front()
+                                                   ->output.buffers[0]
+                                                   ->data()
+                                                   .linearBlocks()
+                                                   .front()
+                                                   .map()
+                                                   .get()
+                                                   .capacity();
+                    // List of timestamp values and output size to calculate timestamp
                     if (mTimestampDevTest) {
                         outputMetaData meta = {mTimestampUs, rangeLength};
                         oBufferMetaData.push_back(meta);
                     }
                 }
                 bool mCsd = false;
-                workDone(mComponent, work, mFlushedIndices, mQueueLock,
-                         mQueueCondition, mWorkQueue, mEos, mCsd,
-                         mFramesReceived);
+                workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
+                         mEos, mCsd, mFramesReceived);
                 (void)mCsd;
             }
         }
@@ -196,6 +176,8 @@
         unknown_comp,
     };
 
+    std::string mInstanceName;
+    std::string mComponentName;
     bool mEos;
     bool mDisableTest;
     bool mTimestampDevTest;
@@ -218,15 +200,23 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
-   protected:
+  protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
 };
 
-void validateComponent(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) {
+class Codec2AudioDecHidlTest
+    : public Codec2AudioDecHidlTestBase,
+      public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
+};
+
+void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
+                       Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) {
     // Validate its a C2 Component
     if (component->getName().find("c2") == std::string::npos) {
         ALOGE("Not a c2 component");
@@ -241,14 +231,12 @@
         return;
     }
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err =
-        component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
-                         C2_DONT_BLOCK, &queried);
+    c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+                                         C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK && queried.size() == 0) {
         ALOGE("Query media type failed => %d", c2err);
     } else {
-        std::string inputDomain =
-            ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
+        std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
         if (inputDomain.find("audio/") == std::string::npos) {
             ALOGE("Expected Audio Component");
             disableTest = true;
@@ -266,16 +254,14 @@
 }
 
 // Set Default config param.
-bool setupConfigParam(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    int32_t* bitStreamInfo) {
+bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
+                      int32_t* bitStreamInfo) {
     std::vector<std::unique_ptr<C2SettingResult>> failures;
     C2StreamSampleRateInfo::output sampleRateInfo(0u, bitStreamInfo[0]);
     C2StreamChannelCountInfo::output channelCountInfo(0u, bitStreamInfo[1]);
 
     std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
-    c2_status_t status =
-        component->config(configParam, C2_DONT_BLOCK, &failures);
+    c2_status_t status = component->config(configParam, C2_DONT_BLOCK, &failures);
     if (status == C2_OK && failures.size() == 0u) return true;
     return false;
 }
@@ -283,17 +269,15 @@
 // In decoder components, often the input parameters get updated upon
 // parsing the header of elementary stream. Client needs to collect this
 // information and reconfigure
-void getInputChannelInfo(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
+void getInputChannelInfo(const std::shared_ptr<android::Codec2Client::Component>& component,
+                         Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
     // query nSampleRate and nChannels
     std::initializer_list<C2Param::Index> indices{
-        C2StreamSampleRateInfo::output::PARAM_TYPE,
-        C2StreamChannelCountInfo::output::PARAM_TYPE,
+            C2StreamSampleRateInfo::output::PARAM_TYPE,
+            C2StreamChannelCountInfo::output::PARAM_TYPE,
     };
     std::vector<std::unique_ptr<C2Param>> inParams;
-    c2_status_t status =
-        component->query({}, indices, C2_DONT_BLOCK, &inParams);
+    c2_status_t status = component->query({}, indices, C2_DONT_BLOCK, &inParams);
     if (status != C2_OK && inParams.size() == 0) {
         ALOGE("Query media type failed => %d", status);
         ASSERT_TRUE(false);
@@ -328,8 +312,8 @@
 #define STREAM_COUNT 2
 
 // LookUpTable of clips and metadata for component testing
-void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL,
-                        char* info, size_t streamIndex = 0) {
+void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL, char* info,
+                        size_t streamIndex = 0) {
     struct CompToURL {
         Codec2AudioDecHidlTest::standardComp comp;
         const char mURL[STREAM_COUNT][512];
@@ -338,52 +322,47 @@
     ASSERT_TRUE(streamIndex < STREAM_COUNT);
 
     static const CompToURL kCompToURL[] = {
-        {Codec2AudioDecHidlTest::standardComp::xaac,
-         {"bbb_aac_stereo_128kbps_48000hz.aac",
-          "bbb_aac_stereo_128kbps_48000hz.aac"},
-         {"bbb_aac_stereo_128kbps_48000hz.info",
-          "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
-        {Codec2AudioDecHidlTest::standardComp::mp3,
-         {"bbb_mp3_stereo_192kbps_48000hz.mp3",
-          "bbb_mp3_stereo_192kbps_48000hz.mp3"},
-         {"bbb_mp3_stereo_192kbps_48000hz.info",
-          "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}},
-        {Codec2AudioDecHidlTest::standardComp::aac,
-         {"bbb_aac_stereo_128kbps_48000hz.aac",
-          "bbb_aac_stereo_128kbps_48000hz.aac"},
-         {"bbb_aac_stereo_128kbps_48000hz.info",
-          "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
-        {Codec2AudioDecHidlTest::standardComp::amrnb,
-         {"sine_amrnb_1ch_12kbps_8000hz.amrnb",
-          "sine_amrnb_1ch_12kbps_8000hz.amrnb"},
-         {"sine_amrnb_1ch_12kbps_8000hz.info",
-          "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}},
-        {Codec2AudioDecHidlTest::standardComp::amrwb,
-         {"bbb_amrwb_1ch_14kbps_16000hz.amrwb",
-          "bbb_amrwb_1ch_14kbps_16000hz.amrwb"},
-         {"bbb_amrwb_1ch_14kbps_16000hz.info",
-          "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}},
-        {Codec2AudioDecHidlTest::standardComp::vorbis,
-         {"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""},
-         {"bbb_vorbis_stereo_128kbps_48000hz.info", ""}},
-        {Codec2AudioDecHidlTest::standardComp::opus,
-         {"bbb_opus_stereo_128kbps_48000hz.opus", ""},
-         {"bbb_opus_stereo_128kbps_48000hz.info", ""}},
-        {Codec2AudioDecHidlTest::standardComp::g711alaw,
-         {"bbb_g711alaw_1ch_8khz.raw", ""},
-         {"bbb_g711alaw_1ch_8khz.info", ""}},
-        {Codec2AudioDecHidlTest::standardComp::g711mlaw,
-         {"bbb_g711mulaw_1ch_8khz.raw", ""},
-         {"bbb_g711mulaw_1ch_8khz.info", ""}},
-        {Codec2AudioDecHidlTest::standardComp::gsm,
-         {"bbb_gsm_1ch_8khz_13kbps.raw", ""},
-         {"bbb_gsm_1ch_8khz_13kbps.info", ""}},
-        {Codec2AudioDecHidlTest::standardComp::raw,
-         {"bbb_raw_1ch_8khz_s32le.raw", ""},
-         {"bbb_raw_1ch_8khz_s32le.info", ""}},
-        {Codec2AudioDecHidlTest::standardComp::flac,
-         {"bbb_flac_stereo_680kbps_48000hz.flac", ""},
-         {"bbb_flac_stereo_680kbps_48000hz.info", ""}},
+            {Codec2AudioDecHidlTest::standardComp::xaac,
+             {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
+             {"bbb_aac_stereo_128kbps_48000hz.info",
+              "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
+            {Codec2AudioDecHidlTest::standardComp::mp3,
+             {"bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.mp3"},
+             {"bbb_mp3_stereo_192kbps_48000hz.info",
+              "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}},
+            {Codec2AudioDecHidlTest::standardComp::aac,
+             {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
+             {"bbb_aac_stereo_128kbps_48000hz.info",
+              "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
+            {Codec2AudioDecHidlTest::standardComp::amrnb,
+             {"sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz.amrnb"},
+             {"sine_amrnb_1ch_12kbps_8000hz.info",
+              "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}},
+            {Codec2AudioDecHidlTest::standardComp::amrwb,
+             {"bbb_amrwb_1ch_14kbps_16000hz.amrwb", "bbb_amrwb_1ch_14kbps_16000hz.amrwb"},
+             {"bbb_amrwb_1ch_14kbps_16000hz.info",
+              "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}},
+            {Codec2AudioDecHidlTest::standardComp::vorbis,
+             {"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""},
+             {"bbb_vorbis_stereo_128kbps_48000hz.info", ""}},
+            {Codec2AudioDecHidlTest::standardComp::opus,
+             {"bbb_opus_stereo_128kbps_48000hz.opus", ""},
+             {"bbb_opus_stereo_128kbps_48000hz.info", ""}},
+            {Codec2AudioDecHidlTest::standardComp::g711alaw,
+             {"bbb_g711alaw_1ch_8khz.raw", ""},
+             {"bbb_g711alaw_1ch_8khz.info", ""}},
+            {Codec2AudioDecHidlTest::standardComp::g711mlaw,
+             {"bbb_g711mulaw_1ch_8khz.raw", ""},
+             {"bbb_g711mulaw_1ch_8khz.info", ""}},
+            {Codec2AudioDecHidlTest::standardComp::gsm,
+             {"bbb_gsm_1ch_8khz_13kbps.raw", ""},
+             {"bbb_gsm_1ch_8khz_13kbps.info", ""}},
+            {Codec2AudioDecHidlTest::standardComp::raw,
+             {"bbb_raw_1ch_8khz_s32le.raw", ""},
+             {"bbb_raw_1ch_8khz_s32le.info", ""}},
+            {Codec2AudioDecHidlTest::standardComp::flac,
+             {"bbb_flac_stereo_680kbps_48000hz.flac", ""},
+             {"bbb_flac_stereo_680kbps_48000hz.info", ""}},
     };
 
     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@@ -396,13 +375,11 @@
 }
 
 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
-                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::mutex& queueLock, std::condition_variable& queueCondition,
                    std::list<std::unique_ptr<C2Work>>& workQueue,
-                   std::list<uint64_t>& flushedIndices,
-                   std::shared_ptr<C2BlockPool>& linearPool,
-                   std::ifstream& eleStream,
-                   android::Vector<FrameInfo>* Info,
-                   int offset, int range, bool signalEOS = true) {
+                   std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
+                   std::ifstream& eleStream, android::Vector<FrameInfo>* Info, int offset,
+                   int range, bool signalEOS = true) {
     typedef std::unique_lock<std::mutex> ULock;
     int frameID = offset;
     int maxRetry = 0;
@@ -426,8 +403,7 @@
         }
         int64_t timestamp = (*Info)[frameID].timestamp;
         if ((*Info)[frameID].flags) flags = 1u << ((*Info)[frameID].flags - 1);
-        if (signalEOS && ((frameID == (int)Info->size() - 1) ||
-                          (frameID == (offset + range - 1))))
+        if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1))))
             flags |= C2FrameData::FLAG_END_OF_STREAM;
 
         work->input.flags = (C2FrameData::flags_t)flags;
@@ -448,9 +424,8 @@
         if (size) {
             std::shared_ptr<C2LinearBlock> block;
             ASSERT_EQ(C2_OK,
-                    linearPool->fetchLinearBlock(
-                        size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
-                        &block));
+                      linearPool->fetchLinearBlock(
+                              size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
             ASSERT_TRUE(block);
 
             // Write View
@@ -482,45 +457,49 @@
     }
 }
 
-TEST_F(Codec2AudioDecHidlTest, validateCompName) {
-    if (mDisableTest) return;
+TEST_P(Codec2AudioDecHidlTest, validateCompName) {
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ALOGV("Checks if the given component is a valid audio component");
     validateComponent(mComponent, mCompName, mDisableTest);
     ASSERT_EQ(mDisableTest, false);
 }
 
-TEST_F(Codec2AudioDecHidlTest, configComp) {
+TEST_P(Codec2AudioDecHidlTest, configComp) {
     description("Tests component specific configuration");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ASSERT_EQ(mComponent->start(), C2_OK);
     int32_t bitStreamInfo[2] = {0};
-    ASSERT_NO_FATAL_FAILURE(
-        getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+    ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     setupConfigParam(mComponent, bitStreamInfo);
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
 class Codec2AudioDecDecodeTest
-    : public Codec2AudioDecHidlTest,
-      public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
+    : public Codec2AudioDecHidlTestBase,
+      public ::testing::WithParamInterface<
+              std::tuple<std::string, std::string, std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
 };
 
 TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
     description("Decodes input file");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    uint32_t streamIndex = GetParam().first;
-    bool signalEOS = GetParam().second;
+    uint32_t streamIndex = std::stoi(std::get<2>(GetParam()));
+    ;
+    bool signalEOS = !std::get<3>(GetParam()).compare("true");
     mTimestampDevTest = true;
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info, streamIndex);
-    if (!strcmp(mURL, gEnv->getRes().c_str())) {
-        ALOGV("EMPTY INPUT gEnv->getRes().c_str() %s mURL  %s ",
-              gEnv->getRes().c_str(), mURL);
+    if (!strcmp(mURL, sResourceDir.c_str())) {
+        ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL  %s ", sResourceDir.c_str(), mURL);
         return;
     }
 
@@ -534,10 +513,8 @@
         if (!(eleInfo >> bytesCount)) break;
         eleInfo >> flags;
         eleInfo >> timestamp;
-        bool codecConfig =
-            ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
-        if (mTimestampDevTest && !codecConfig)
-            mTimestampUslist.push_back(timestamp);
+        bool codecConfig = ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0;
+        if (mTimestampDevTest && !codecConfig) mTimestampUslist.push_back(timestamp);
         Info.push_back({bytesCount, flags, timestamp});
     }
     eleInfo.close();
@@ -549,8 +526,7 @@
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
     } else {
-        ASSERT_NO_FATAL_FAILURE(
-            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+        ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     }
     if (!setupConfigParam(mComponent, bitStreamInfo)) {
         std::cout << "[   WARN   ] Test Skipped \n";
@@ -560,29 +536,25 @@
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
-    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS));
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                          (int)Info.size(), signalEOS));
 
     // If EOS is not sent, sending empty input with EOS flag
     size_t infoSize = Info.size();
     if (!signalEOS) {
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
-        ASSERT_NO_FATAL_FAILURE(
-            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
-                            C2FrameData::FLAG_END_OF_STREAM, false));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                                                C2FrameData::FLAG_END_OF_STREAM, false));
         infoSize += 1;
     }
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     eleStream.close();
     if (mFramesReceived != infoSize) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived,
-              infoSize);
+        ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived, infoSize);
         ASSERT_TRUE(false);
     }
     ASSERT_EQ(mEos, true);
@@ -590,8 +562,7 @@
         uint64_t expTs;
         uint32_t samplesReceived = 0;
         // Update SampleRate and ChannelCount
-        ASSERT_NO_FATAL_FAILURE(
-            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+        ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
         int nSampleRate = bitStreamInfo[0];
         int nChannels = bitStreamInfo[1];
         std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
@@ -614,23 +585,17 @@
     }
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
-// DecodeTest with StreamIndex and EOS / No EOS
-INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
-                        ::testing::Values(std::make_pair(0, false),
-                                          std::make_pair(0, true),
-                                          std::make_pair(1, false),
-                                          std::make_pair(1, true)));
 
 // thumbnail test
-TEST_F(Codec2AudioDecHidlTest, ThumbnailTest) {
+TEST_P(Codec2AudioDecHidlTest, ThumbnailTest) {
     description("Test Request for thumbnail");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info);
 
     eleInfo.open(info);
@@ -651,8 +616,7 @@
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
     } else {
-        ASSERT_NO_FATAL_FAILURE(
-            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+        ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     }
     if (!setupConfigParam(mComponent, bitStreamInfo)) {
         std::cout << "[   WARN   ] Test Skipped \n";
@@ -672,20 +636,19 @@
     } while (!(flags & SYNC_FRAME));
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
-    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, i + 1));
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                          i + 1));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     eleStream.close();
     EXPECT_GE(mFramesReceived, 1U);
     ASSERT_EQ(mEos, true);
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2AudioDecHidlTest, EOSTest) {
+TEST_P(Codec2AudioDecHidlTest, EOSTest) {
     description("Test empty input buffer with EOS flag");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     typedef std::unique_lock<std::mutex> ULock;
     ASSERT_EQ(mComponent->start(), C2_OK);
     std::unique_ptr<C2Work> work;
@@ -723,15 +686,15 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2AudioDecHidlTest, FlushTest) {
+TEST_P(Codec2AudioDecHidlTest, FlushTest) {
     description("Tests Flush calls");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     typedef std::unique_lock<std::mutex> ULock;
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info);
 
     eleInfo.open(info);
@@ -753,8 +716,7 @@
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
     } else {
-        ASSERT_NO_FATAL_FAILURE(
-            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+        ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     }
     if (!setupConfigParam(mComponent, bitStreamInfo)) {
         std::cout << "[   WARN   ] Test Skipped \n";
@@ -768,29 +730,25 @@
     // frame after this so that the below section can be covered for all
     // components
     uint32_t numFramesFlushed = 128;
-    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, numFramesFlushed, false));
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                          numFramesFlushed, false));
     // flush
     std::list<std::unique_ptr<C2Work>> flushedWork;
-    c2_status_t err =
-        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
     uint64_t frameIndex;
     {
-        //Update mFlushedIndices based on the index received from flush()
+        // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
             frameIndex = work->input.ordinal.frameIndex.peeku();
             std::list<uint64_t>::iterator frameIndexIt =
-                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
-                          frameIndex);
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+                    std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -814,29 +772,24 @@
         index++;
     }
     if (keyFrame) {
-        ASSERT_NO_FATAL_FAILURE(
-            decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                          mFlushedIndices, mLinearPool, eleStream, &Info, index,
-                          (int)Info.size() - index));
+        ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                              mFlushedIndices, mLinearPool, eleStream, &Info, index,
+                                              (int)Info.size() - index));
     }
     eleStream.close();
-    err =
-        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
     {
-        //Update mFlushedIndices based on the index received from flush()
+        // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
             frameIndex = work->input.ordinal.frameIndex.peeku();
             std::list<uint64_t>::iterator frameIndexIt =
-                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
-                          frameIndex);
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+                    std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -848,15 +801,15 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
+TEST_P(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
     description("Decode with multiple empty input frames");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info);
 
     eleInfo.open(info);
@@ -871,15 +824,16 @@
     // and empty input frames at an interval of 5 frames.
     while (1) {
         if (!(frameId % 5)) {
-            if (!(frameId % 20)) flags = 32;
-            else flags = 0;
+            if (!(frameId % 20))
+                flags = 32;
+            else
+                flags = 0;
             bytesCount = 0;
         } else {
             if (!(eleInfo >> bytesCount)) break;
             eleInfo >> flags;
             eleInfo >> timestamp;
-            codecConfig = flags ?
-                ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+            codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
         }
         Info.push_back({bytesCount, flags, timestamp});
         frameId++;
@@ -890,8 +844,7 @@
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
     } else {
-        ASSERT_NO_FATAL_FAILURE(
-            getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
+        ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
     }
     if (!setupConfigParam(mComponent, bitStreamInfo)) {
         std::cout << "[   WARN   ] Test Skipped \n";
@@ -901,40 +854,59 @@
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
-    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                          (int)Info.size()));
 
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     if (!mEos) {
         ALOGV("Waiting for input consumption");
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     }
 
     eleStream.close();
     if (mFramesReceived != Info.size()) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
-              Info.size());
+        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, Info.size());
         ASSERT_TRUE(false);
     }
 
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
+INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2AudioDecHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+// DecodeTest with StreamIndex and EOS / No EOS
+INSTANTIATE_TEST_SUITE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
+                         testing::ValuesIn(kDecodeTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
 }  // anonymous namespace
 
 int main(int argc, char** argv) {
-    gEnv = new ComponentTestEnvironment();
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "C2 Test result = " << status;
+    kTestParameters = getTestParameters(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER);
+    for (auto params : kTestParameters) {
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "false"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "true"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "false"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "true"));
     }
-    return status;
-}
+
+    // Set the resource directory based on command line args.
+    // Test will fail to set up if the argument is not set.
+    for (int i = 1; i < argc; i++) {
+        if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
+            sResourceDir = argv[i + 1];
+            break;
+        }
+    }
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
new file mode 100644
index 0000000..a22f8cf
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the"License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an"AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalMediaC2V1_0TargetAudioDecTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="vts_media_c2_v1_0_audio_dec_test" value="/data/local/tmp/vts_media_c2_v1_0_audio_dec_test" />
+
+        <!-- Files used for audio testing -->
+        <option name="push-file" key="bbb_aac_stereo_128kbps_48000hz.aac" value="/data/local/tmp/media/bbb_aac_stereo_128kbps_48000hz.aac" />
+        <option name="push-file" key="bbb_aac_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_aac_stereo_128kbps_48000hz.info" />
+        <option name="push-file" key="bbb_aac_stereo_128kbps_48000hz_multi_frame.info" value="/data/local/tmp/media/bbb_aac_stereo_128kbps_48000hz_multi_frame.info" />
+        <option name="push-file" key="bbb_amrwb_1ch_14kbps_16000hz.amrwb" value="/data/local/tmp/media/bbb_amrwb_1ch_14kbps_16000hz.amrwb" />
+        <option name="push-file" key="bbb_amrwb_1ch_14kbps_16000hz.info" value="/data/local/tmp/media/bbb_amrwb_1ch_14kbps_16000hz.info" />
+        <option name="push-file" key="bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info" value="/data/local/tmp/media/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info" />
+        <option name="push-file" key="bbb_flac_stereo_680kbps_48000hz.flac" value="/data/local/tmp/media/bbb_flac_stereo_680kbps_48000hz.flac" />
+        <option name="push-file" key="bbb_flac_stereo_680kbps_48000hz.info" value="/data/local/tmp/media/bbb_flac_stereo_680kbps_48000hz.info" />
+        <option name="push-file" key="bbb_g711alaw_1ch_8khz.info" value="/data/local/tmp/media/bbb_g711alaw_1ch_8khz.info" />
+        <option name="push-file" key="bbb_g711alaw_1ch_8khz.raw" value="/data/local/tmp/media/bbb_g711alaw_1ch_8khz.raw" />
+        <option name="push-file" key="bbb_g711mulaw_1ch_8khz.info" value="/data/local/tmp/media/bbb_g711mulaw_1ch_8khz.info" />
+        <option name="push-file" key="bbb_g711mulaw_1ch_8khz.raw" value="/data/local/tmp/media/bbb_g711mulaw_1ch_8khz.raw" />
+        <option name="push-file" key="bbb_gsm_1ch_8khz_13kbps.info" value="/data/local/tmp/media/bbb_gsm_1ch_8khz_13kbps.info" />
+        <option name="push-file" key="bbb_gsm_1ch_8khz_13kbps.raw" value="/data/local/tmp/media/bbb_gsm_1ch_8khz_13kbps.raw" />
+        <option name="push-file" key="bbb_mp3_stereo_192kbps_48000hz.info" value="/data/local/tmp/media/bbb_mp3_stereo_192kbps_48000hz.info" />
+        <option name="push-file" key="bbb_mp3_stereo_192kbps_48000hz.mp3" value="/data/local/tmp/media/bbb_mp3_stereo_192kbps_48000hz.mp3" />
+        <option name="push-file" key="bbb_mp3_stereo_192kbps_48000hz_multi_frame.info" value="/data/local/tmp/media/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info" />
+        <option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.info" />
+        <option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.opus" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.opus" />
+        <option name="push-file" key="bbb_raw_1ch_8khz_s32le.info" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.info" />
+        <option name="push-file" key="bbb_raw_1ch_8khz_s32le.raw" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.raw" />
+        <option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.info" />
+        <option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.vorbis" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.vorbis" />
+        <option name="push-file" key="sine_amrnb_1ch_12kbps_8000hz.amrnb" value="/data/local/tmp/media/sine_amrnb_1ch_12kbps_8000hz.amrnb" />
+        <option name="push-file" key="sine_amrnb_1ch_12kbps_8000hz.info" value="/data/local/tmp/media/sine_amrnb_1ch_12kbps_8000hz.info" />
+        <option name="push-file" key="sine_amrnb_1ch_12kbps_8000hz_multi_frame.info" value="/data/local/tmp/media/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info" />
+
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="vts_media_c2_v1_0_audio_dec_test" />
+        <option name="native-test-flag" value="-P /data/local/tmp/media/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index ab6bfb2..5f3ae41 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -19,74 +19,60 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <stdio.h>
-#include <fstream>
 #include <algorithm>
+#include <fstream>
 
-#include <codec2/hidl/client.h>
 #include <C2AllocatorIon.h>
-#include <C2Config.h>
-#include <C2Debug.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <codec2/hidl/client.h>
 
 using android::C2AllocatorIon;
 
-#include <VtsHalHidlTargetTestBase.h>
-#include "media_c2_audio_hidl_test_common.h"
 #include "media_c2_hidl_test_common.h"
 
-class LinearBuffer : public C2Buffer {
-   public:
-    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
-        : C2Buffer(
-              {block->share(block->offset(), block->size(), ::C2Fence())}) {}
-};
+static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
+        kEncodeTestParameters;
 
-static ComponentTestEnvironment* gEnv = nullptr;
+// Resource directory
+static std::string sResourceDir = "";
+
+class LinearBuffer : public C2Buffer {
+  public:
+    explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
+        : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
+};
 
 namespace {
 
-class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
-    typedef ::testing::VtsHalHidlTargetTestBase Super;
-
-   public:
-    ::std::string getTestCaseInfo() const override {
-        return ::std::string() +
-                "Component: " + gEnv->getComponent().c_str() + " | " +
-                "Instance: " + gEnv->getInstance().c_str() + " | " +
-                "Res: " + gEnv->getRes().c_str();
-    }
-
+class Codec2AudioEncHidlTestBase : public ::testing::Test {
+  public:
     // google.codec2 Audio test setup
     virtual void SetUp() override {
-        Super::SetUp();
+        getParams();
         mDisableTest = false;
         ALOGV("Codec2AudioEncHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str(),
-            !bool(android::Codec2Client::CreateFromService("default", true)));
+                mInstanceName.c_str(),
+                !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
-        mListener.reset(new CodecListener(
-            [this](std::list<std::unique_ptr<C2Work>>& workItems) {
-                handleWorkDone(workItems);
-            }));
+        mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
+            handleWorkDone(workItems);
+        }));
         ASSERT_NE(mListener, nullptr);
         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
             mWorkQueue.emplace_back(new C2Work);
         }
-        mClient->createComponent(gEnv->getComponent().c_str(), mListener,
-                                 &mComponent);
+        mClient->createComponent(mComponentName, mListener, &mComponent);
         ASSERT_NE(mComponent, nullptr);
 
-        std::shared_ptr<C2AllocatorStore> store =
-            android::GetCodec2PlatformAllocatorStore();
-        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR,
-                                       &mLinearAllocator),
-                 C2_OK);
-        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
-                                                          mBlockPoolId++);
+        std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
+        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
         ASSERT_NE(mLinearPool, nullptr);
 
         mCompName = unknown_comp;
@@ -95,19 +81,13 @@
             standardComp CompName;
         };
         const StringToName kStringToName[] = {
-            {"aac", aac},
-            {"flac", flac},
-            {"opus", opus},
-            {"amrnb", amrnb},
-            {"amrwb", amrwb},
+                {"aac", aac}, {"flac", flac}, {"opus", opus}, {"amrnb", amrnb}, {"amrwb", amrwb},
         };
-        const size_t kNumStringToName =
-            sizeof(kStringToName) / sizeof(kStringToName[0]);
+        const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
 
         // Find the component type
-        std::string comp = std::string(gEnv->getComponent());
         for (size_t i = 0; i < kNumStringToName; ++i) {
-            if (strcasestr(comp.c_str(), kStringToName[i].Name)) {
+            if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
                 mCompName = kStringToName[i].CompName;
                 break;
             }
@@ -126,15 +106,17 @@
             mComponent->release();
             mComponent = nullptr;
         }
-        Super::TearDown();
     }
+
+    // Get the test parameters from GetParam call.
+    virtual void getParams() {}
+
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
         for (std::unique_ptr<C2Work>& work : workItems) {
             if (!work->worklets.empty()) {
-                workDone(mComponent, work, mFlushedIndices, mQueueLock,
-                         mQueueCondition, mWorkQueue, mEos, mCsd,
-                         mFramesReceived);
+                workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
+                         mEos, mCsd, mFramesReceived);
             }
         }
     }
@@ -147,6 +129,8 @@
         unknown_comp,
     };
 
+    std::string mInstanceName;
+    std::string mComponentName;
     bool mEos;
     bool mCsd;
     bool mDisableTest;
@@ -167,7 +151,7 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
-   protected:
+  protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
@@ -176,9 +160,8 @@
     void getInputMaxBufSize() {
         int32_t bitStreamInfo[1] = {0};
         std::vector<std::unique_ptr<C2Param>> inParams;
-        c2_status_t status = mComponent->query(
-            {}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK,
-            &inParams);
+        c2_status_t status = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
+                                               C2_DONT_BLOCK, &inParams);
         if (status != C2_OK && inParams.size() == 0) {
             ALOGE("Query MaxBufferSizeInfo failed => %d", status);
             ASSERT_TRUE(false);
@@ -191,12 +174,19 @@
         }
         mInputMaxBufSize = bitStreamInfo[0];
     }
-
 };
 
-void validateComponent(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    Codec2AudioEncHidlTest::standardComp compName, bool& disableTest) {
+class Codec2AudioEncHidlTest
+    : public Codec2AudioEncHidlTestBase,
+      public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
+};
+
+void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
+                       Codec2AudioEncHidlTest::standardComp compName, bool& disableTest) {
     // Validate its a C2 Component
     if (component->getName().find("c2") == std::string::npos) {
         ALOGE("Not a c2 component");
@@ -211,14 +201,12 @@
         return;
     }
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err =
-        component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
-                         C2_DONT_BLOCK, &queried);
+    c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+                                         C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK && queried.size() == 0) {
         ALOGE("Query media type failed => %d", c2err);
     } else {
-        std::string inputDomain =
-            ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
+        std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
         if (inputDomain.find("audio/") == std::string::npos) {
             ALOGE("Expected Audio Component");
             disableTest = true;
@@ -236,16 +224,14 @@
 }
 
 // Set Default config param.
-bool setupConfigParam(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    int32_t nChannels, int32_t nSampleRate) {
+bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
+                      int32_t nChannels, int32_t nSampleRate) {
     std::vector<std::unique_ptr<C2SettingResult>> failures;
     C2StreamSampleRateInfo::input sampleRateInfo(0u, nSampleRate);
     C2StreamChannelCountInfo::input channelCountInfo(0u, nChannels);
 
     std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
-    c2_status_t status =
-        component->config(configParam, C2_DONT_BLOCK, &failures);
+    c2_status_t status = component->config(configParam, C2_DONT_BLOCK, &failures);
     if (status == C2_OK && failures.size() == 0u) return true;
     return false;
 }
@@ -257,16 +243,11 @@
         const char* mURL;
     };
     static const CompToURL kCompToURL[] = {
-        {Codec2AudioEncHidlTest::standardComp::aac,
-         "bbb_raw_2ch_48khz_s16le.raw"},
-        {Codec2AudioEncHidlTest::standardComp::amrnb,
-         "bbb_raw_1ch_8khz_s16le.raw"},
-        {Codec2AudioEncHidlTest::standardComp::amrwb,
-         "bbb_raw_1ch_16khz_s16le.raw"},
-        {Codec2AudioEncHidlTest::standardComp::flac,
-         "bbb_raw_2ch_48khz_s16le.raw"},
-        {Codec2AudioEncHidlTest::standardComp::opus,
-         "bbb_raw_2ch_48khz_s16le.raw"},
+            {Codec2AudioEncHidlTest::standardComp::aac, "bbb_raw_2ch_48khz_s16le.raw"},
+            {Codec2AudioEncHidlTest::standardComp::amrnb, "bbb_raw_1ch_8khz_s16le.raw"},
+            {Codec2AudioEncHidlTest::standardComp::amrwb, "bbb_raw_1ch_16khz_s16le.raw"},
+            {Codec2AudioEncHidlTest::standardComp::flac, "bbb_raw_2ch_48khz_s16le.raw"},
+            {Codec2AudioEncHidlTest::standardComp::opus, "bbb_raw_2ch_48khz_s16le.raw"},
     };
 
     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@@ -278,21 +259,18 @@
 }
 
 void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
-                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::mutex& queueLock, std::condition_variable& queueCondition,
                    std::list<std::unique_ptr<C2Work>>& workQueue,
-                   std::list<uint64_t>& flushedIndices,
-                   std::shared_ptr<C2BlockPool>& linearPool,
-                   std::ifstream& eleStream, uint32_t nFrames,
-                   int32_t samplesPerFrame, int32_t nChannels,
-                   int32_t nSampleRate, bool flushed = false,
+                   std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
+                   std::ifstream& eleStream, uint32_t nFrames, int32_t samplesPerFrame,
+                   int32_t nChannels, int32_t nSampleRate, bool flushed = false,
                    bool signalEOS = true) {
     typedef std::unique_lock<std::mutex> ULock;
 
     uint32_t frameID = 0;
     uint32_t maxRetry = 0;
     int bytesCount = samplesPerFrame * nChannels * 2;
-    int32_t timestampIncr =
-        (int)(((float)samplesPerFrame / nSampleRate) * 1000000);
+    int32_t timestampIncr = (int)(((float)samplesPerFrame / nSampleRate) * 1000000);
     uint64_t timestamp = 0;
     while (1) {
         if (nFrames == 0) break;
@@ -312,8 +290,7 @@
         if (!work && (maxRetry >= MAX_RETRY)) {
             ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
         }
-        if (signalEOS && (nFrames == 1))
-            flags |= C2FrameData::FLAG_END_OF_STREAM;
+        if (signalEOS && (nFrames == 1)) flags |= C2FrameData::FLAG_END_OF_STREAM;
         if (flushed) {
             flags |= SYNC_FRAME;
             flushed = false;
@@ -330,10 +307,9 @@
         eleStream.read(data, bytesCount);
         ASSERT_EQ(eleStream.gcount(), bytesCount);
         std::shared_ptr<C2LinearBlock> block;
-        ASSERT_EQ(C2_OK, linearPool->fetchLinearBlock(
-                             bytesCount, {C2MemoryUsage::CPU_READ,
-                                          C2MemoryUsage::CPU_WRITE},
-                             &block));
+        ASSERT_EQ(C2_OK,
+                  linearPool->fetchLinearBlock(
+                          bytesCount, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
         ASSERT_TRUE(block);
         // Write View
         C2WriteView view = block->map().get();
@@ -365,27 +341,33 @@
     }
 }
 
-TEST_F(Codec2AudioEncHidlTest, validateCompName) {
-    if (mDisableTest) return;
+TEST_P(Codec2AudioEncHidlTest, validateCompName) {
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ALOGV("Checks if the given component is a valid audio component");
     validateComponent(mComponent, mCompName, mDisableTest);
     ASSERT_EQ(mDisableTest, false);
 }
 
 class Codec2AudioEncEncodeTest
-    : public Codec2AudioEncHidlTest,
-      public ::testing::WithParamInterface<std::pair<bool, int32_t>> {
+    : public Codec2AudioEncHidlTestBase,
+      public ::testing::WithParamInterface<
+              std::tuple<std::string, std::string, std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
 };
 
 TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
     ALOGV("EncodeTest");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     char mURL[512];
-    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL);
-    bool signalEOS = GetParam().first;
+    bool signalEOS = !std::get<2>(GetParam()).compare("true");
     // Ratio w.r.t to mInputMaxBufSize
-    int32_t inputMaxBufRatio = GetParam().second;
+    int32_t inputMaxBufRatio = std::stoi(std::get<3>(GetParam()));
+    ;
 
     // Setting default sampleRate
     int32_t nChannels = 2;
@@ -414,10 +396,9 @@
         default:
             ASSERT_TRUE(false);
     }
-    int32_t samplesPerFrame =
-        ((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2));
-    ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS,
-          mInputMaxBufSize, samplesPerFrame);
+    int32_t samplesPerFrame = ((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2));
+    ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS, mInputMaxBufSize,
+          samplesPerFrame);
 
     if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
         std::cout << "[   WARN   ] Test Skipped \n";
@@ -429,26 +410,21 @@
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ALOGV("mURL : %s", mURL);
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mLinearPool, eleStream, numFrames,
-                      samplesPerFrame, nChannels, nSampleRate, false,
-                      signalEOS));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(
+            mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices, mLinearPool,
+            eleStream, numFrames, samplesPerFrame, nChannels, nSampleRate, false, signalEOS));
 
     // If EOS is not sent, sending empty input with EOS flag
     if (!signalEOS) {
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
-        ASSERT_NO_FATAL_FAILURE(
-            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
-                            C2FrameData::FLAG_END_OF_STREAM, false));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                                                C2FrameData::FLAG_END_OF_STREAM, false));
         numFrames += 1;
     }
 
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     eleStream.close();
     if (mFramesReceived != numFrames) {
         ALOGE("Input buffer count and Output buffer count mismatch");
@@ -465,18 +441,9 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-// EncodeTest with EOS / No EOS and inputMaxBufRatio
-// inputMaxBufRatio is ratio w.r.t. to mInputMaxBufSize
-INSTANTIATE_TEST_CASE_P(EncodeTest, Codec2AudioEncEncodeTest,
-                        ::testing::Values(std::make_pair(false, 1),
-                                          std::make_pair(false, 2),
-                                          std::make_pair(true, 1),
-                                          std::make_pair(true, 2)));
-
-
-TEST_F(Codec2AudioEncHidlTest, EOSTest) {
+TEST_P(Codec2AudioEncHidlTest, EOSTest) {
     description("Test empty input buffer with EOS flag");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ASSERT_EQ(mComponent->start(), C2_OK);
 
     typedef std::unique_lock<std::mutex> ULock;
@@ -514,13 +481,13 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2AudioEncHidlTest, FlushTest) {
+TEST_P(Codec2AudioEncHidlTest, FlushTest) {
     description("Test Request for flush");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     typedef std::unique_lock<std::mutex> ULock;
     char mURL[512];
-    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL);
 
     // Setting default configuration
@@ -570,29 +537,24 @@
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ALOGV("mURL : %s", mURL);
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mLinearPool, eleStream, numFramesFlushed,
-                      samplesPerFrame, nChannels, nSampleRate));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, numFramesFlushed,
+                                          samplesPerFrame, nChannels, nSampleRate));
     std::list<std::unique_ptr<C2Work>> flushedWork;
-    c2_status_t err =
-        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
     uint64_t frameIndex;
     {
-        //Update mFlushedIndices based on the index received from flush()
+        // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
             frameIndex = work->input.ordinal.frameIndex.peeku();
             std::list<uint64_t>::iterator frameIndexIt =
-                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
-                          frameIndex);
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+                    std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -601,29 +563,24 @@
         }
     }
     mFlushedIndices.clear();
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mLinearPool, eleStream,
-                      numFrames - numFramesFlushed, samplesPerFrame,
-                      nChannels, nSampleRate, true));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream,
+                                          numFrames - numFramesFlushed, samplesPerFrame, nChannels,
+                                          nSampleRate, true));
     eleStream.close();
-    err =
-        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
     {
-        //Update mFlushedIndices based on the index received from flush()
+        // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
             frameIndex = work->input.ordinal.frameIndex.peeku();
             std::list<uint64_t>::iterator frameIndexIt =
-                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
-                          frameIndex);
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+                    std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -635,17 +592,39 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
+INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2AudioEncHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+// EncodeTest with EOS / No EOS and inputMaxBufRatio
+// inputMaxBufRatio is ratio w.r.t. to mInputMaxBufSize
+INSTANTIATE_TEST_SUITE_P(EncodeTest, Codec2AudioEncEncodeTest,
+                         testing::ValuesIn(kEncodeTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
 }  // anonymous namespace
 
 int main(int argc, char** argv) {
-    gEnv = new ComponentTestEnvironment();
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "C2 Test result = " << status;
+    kTestParameters = getTestParameters(C2Component::DOMAIN_AUDIO, C2Component::KIND_ENCODER);
+    for (auto params : kTestParameters) {
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "1"));
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "2"));
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "1"));
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "2"));
     }
-    return status;
+
+    // Set the resource directory based on command line args.
+    // Test will fail to set up if the argument is not set.
+    for (int i = 1; i < argc; i++) {
+        if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
+            sResourceDir = argv[i + 1];
+            break;
+        }
+    }
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
 }
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.xml b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.xml
new file mode 100644
index 0000000..2e37111
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the"License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an"AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalMediaC2V1_0TargetAudioEncTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="vts_media_c2_v1_0_audio_enc_test" value="/data/local/tmp/vts_media_c2_v1_0_audio_enc_test" />
+
+        <!-- Files used for audio testing -->
+        <option name="push-file" key="bbb_raw_2ch_48khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_2ch_48khz_s16le.raw" />
+        <option name="push-file" key="bbb_raw_1ch_8khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s16le.raw" />
+        <option name="push-file" key="bbb_raw_1ch_16khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_1ch_16khz_s16le.raw" />
+        <option name="push-file" key="bbb_raw_2ch_48khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_2ch_48khz_s16le.raw" />
+        <option name="push-file" key="bbb_raw_2ch_48khz_s16le.raw" value="/data/local/tmp/media/bbb_raw_2ch_48khz_s16le.raw" />
+
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="vts_media_c2_v1_0_audio_enc_test" />
+        <option name="native-test-flag" value="-P /data/local/tmp/media/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/common/Android.bp b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
index a011ba3..f9ec5ae 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
@@ -24,10 +24,14 @@
     ],
 
     static_libs: [
+        "libgtest",
         "VtsHalMediaC2V1_0CommonUtil",
     ],
 
     shared_libs: [
         "libcodec2_client",
     ],
+    test_suites: [
+        "vts",
+    ],
 }
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 f2f579c..ac510c5 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/README.md
+++ b/media/codec2/hidl/1.0/vts/functional/common/README.md
@@ -3,34 +3,22 @@
 ## master :
 Functionality of master is to enumerate all the Codec2 components available in C2 media service.
 
-usage: `VtsHalMediaC2V1_0TargetMasterTest -I default`
+usage: `atest VtsHalMediaC2V1_0TargetMasterTest`
 
 ## 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: `atest VtsHalMediaC2V1_0TargetComponentTest`
 
 ## 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.)
 
-usage: `VtsHalMediaC2V1_0TargetAudioDecTest -I default -C <comp name> -P <path to resource files>`
+usage: `atest VtsHalMediaC2V1_0TargetAudioDecTest`
 
-usage: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C <comp name> -P <path to resource files>`
-
-example: `VtsHalMediaC2V1_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /data/local/tmp/media/`
-
-example: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /data/local/tmp/media/`
+usage: `atest VtsHalMediaC2V1_0TargetAudioEncTest`
 
 ## 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/`
-
+usage: `atest VtsHalMediaC2V1_0TargetVideoDecTest`
+usage: `atest VtsHalMediaC2V1_0TargetVideoEncTest`
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index 2f02913..da8225c 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -22,16 +22,10 @@
 
 #include <android/hardware/media/c2/1.0/IComponentStore.h>
 
-void ComponentTestEnvironment::registerTestServices() {
-    registerTestService<::android::hardware::media::c2::V1_0::
-                        IComponentStore>();
-}
-
 // Test the codecs for NullBuffer, Empty Input Buffer with(out) flags set
-void testInputBuffer(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
-    uint32_t flags, bool isNullBuffer) {
+void testInputBuffer(const std::shared_ptr<android::Codec2Client::Component>& component,
+                     std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
+                     uint32_t flags, bool isNullBuffer) {
     std::unique_ptr<C2Work> work;
     {
         typedef std::unique_lock<std::mutex> ULock;
@@ -61,10 +55,8 @@
 }
 
 // Wait for all the inputs to be consumed by the plugin.
-void waitOnInputConsumption(std::mutex& queueLock,
-                            std::condition_variable& queueCondition,
-                            std::list<std::unique_ptr<C2Work>>& workQueue,
-                            size_t bufferCount) {
+void waitOnInputConsumption(std::mutex& queueLock, std::condition_variable& queueCondition,
+                            std::list<std::unique_ptr<C2Work>>& workQueue, size_t bufferCount) {
     typedef std::unique_lock<std::mutex> ULock;
     uint32_t queueSize;
     uint32_t maxRetry = 0;
@@ -85,29 +77,25 @@
 }
 
 // process onWorkDone received by Listener
-void workDone(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
-    std::mutex& queueLock, std::condition_variable& queueCondition,
-    std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
-    uint32_t& framesReceived) {
+void workDone(const std::shared_ptr<android::Codec2Client::Component>& component,
+              std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
+              std::mutex& queueLock, std::condition_variable& queueCondition,
+              std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
+              uint32_t& framesReceived) {
     // handle configuration changes in work done
     if (work->worklets.front()->output.configUpdate.size() != 0) {
         ALOGV("Config Update");
         std::vector<std::unique_ptr<C2Param>> updates =
-            std::move(work->worklets.front()->output.configUpdate);
+                std::move(work->worklets.front()->output.configUpdate);
         std::vector<C2Param*> configParam;
         std::vector<std::unique_ptr<C2SettingResult>> failures;
         for (size_t i = 0; i < updates.size(); ++i) {
             C2Param* param = updates[i].get();
             if (param->index() == C2StreamInitDataInfo::output::PARAM_TYPE) {
                 csd = true;
-            } else if ((param->index() ==
-                        C2StreamSampleRateInfo::output::PARAM_TYPE) ||
-                       (param->index() ==
-                        C2StreamChannelCountInfo::output::PARAM_TYPE) ||
-                       (param->index() ==
-                        C2StreamPictureSizeInfo::output::PARAM_TYPE)) {
+            } else if ((param->index() == C2StreamSampleRateInfo::output::PARAM_TYPE) ||
+                       (param->index() == C2StreamChannelCountInfo::output::PARAM_TYPE) ||
+                       (param->index() == C2StreamPictureSizeInfo::output::PARAM_TYPE)) {
                 configParam.push_back(param);
             }
         }
@@ -116,8 +104,7 @@
     }
     if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
         framesReceived++;
-        eos = (work->worklets.front()->output.flags &
-               C2FrameData::FLAG_END_OF_STREAM) != 0;
+        eos = (work->worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
         auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(),
                                       work->input.ordinal.frameIndex.peeku());
         ALOGV("WorkDone: frameID received %d",
@@ -128,7 +115,8 @@
             typedef std::unique_lock<std::mutex> ULock;
             ULock l(queueLock);
             workQueue.push_back(std::move(work));
-            if (!flushedIndices.empty()) {
+            if (!flushedIndices.empty() &&
+                (frameIndexIt != flushedIndices.end())) {
                 flushedIndices.erase(frameIndexIt);
             }
             queueCondition.notify_all();
@@ -143,3 +131,33 @@
 
     return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
 }
+
+// Return all test parameters, a list of tuple of <instance, component>
+const std::vector<std::tuple<std::string, std::string>>& getTestParameters() {
+    return getTestParameters(C2Component::DOMAIN_OTHER, C2Component::KIND_OTHER);
+}
+
+// Return all test parameters, a list of tuple of <instance, component> with matching domain and
+// kind.
+const std::vector<std::tuple<std::string, std::string>>& getTestParameters(
+        C2Component::domain_t domain, C2Component::kind_t kind) {
+    static std::vector<std::tuple<std::string, std::string>> parameters;
+
+    auto instances = android::Codec2Client::GetServiceNames();
+    for (std::string instance : instances) {
+        std::shared_ptr<android::Codec2Client> client =
+                android::Codec2Client::CreateFromService(instance.c_str());
+        std::vector<C2Component::Traits> components = client->listComponents();
+        for (C2Component::Traits traits : components) {
+            if (instance.compare(traits.owner)) continue;
+            if (domain != C2Component::DOMAIN_OTHER &&
+                (traits.domain != domain || traits.kind != kind)) {
+                continue;
+            }
+
+            parameters.push_back(std::make_tuple(instance, traits.name));
+        }
+    }
+
+    return parameters;
+}
\ No newline at end of file
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 23e332a..4b5e0a6 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
@@ -22,31 +22,34 @@
 
 #include <codec2/hidl/client.h>
 #include <getopt.h>
+#include <gtest/gtest.h>
 #include <hidl/HidlSupport.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <chrono>
 
 #define MAX_RETRY 20
 #define TIME_OUT 400ms
 #define MAX_INPUT_BUFFERS 8
 
-using ::android::hardware::Void;
-using ::android::hardware::Return;
-using ::android::hardware::hidl_vec;
 using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using namespace ::std::chrono;
+
+static std::vector<std::tuple<std::string, std::string>> kTestParameters;
 
 /*
  * Handle Callback functions onWorkDone(), onTripped(),
  * onError(), onDeath(), onFramesRendered()
  */
 struct CodecListener : public android::Codec2Client::Listener {
-   public:
+  public:
     CodecListener(
-        const std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> fn =
-            nullptr)
+            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 {
+    virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component>& comp,
+                            std::list<std::unique_ptr<C2Work>>& workItems) override {
         /* TODO */
         ALOGD("onWorkDone called");
         (void)comp;
@@ -54,40 +57,34 @@
     }
 
     virtual void onTripped(
-        const std::weak_ptr<android::Codec2Client::Component>& comp,
-        const std::vector<std::shared_ptr<C2SettingResult>>& settingResults)
-        override {
+            const std::weak_ptr<android::Codec2Client::Component>& comp,
+            const std::vector<std::shared_ptr<C2SettingResult>>& settingResults) override {
         /* TODO */
         (void)comp;
         (void)settingResults;
     }
 
-    virtual void onError(
-        const std::weak_ptr<android::Codec2Client::Component>& comp,
-        uint32_t errorCode) override {
+    virtual void onError(const std::weak_ptr<android::Codec2Client::Component>& comp,
+                         uint32_t errorCode) override {
         /* TODO */
         (void)comp;
         ALOGD("onError called");
         if (errorCode != 0) ALOGE("Error : %u", errorCode);
     }
 
-    virtual void onDeath(
-        const std::weak_ptr<android::Codec2Client::Component>& comp) override {
+    virtual void onDeath(const std::weak_ptr<android::Codec2Client::Component>& comp) override {
         /* TODO */
         (void)comp;
     }
 
-    virtual void onInputBufferDone(
-        uint64_t frameIndex, size_t arrayIndex) override {
+    virtual void onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) override {
         /* TODO */
         (void)frameIndex;
         (void)arrayIndex;
     }
 
-    virtual void onFrameRendered(
-        uint64_t bufferQueueId,
-        int32_t slotId,
-        int64_t timestampNs) override {
+    virtual void onFrameRendered(uint64_t bufferQueueId, int32_t slotId,
+                                 int64_t timestampNs) override {
         /* TODO */
         (void)bufferQueueId;
         (void)slotId;
@@ -99,96 +96,30 @@
     std::function<void(std::list<std::unique_ptr<C2Work>>& workItems)> callBack;
 };
 
-// A class for test environment setup
-class ComponentTestEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   private:
-    typedef ::testing::VtsHalHidlTargetTestEnvBase Super;
+// Return all test parameters, a list of tuple of <instance, component>.
+const std::vector<std::tuple<std::string, std::string>>& getTestParameters();
 
-   public:
-    virtual void registerTestServices() override;
-
-    ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
-
-    void setComponent(const char* _component) { component = _component; }
-
-    void setInstance(const char* _instance) { instance = _instance; }
-
-    void setRes(const char* _res) { res = _res; }
-
-    const hidl_string getInstance() const { return instance; }
-
-    const hidl_string getComponent() const { return component; }
-
-    const hidl_string getRes() const { return res; }
-
-    int initFromOptions(int argc, char** argv) {
-        static struct option options[] = {
-            {"instance", required_argument, 0, 'I'},
-            {"component", required_argument, 0, 'C'},
-            {"res", required_argument, 0, 'P'},
-            {0, 0, 0, 0}};
-
-        while (true) {
-            int index = 0;
-            int c = getopt_long(argc, argv, "I:C:P:", options, &index);
-            if (c == -1) {
-                break;
-            }
-
-            switch (c) {
-                case 'I':
-                    setInstance(optarg);
-                    break;
-                case 'C':
-                    setComponent(optarg);
-                    break;
-                case 'P':
-                    setRes(optarg);
-                    break;
-                case '?':
-                    break;
-            }
-        }
-
-        if (optind < argc) {
-            fprintf(stderr,
-                    "unrecognized option: %s\n\n"
-                    "usage: %s <gtest options> <test options>\n\n"
-                    "test options are:\n\n"
-                    "-I, --instance: software for C2 components, else default\n"
-                    "-C, --component: C2 component to test\n"
-                    "-P, --res: Resource files directory location\n",
-                    argv[optind ?: 1], argv[0]);
-            return 2;
-        }
-        return 0;
-    }
-
-   private:
-    hidl_string instance;
-    hidl_string component;
-    hidl_string res;
-};
+// Return all test parameters, a list of tuple of <instance, component> with matching domain and
+// kind.
+const std::vector<std::tuple<std::string, std::string>>& getTestParameters(
+        C2Component::domain_t domain, C2Component::kind_t kind);
 
 /*
  * common functions declarations
  */
-void testInputBuffer(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
-    uint32_t flags, bool isNullBuffer);
+void testInputBuffer(const std::shared_ptr<android::Codec2Client::Component>& component,
+                     std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
+                     uint32_t flags, bool isNullBuffer);
 
-void waitOnInputConsumption(std::mutex& queueLock,
-                            std::condition_variable& queueCondition,
+void waitOnInputConsumption(std::mutex& queueLock, std::condition_variable& queueCondition,
                             std::list<std::unique_ptr<C2Work>>& workQueue,
                             size_t bufferCount = MAX_INPUT_BUFFERS);
 
-void workDone(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
-    std::mutex& queueLock, std::condition_variable& queueCondition,
-    std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
-    uint32_t& framesReceived);
+void workDone(const std::shared_ptr<android::Codec2Client::Component>& component,
+              std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
+              std::mutex& queueLock, std::condition_variable& queueCondition,
+              std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
+              uint32_t& framesReceived);
 
 int64_t getNowUs();
 
diff --git a/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
index 9dc541c..6122225 100644
--- a/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
@@ -19,11 +19,11 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 
 #include <C2Config.h>
 #include <codec2/hidl/client.h>
 
-#include <VtsHalHidlTargetTestBase.h>
 #include "media_c2_hidl_test_common.h"
 
 /* Time_Out for start(), stop(), reset(), release(), flush(), queue() are
@@ -31,50 +31,45 @@
  * extra in case of timeout is 500ms, 1ms extra in case timeout is 1ms/5ms. All
  * timeout is calculated in us.
  */
-#define START_TIME_OUT                  550000
-#define STOP_TIME_OUT                   550000
-#define RESET_TIME_OUT                  550000
-#define RELEASE_TIME_OUT                550000
-#define FLUSH_TIME_OUT                  6000
-#define QUEUE_TIME_OUT                  2000
+#define START_TIME_OUT 550000
+#define STOP_TIME_OUT 550000
+#define RESET_TIME_OUT 550000
+#define RELEASE_TIME_OUT 550000
+#define FLUSH_TIME_OUT 6000
+#define QUEUE_TIME_OUT 2000
 
 // Time_Out for config(), query(), querySupportedParams() are defined in
 // hardware/interfaces/media/c2/1.0/IConfigurable.hal.
-#define CONFIG_TIME_OUT                 6000
-#define QUERY_TIME_OUT                  6000
-#define QUERYSUPPORTEDPARAMS_TIME_OUT   2000
+#define CONFIG_TIME_OUT 6000
+#define QUERY_TIME_OUT 6000
+#define QUERYSUPPORTEDPARAMS_TIME_OUT 2000
 
-#define CHECK_TIMEOUT(timeConsumed, TIME_OUT, FuncName)          \
-    if (timeConsumed > TIME_OUT) {                               \
-        ALOGW(                                                   \
-            "TIMED_OUT %s  timeConsumed=%" PRId64 " us is "      \
-            "greater than threshold %d us",                      \
-            FuncName, timeConsumed, TIME_OUT);                   \
+#define CHECK_TIMEOUT(timeConsumed, TIME_OUT, FuncName) \
+    if (timeConsumed > TIME_OUT) {                      \
+        ALOGW("TIMED_OUT %s  timeConsumed=%" PRId64     \
+              " us is "                                 \
+              "greater than threshold %d us",           \
+              FuncName, timeConsumed, TIME_OUT);        \
     }
 
-static ComponentTestEnvironment* gEnv = nullptr;
-
 namespace {
 
-// google.codec2 Component test setup
-class Codec2ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
-    typedef ::testing::VtsHalHidlTargetTestBase Super;
+static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
+        kInputTestParameters;
 
-   public:
+// google.codec2 Component test setup
+class Codec2ComponentHidlTestBase : public ::testing::Test {
+  public:
     virtual void SetUp() override {
-        Super::SetUp();
+        getParams();
         mEos = false;
-        mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str());
+        mClient = android::Codec2Client::CreateFromService(mInstanceName.c_str());
         ASSERT_NE(mClient, nullptr);
-        mListener.reset(new CodecListener(
-            [this](std::list<std::unique_ptr<C2Work>>& workItems) {
-                handleWorkDone(workItems);
-            }));
+        mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
+            handleWorkDone(workItems);
+        }));
         ASSERT_NE(mListener, nullptr);
-        mClient->createComponent(gEnv->getComponent().c_str(), mListener,
-                                 &mComponent);
+        mClient->createComponent(mComponentName.c_str(), mListener, &mComponent);
         ASSERT_NE(mComponent, nullptr);
         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
             mWorkQueue.emplace_back(new C2Work);
@@ -90,8 +85,11 @@
             mComponent->release();
             mComponent = nullptr;
         }
-        Super::TearDown();
     }
+
+    // Get the test parameters from GetParam call.
+    virtual void getParams() {}
+
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
         for (std::unique_ptr<C2Work>& work : workItems) {
@@ -99,12 +97,14 @@
                 bool mCsd = false;
                 uint32_t mFramesReceived = 0;
                 std::list<uint64_t> mFlushedIndices;
-                workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition,
-                         mWorkQueue, mEos, mCsd, mFramesReceived);
+                workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
+                         mEos, mCsd, mFramesReceived);
             }
         }
     }
 
+    std::string mInstanceName;
+    std::string mComponentName;
     bool mEos;
     std::mutex mQueueLock;
     std::condition_variable mQueueCondition;
@@ -114,14 +114,23 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
-   protected:
+  protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
 };
 
+class Codec2ComponentHidlTest
+    : public Codec2ComponentHidlTestBase,
+      public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
+};
+
 // Test Empty Flush
-TEST_F(Codec2ComponentHidlTest, EmptyFlush) {
+TEST_P(Codec2ComponentHidlTest, EmptyFlush) {
     ALOGV("Empty Flush Test");
     c2_status_t err = mComponent->start();
     ASSERT_EQ(err, C2_OK);
@@ -137,7 +146,7 @@
 }
 
 // Test Queue Empty Work
-TEST_F(Codec2ComponentHidlTest, QueueEmptyWork) {
+TEST_P(Codec2ComponentHidlTest, QueueEmptyWork) {
     ALOGV("Queue Empty Work Test");
     c2_status_t err = mComponent->start();
     ASSERT_EQ(err, C2_OK);
@@ -151,7 +160,7 @@
 }
 
 // Test Component Configuration
-TEST_F(Codec2ComponentHidlTest, Config) {
+TEST_P(Codec2ComponentHidlTest, Config) {
     ALOGV("Configuration Test");
 
     C2String name = mComponent->getName();
@@ -180,7 +189,7 @@
 }
 
 // Test Multiple Start Stop Reset Test
-TEST_F(Codec2ComponentHidlTest, MultipleStartStopReset) {
+TEST_P(Codec2ComponentHidlTest, MultipleStartStopReset) {
     ALOGV("Multiple Start Stop and Reset Test");
 
     for (size_t i = 0; i < MAX_RETRY; i++) {
@@ -202,21 +211,21 @@
 }
 
 // Test Component Release API
-TEST_F(Codec2ComponentHidlTest, MultipleRelease) {
+TEST_P(Codec2ComponentHidlTest, MultipleRelease) {
     ALOGV("Multiple Release Test");
     c2_status_t err = mComponent->start();
     ASSERT_EQ(err, C2_OK);
 
     // Query Component Domain Type
     std::vector<std::unique_ptr<C2Param>> queried;
-    err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
-                            C2_DONT_BLOCK, &queried);
+    err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK,
+                            &queried);
     EXPECT_NE(queried.size(), 0u);
 
     // Configure Component Domain
     std::vector<std::unique_ptr<C2SettingResult>> failures;
     C2PortMediaTypeSetting::input* portMediaType =
-        C2PortMediaTypeSetting::input::From(queried[0].get());
+            C2PortMediaTypeSetting::input::From(queried[0].get());
     err = mComponent->config({portMediaType}, C2_DONT_BLOCK, &failures);
     ASSERT_EQ(err, C2_OK);
     ASSERT_EQ(failures.size(), 0u);
@@ -226,40 +235,8 @@
     }
 }
 
-class Codec2ComponentInputTests : public Codec2ComponentHidlTest,
-        public ::testing::WithParamInterface<std::pair<uint32_t, bool> > {
-};
-
-TEST_P(Codec2ComponentInputTests, InputBufferTest) {
-    description("Tests for different inputs");
-
-    uint32_t flags = GetParam().first;
-    bool isNullBuffer = GetParam().second;
-    if (isNullBuffer) ALOGD("Testing for null input buffer with flag : %u", flags);
-    else ALOGD("Testing for empty input buffer with flag : %u", flags);
-    mEos = false;
-    ASSERT_EQ(mComponent->start(), C2_OK);
-    ASSERT_NO_FATAL_FAILURE(testInputBuffer(
-        mComponent, mQueueLock, mWorkQueue, flags, isNullBuffer));
-
-    ALOGD("Waiting for input consumption");
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
-
-    if (flags == C2FrameData::FLAG_END_OF_STREAM) ASSERT_EQ(mEos, true);
-    ASSERT_EQ(mComponent->stop(), C2_OK);
-    ASSERT_EQ(mComponent->reset(), C2_OK);
-}
-
-INSTANTIATE_TEST_CASE_P(NonStdInputs, Codec2ComponentInputTests, ::testing::Values(
-    std::make_pair(0, true),
-    std::make_pair(C2FrameData::FLAG_END_OF_STREAM, true),
-    std::make_pair(0, false),
-    std::make_pair(C2FrameData::FLAG_CODEC_CONFIG, false),
-    std::make_pair(C2FrameData::FLAG_END_OF_STREAM, false)));
-
 // Test API's Timeout
-TEST_F(Codec2ComponentHidlTest, Timeout) {
+TEST_P(Codec2ComponentHidlTest, Timeout) {
     ALOGV("Timeout Test");
     c2_status_t err = C2_OK;
 
@@ -285,10 +262,8 @@
     startTime = getNowUs();
     err = mComponent->querySupportedParams(&params);
     timeConsumed = getNowUs() - startTime;
-    CHECK_TIMEOUT(timeConsumed, QUERYSUPPORTEDPARAMS_TIME_OUT,
-                  "querySupportedParams()");
-    ALOGV("mComponent->querySupportedParams() timeConsumed=%" PRId64 " us",
-          timeConsumed);
+    CHECK_TIMEOUT(timeConsumed, QUERYSUPPORTEDPARAMS_TIME_OUT, "querySupportedParams()");
+    ALOGV("mComponent->querySupportedParams() timeConsumed=%" PRId64 " us", timeConsumed);
     ASSERT_EQ(err, C2_OK);
 
     std::vector<std::unique_ptr<C2Param>> queried;
@@ -301,8 +276,8 @@
         CHECK_TIMEOUT(timeConsumed, QUERY_TIME_OUT, "query()");
         EXPECT_NE(queried.size(), 0u);
         EXPECT_EQ(err, C2_OK);
-        ALOGV("mComponent->query() for %s timeConsumed=%" PRId64 " us",
-              p->name().c_str(), timeConsumed);
+        ALOGV("mComponent->query() for %s timeConsumed=%" PRId64 " us", p->name().c_str(),
+              timeConsumed);
 
         startTime = getNowUs();
         err = mComponent->config({queried[0].get()}, C2_DONT_BLOCK, &failures);
@@ -310,8 +285,8 @@
         CHECK_TIMEOUT(timeConsumed, CONFIG_TIME_OUT, "config()");
         ASSERT_EQ(err, C2_OK);
         ASSERT_EQ(failures.size(), 0u);
-        ALOGV("mComponent->config() for %s timeConsumed=%" PRId64 " us",
-              p->name().c_str(), timeConsumed);
+        ALOGV("mComponent->config() for %s timeConsumed=%" PRId64 " us", p->name().c_str(),
+              timeConsumed);
     }
 
     std::list<std::unique_ptr<C2Work>> workList;
@@ -340,22 +315,68 @@
     ALOGV("mComponent->release() timeConsumed=%" PRId64 " us", timeConsumed);
     CHECK_TIMEOUT(timeConsumed, RELEASE_TIME_OUT, "release()");
     ASSERT_EQ(err, C2_OK);
-
 }
 
+class Codec2ComponentInputTests
+    : public Codec2ComponentHidlTestBase,
+      public ::testing::WithParamInterface<
+              std::tuple<std::string, std::string, std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
+};
+
+TEST_P(Codec2ComponentInputTests, InputBufferTest) {
+    description("Tests for different inputs");
+
+    uint32_t flags = std::stoul(std::get<2>(GetParam()));
+    bool isNullBuffer = !std::get<3>(GetParam()).compare("true");
+    if (isNullBuffer)
+        ALOGD("Testing for null input buffer with flag : %u", flags);
+    else
+        ALOGD("Testing for empty input buffer with flag : %u", flags);
+    mEos = false;
+    ASSERT_EQ(mComponent->start(), C2_OK);
+    ASSERT_NO_FATAL_FAILURE(
+            testInputBuffer(mComponent, mQueueLock, mWorkQueue, flags, isNullBuffer));
+
+    ALOGD("Waiting for input consumption");
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+
+    if (flags == C2FrameData::FLAG_END_OF_STREAM) ASSERT_EQ(mEos, true);
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+    ASSERT_EQ(mComponent->reset(), C2_OK);
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2ComponentHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_CASE_P(NonStdInputs, Codec2ComponentInputTests,
+                        testing::ValuesIn(kInputTestParameters),
+                        android::hardware::PrintInstanceTupleNameToString<>);
 }  // anonymous namespace
 
 // TODO: Add test for Invalid work,
 // TODO: Add test for Invalid states
 int main(int argc, char** argv) {
-    gEnv = new ComponentTestEnvironment();
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        status = RUN_ALL_TESTS();
-        LOG(INFO) << "C2 Test result = " << status;
+    kTestParameters = getTestParameters();
+    for (auto params : kTestParameters) {
+        kInputTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "true"));
+        kInputTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params),
+                                std::to_string(C2FrameData::FLAG_END_OF_STREAM), "true"));
+        kInputTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "false"));
+        kInputTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params),
+                                std::to_string(C2FrameData::FLAG_CODEC_CONFIG), "false"));
+        kInputTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params),
+                                std::to_string(C2FrameData::FLAG_END_OF_STREAM), "false"));
     }
-    return status;
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
 }
diff --git a/media/codec2/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp b/media/codec2/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
index e88fbc7..fb1c291 100644
--- a/media/codec2/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/master/VtsHalMediaC2V1_0TargetMasterTest.cpp
@@ -19,30 +19,25 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <codec2/hidl/client.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 #include "media_c2_hidl_test_common.h"
 
-static ComponentTestEnvironment* gEnv = nullptr;
-
 namespace {
 
 // google.codec2 Master test setup
-class Codec2MasterHalTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
-    typedef ::testing::VtsHalHidlTargetTestBase Super;
-
-   public:
+class Codec2MasterHalTest : public ::testing::TestWithParam<std::string> {
+  public:
     virtual void SetUp() override {
-        Super::SetUp();
-        mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str());
+        mClient = android::Codec2Client::CreateFromService(GetParam().c_str());
         ASSERT_NE(mClient, nullptr);
     }
 
-   protected:
+  protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
@@ -58,15 +53,14 @@
 }
 
 // List Components
-TEST_F(Codec2MasterHalTest, ListComponents) {
+TEST_P(Codec2MasterHalTest, ListComponents) {
     ALOGV("ListComponents Test");
 
     C2String name = mClient->getName();
     EXPECT_NE(name.empty(), true) << "Invalid Codec2Client Name";
 
     // Get List of components from all known services
-    const std::vector<C2Component::Traits> listTraits =
-        mClient->ListComponents();
+    const std::vector<C2Component::Traits> listTraits = mClient->ListComponents();
 
     if (listTraits.size() == 0)
         ALOGE("Warning, ComponentInfo list empty");
@@ -79,24 +73,16 @@
             ASSERT_NE(listener, nullptr);
 
             // Create component from all known services
-            component = mClient->CreateComponentByName(
-                listTraits[i].name.c_str(), listener, &mClient);
-            ASSERT_NE(component, nullptr) << "Create component failed for "
-                                          << listTraits[i].name.c_str();
+            component =
+                    mClient->CreateComponentByName(listTraits[i].name.c_str(), listener, &mClient);
+            ASSERT_NE(component, nullptr)
+                    << "Create component failed for " << listTraits[i].name.c_str();
         }
     }
 }
 
 }  // anonymous namespace
 
-int main(int argc, char** argv) {
-    gEnv = new ComponentTestEnvironment();
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        status = RUN_ALL_TESTS();
-        LOG(INFO) << "C2 Test result = " << status;
-    }
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2MasterHalTest,
+                         testing::ValuesIn(android::Codec2Client::GetServiceNames()),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.info
new file mode 100644
index 0000000..9ea1ffa
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.info
@@ -0,0 +1,352 @@
+73 0 0
+159 16 41000
+103 16 41000
+34 0 41000
+30 0 83000
+30 0 125000
+30 0 166000
+1 0 208000
+105 0 250000
+54 0 291000
+65 0 333000
+1 0 375000
+239 0 416000
+1373 16 458000
+263 16 458000
+133 0 458000
+109 0 500000
+127 0 541000
+1 0 583000
+134 0 625000
+159 0 666000
+131 0 708000
+1 0 750000
+4420 16 791000
+349 16 791000
+151 0 791000
+1 0 833000
+120 0 875000
+1 0 916000
+3203 16 958000
+433 16 958000
+125 0 958000
+1 0 1000000
+107 0 1041000
+1 0 1083000
+3832 16 1125000
+541 16 1125000
+116 0 1125000
+1 0 1166000
+115 0 1208000
+1 0 1250000
+3777 16 1291000
+495 16 1291000
+109 0 1291000
+1 0 1333000
+79 0 1375000
+1 0 1416000
+3906 16 1458000
+539 16 1458000
+149 0 1458000
+1 0 1500000
+112 0 1541000
+1 0 1583000
+5495 16 1625000
+594 16 1625000
+392 0 1625000
+235 0 1666000
+170 0 1708000
+1 0 1750000
+384 0 1791000
+378 0 1833000
+120 0 1875000
+1 0 1916000
+16843 16 1958000
+1951 16 1958000
+774 0 1958000
+831 0 2000000
+560 0 2041000
+489 0 2083000
+345 0 2125000
+243 0 2166000
+260 0 2208000
+1 0 2250000
+498 0 2291000
+463 0 2333000
+414 0 2375000
+341 0 2416000
+262 0 2458000
+194 0 2500000
+85 0 2541000
+1 0 2583000
+11253 16 2625000
+1561 16 2625000
+250 0 2625000
+402 0 2666000
+454 0 2708000
+350 0 2750000
+316 0 2791000
+164 0 2833000
+108 0 2875000
+1 0 2916000
+246 0 2958000
+586 0 3000000
+493 0 3041000
+363 0 3083000
+325 0 3125000
+170 0 3166000
+78 0 3208000
+40 0 3250000
+15630 16 3291000
+2228 16 3291000
+346 0 3291000
+707 0 3333000
+685 0 3375000
+582 0 3416000
+473 0 3458000
+249 0 3500000
+177 0 3541000
+1 0 3583000
+541 0 3625000
+834 0 3666000
+614 0 3708000
+473 0 3750000
+365 0 3791000
+211 0 3833000
+91 0 3875000
+1 0 3916000
+8384 16 3958000
+1138 16 3958000
+256 0 3958000
+377 0 4000000
+316 0 4041000
+267 0 4083000
+119 0 4125000
+1 0 4166000
+319 0 4208000
+390 0 4250000
+243 0 4291000
+203 0 4333000
+110 0 4375000
+1 0 4416000
+11302 16 4458000
+1527 16 4458000
+408 0 4458000
+507 0 4500000
+350 0 4541000
+377 0 4583000
+239 0 4625000
+125 0 4666000
+1 0 4708000
+351 0 4750000
+469 0 4791000
+288 0 4833000
+244 0 4875000
+224 0 4916000
+108 0 4958000
+1 0 5000000
+6016 16 5041000
+561 16 5041000
+235 0 5041000
+213 0 5083000
+118 0 5125000
+1 0 5166000
+299 0 5208000
+213 0 5250000
+129 0 5291000
+1 0 5333000
+7029 16 5375000
+728 16 5375000
+339 0 5375000
+287 0 5416000
+225 0 5458000
+147 0 5500000
+1 0 5541000
+270 0 5583000
+217 0 5625000
+138 0 5666000
+46 0 5708000
+32861 0 5750000
+16095 16 5791000
+2033 16 5791000
+318 0 5791000
+443 0 5833000
+361 0 5875000
+313 0 5916000
+274 0 5958000
+210 0 6000000
+134 0 6041000
+1 0 6083000
+295 0 6125000
+415 0 6166000
+330 0 6208000
+264 0 6250000
+242 0 6291000
+166 0 6333000
+116 0 6375000
+1 0 6416000
+9488 16 6458000
+1466 16 6458000
+378 0 6458000
+419 0 6500000
+335 0 6541000
+290 0 6583000
+315 0 6625000
+199 0 6666000
+131 0 6708000
+1 0 6750000
+342 0 6791000
+421 0 6833000
+306 0 6875000
+320 0 6916000
+245 0 6958000
+205 0 7000000
+143 0 7041000
+1 0 7083000
+16554 16 7125000
+1744 16 7125000
+482 0 7125000
+365 0 7166000
+352 0 7208000
+308 0 7250000
+295 0 7291000
+199 0 7333000
+149 0 7375000
+1 0 7416000
+360 0 7458000
+428 0 7500000
+377 0 7541000
+347 0 7583000
+270 0 7625000
+187 0 7666000
+130 0 7708000
+39 0 7750000
+14637 16 7791000
+1832 16 7791000
+422 0 7791000
+466 0 7833000
+375 0 7875000
+405 0 7916000
+352 0 7958000
+275 0 8000000
+173 0 8041000
+1 0 8083000
+484 0 8125000
+516 0 8166000
+497 0 8208000
+452 0 8250000
+428 0 8291000
+293 0 8333000
+190 0 8375000
+1 0 8416000
+11534 16 8458000
+1655 16 8458000
+446 0 8458000
+531 0 8500000
+465 0 8541000
+495 0 8583000
+402 0 8625000
+330 0 8666000
+227 0 8708000
+1 0 8750000
+568 0 8791000
+694 0 8833000
+382 0 8875000
+422 0 8916000
+280 0 8958000
+305 0 9000000
+203 0 9041000
+1 0 9083000
+17067 16 9125000
+1521 16 9125000
+428 0 9125000
+434 0 9166000
+359 0 9208000
+368 0 9250000
+240 0 9291000
+215 0 9333000
+211 0 9375000
+1 0 9416000
+346 0 9458000
+533 0 9500000
+391 0 9541000
+313 0 9583000
+326 0 9625000
+211 0 9666000
+233 0 9708000
+35 0 9750000
+23743 16 9791000
+1968 16 9791000
+277 0 9791000
+276 0 9833000
+285 0 9875000
+232 0 9916000
+179 0 9958000
+203 0 10000000
+121 0 10041000
+1 0 10083000
+318 0 10125000
+391 0 10166000
+362 0 10208000
+291 0 10250000
+235 0 10291000
+187 0 10333000
+117 0 10375000
+43 0 10416000
+12465 16 10458000
+1607 16 10458000
+280 0 10458000
+295 0 10500000
+244 0 10541000
+211 0 10583000
+171 0 10625000
+159 0 10666000
+106 0 10708000
+1 0 10750000
+216 0 10791000
+195 0 10833000
+180 0 10875000
+164 0 10916000
+156 0 10958000
+96 0 11000000
+1 0 11041000
+54547 0 11083000
+2920 16 11125000
+153 16 11125000
+117 0 11125000
+83 0 11166000
+86 0 11208000
+1 0 11250000
+92 0 11291000
+93 0 11333000
+80 0 11375000
+1 0 11416000
+1314 16 11458000
+311 16 11458000
+79 0 11458000
+65 0 11500000
+74 0 11541000
+61 0 11583000
+1 0 11625000
+65 0 11666000
+64 0 11708000
+49 0 11750000
+51 0 11791000
+1 0 11833000
+19309 0 11875000
+3848 16 11916000
+771 16 11916000
+167 0 11916000
+202 0 11958000
+190 0 12000000
+173 0 12041000
+128 0 12083000
+79 0 12125000
+1 0 12166000
+155 0 12208000
+211 0 12250000
+192 0 12291000
+131 0 12333000
+91 0 12375000
+128 0 12416000
+1 0 12458000
diff --git a/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9
new file mode 100644
index 0000000..00c7dec
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/functional/video/Android.bp b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
index b737323..760f4da 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
@@ -16,6 +16,7 @@
 
 cc_test {
     name: "VtsHalMediaC2V1_0TargetVideoDecTest",
+    stem: "vts_media_c2_v1_0_video_dec_test",
     defaults: ["VtsHalMediaC2V1_0Defaults"],
     srcs: ["VtsHalMediaC2V1_0TargetVideoDecTest.cpp"],
     header_libs: [
@@ -26,11 +27,16 @@
         "libgui",
         "libutils",
     ],
+    data: [":media_c2_v1_video_decode_res"],
+    test_config: "VtsHalMediaC2V1_0TargetVideoDecTest.xml",
 }
 
 cc_test {
     name: "VtsHalMediaC2V1_0TargetVideoEncTest",
+    stem: "vts_media_c2_v1_0_video_enc_test",
     defaults: ["VtsHalMediaC2V1_0Defaults"],
     srcs: ["VtsHalMediaC2V1_0TargetVideoEncTest.cpp"],
+    data: [":media_c2_v1_video_encode_res"],
+    test_config: "VtsHalMediaC2V1_0TargetVideoEncTest.xml",
 }
 
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 256603c..f216429 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -19,15 +19,16 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <stdio.h>
 #include <fstream>
 
-#include <codec2/hidl/client.h>
 #include <C2AllocatorIon.h>
-#include <C2Config.h>
-#include <C2Debug.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <codec2/hidl/client.h>
 #include <gui/BufferQueue.h>
 #include <gui/IConsumerListener.h>
 #include <gui/IProducerListener.h>
@@ -35,9 +36,8 @@
 
 using android::C2AllocatorIon;
 
-#include <VtsHalHidlTargetTestBase.h>
-#include "media_c2_video_hidl_test_common.h"
 #include "media_c2_hidl_test_common.h"
+#include "media_c2_video_hidl_test_common.h"
 
 struct FrameInfo {
     int bytesCount;
@@ -45,61 +45,47 @@
     int64_t timestamp;
 };
 
+static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
+        kDecodeTestParameters;
+
+// Resource directory
+static std::string sResourceDir = "";
+
 class LinearBuffer : public C2Buffer {
-   public:
+  public:
     explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
-        : C2Buffer(
-              {block->share(block->offset(), block->size(), ::C2Fence())}) {}
+        : 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())}) {}
+        : C2Buffer({block->share(block->offset(), size, ::C2Fence())}) {}
 };
 
-static ComponentTestEnvironment* gEnv = nullptr;
-
 namespace {
 
-class Codec2VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
-    typedef ::testing::VtsHalHidlTargetTestBase Super;
-
-   public:
-    ::std::string getTestCaseInfo() const override {
-        return ::std::string() +
-                "Component: " + gEnv->getComponent().c_str() + " | " +
-                "Instance: " + gEnv->getInstance().c_str() + " | " +
-                "Res: " + gEnv->getRes().c_str();
-    }
-
+class Codec2VideoDecHidlTestBase : public ::testing::Test {
+  public:
     // google.codec2 Video test setup
     virtual void SetUp() override {
-        Super::SetUp();
+        getParams();
         mDisableTest = false;
         ALOGV("Codec2VideoDecHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str(),
-            !bool(android::Codec2Client::CreateFromService("default", true)));
+                mInstanceName.c_str(),
+                !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
-        mListener.reset(new CodecListener(
-            [this](std::list<std::unique_ptr<C2Work>>& workItems) {
-                handleWorkDone(workItems);
-            }));
+        mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
+            handleWorkDone(workItems);
+        }));
         ASSERT_NE(mListener, nullptr);
         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
             mWorkQueue.emplace_back(new C2Work);
         }
-        mClient->createComponent(gEnv->getComponent().c_str(), mListener,
-                                 &mComponent);
+        mClient->createComponent(mComponentName, mListener, &mComponent);
         ASSERT_NE(mComponent, nullptr);
 
-        std::shared_ptr<C2AllocatorStore> store =
-            android::GetCodec2PlatformAllocatorStore();
-        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR,
-                                       &mLinearAllocator),
-                 C2_OK);
-        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
-                                                          mBlockPoolId++);
+        std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
+        mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
         ASSERT_NE(mLinearPool, nullptr);
 
         mCompName = unknown_comp;
@@ -109,17 +95,15 @@
         };
 
         const StringToName kStringToName[] = {
-            {"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4},
-            {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9}, {"av1", av1},
+                {"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4},
+                {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},     {"av1", av1},
         };
 
-        const size_t kNumStringToName =
-            sizeof(kStringToName) / sizeof(kStringToName[0]);
+        const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
 
         // Find the component type
-        std::string comp = std::string(gEnv->getComponent());
         for (size_t i = 0; i < kNumStringToName; ++i) {
-            if (strcasestr(comp.c_str(), kStringToName[i].Name)) {
+            if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
                 mCompName = kStringToName[i].CompName;
                 break;
             }
@@ -131,7 +115,7 @@
         if (mCompName == unknown_comp) mDisableTest = true;
 
         C2SecureModeTuning secureModeTuning{};
-        mComponent->query({ &secureModeTuning }, {}, C2_MAY_BLOCK, nullptr);
+        mComponent->query({&secureModeTuning}, {}, C2_MAY_BLOCK, nullptr);
         if (secureModeTuning.value == C2Config::SM_READ_PROTECTED) {
             mDisableTest = true;
         }
@@ -145,9 +129,11 @@
             mComponent->release();
             mComponent = nullptr;
         }
-        Super::TearDown();
     }
 
+    // Get the test parameters from GetParam call.
+    virtual void getParams() {}
+
     // callback function to process onWorkDone received by Listener
     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
         for (std::unique_ptr<C2Work>& work : workItems) {
@@ -157,13 +143,10 @@
                 typedef std::unique_lock<std::mutex> ULock;
                 bool codecConfig = ((work->worklets.front()->output.flags &
                                      C2FrameData::FLAG_CODEC_CONFIG) != 0);
-                if (!codecConfig &&
-                    !work->worklets.front()->output.buffers.empty()) {
-                    EXPECT_GE(
-                        (work->worklets.front()->output.ordinal.timestamp.peeku()),
-                        mTimestampUs);
-                    mTimestampUs =
-                        work->worklets.front()->output.ordinal.timestamp.peeku();
+                if (!codecConfig && !work->worklets.front()->output.buffers.empty()) {
+                    EXPECT_GE((work->worklets.front()->output.ordinal.timestamp.peeku()),
+                              mTimestampUs);
+                    mTimestampUs = work->worklets.front()->output.ordinal.timestamp.peeku();
 
                     ULock l(mQueueLock);
                     if (mTimestampDevTest) {
@@ -179,8 +162,7 @@
                         }
                         if (tsHit == false) {
                             if (mTimestampUslist.empty() == false) {
-                                EXPECT_EQ(tsHit, true)
-                                    << "TimeStamp not recognized";
+                                EXPECT_EQ(tsHit, true) << "TimeStamp not recognized";
                             } else {
                                 std::cout << "[   INFO   ] Received non-zero "
                                              "output / TimeStamp not recognized \n";
@@ -189,9 +171,8 @@
                     }
                 }
                 bool mCsd;
-                workDone(mComponent, work, mFlushedIndices, mQueueLock,
-                         mQueueCondition, mWorkQueue, mEos, mCsd,
-                         mFramesReceived);
+                workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
+                         mEos, mCsd, mFramesReceived);
                 (void)mCsd;
             }
         }
@@ -209,6 +190,9 @@
         unknown_comp,
     };
 
+    std::string mInstanceName;
+    std::string mComponentName;
+
     bool mEos;
     bool mDisableTest;
     bool mTimestampDevTest;
@@ -229,15 +213,23 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
-   protected:
+  protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
 };
 
-void validateComponent(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    Codec2VideoDecHidlTest::standardComp compName, bool& disableTest) {
+class Codec2VideoDecHidlTest
+    : public Codec2VideoDecHidlTestBase,
+      public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
+};
+
+void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
+                       Codec2VideoDecHidlTest::standardComp compName, bool& disableTest) {
     // Validate its a C2 Component
     if (component->getName().find("c2") == std::string::npos) {
         ALOGE("Not a c2 component");
@@ -252,14 +244,12 @@
         return;
     }
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err =
-        component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
-                         C2_DONT_BLOCK, &queried);
+    c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+                                         C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK && queried.size() == 0) {
         ALOGE("Query media type failed => %d", c2err);
     } else {
-        std::string inputDomain =
-            ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
+        std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
         if (inputDomain.find("video/") == std::string::npos) {
             ALOGE("Expected Video Component");
             disableTest = true;
@@ -277,10 +267,10 @@
 }
 
 // number of elementary streams per component
-#define STREAM_COUNT 2
+#define STREAM_COUNT 3
 // LookUpTable of clips and metadata for component testing
-void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL,
-                        char* info, size_t streamIndex = 1) {
+void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL, char* info,
+                        size_t streamIndex = 1) {
     struct CompToURL {
         Codec2VideoDecHidlTest::standardComp comp;
         const char mURL[STREAM_COUNT][512];
@@ -289,42 +279,32 @@
     ASSERT_TRUE(streamIndex < STREAM_COUNT);
 
     static const CompToURL kCompToURL[] = {
-        {Codec2VideoDecHidlTest::standardComp::avc,
-         {"bbb_avc_176x144_300kbps_60fps.h264",
-          "bbb_avc_640x360_768kbps_30fps.h264"},
-         {"bbb_avc_176x144_300kbps_60fps.info",
-          "bbb_avc_640x360_768kbps_30fps.info"}},
-        {Codec2VideoDecHidlTest::standardComp::hevc,
-         {"bbb_hevc_176x144_176kbps_60fps.hevc",
-          "bbb_hevc_640x360_1600kbps_30fps.hevc"},
-         {"bbb_hevc_176x144_176kbps_60fps.info",
-          "bbb_hevc_640x360_1600kbps_30fps.info"}},
-        {Codec2VideoDecHidlTest::standardComp::mpeg2,
-         {"bbb_mpeg2_176x144_105kbps_25fps.m2v",
-          "bbb_mpeg2_352x288_1mbps_60fps.m2v"},
-         {"bbb_mpeg2_176x144_105kbps_25fps.info",
-          "bbb_mpeg2_352x288_1mbps_60fps.info"}},
-        {Codec2VideoDecHidlTest::standardComp::h263,
-         {"", "bbb_h263_352x288_300kbps_12fps.h263"},
-         {"", "bbb_h263_352x288_300kbps_12fps.info"}},
-        {Codec2VideoDecHidlTest::standardComp::mpeg4,
-         {"", "bbb_mpeg4_352x288_512kbps_30fps.m4v"},
-         {"", "bbb_mpeg4_352x288_512kbps_30fps.info"}},
-        {Codec2VideoDecHidlTest::standardComp::vp8,
-         {"bbb_vp8_176x144_240kbps_60fps.vp8",
-          "bbb_vp8_640x360_2mbps_30fps.vp8"},
-         {"bbb_vp8_176x144_240kbps_60fps.info",
-          "bbb_vp8_640x360_2mbps_30fps.info"}},
-        {Codec2VideoDecHidlTest::standardComp::vp9,
-         {"bbb_vp9_176x144_285kbps_60fps.vp9",
-          "bbb_vp9_640x360_1600kbps_30fps.vp9"},
-         {"bbb_vp9_176x144_285kbps_60fps.info",
-          "bbb_vp9_640x360_1600kbps_30fps.info"}},
-        {Codec2VideoDecHidlTest::standardComp::av1,
-         {"bbb_av1_640_360.av1",
-          "bbb_av1_176_144.av1"},
-         {"bbb_av1_640_360.info",
-          "bbb_av1_176_144.info"}},
+            {Codec2VideoDecHidlTest::standardComp::avc,
+             {"bbb_avc_176x144_300kbps_60fps.h264", "bbb_avc_640x360_768kbps_30fps.h264", ""},
+             {"bbb_avc_176x144_300kbps_60fps.info", "bbb_avc_640x360_768kbps_30fps.info", ""}},
+            {Codec2VideoDecHidlTest::standardComp::hevc,
+             {"bbb_hevc_176x144_176kbps_60fps.hevc", "bbb_hevc_640x360_1600kbps_30fps.hevc", ""},
+             {"bbb_hevc_176x144_176kbps_60fps.info", "bbb_hevc_640x360_1600kbps_30fps.info", ""}},
+            {Codec2VideoDecHidlTest::standardComp::mpeg2,
+             {"bbb_mpeg2_176x144_105kbps_25fps.m2v", "bbb_mpeg2_352x288_1mbps_60fps.m2v", ""},
+             {"bbb_mpeg2_176x144_105kbps_25fps.info", "bbb_mpeg2_352x288_1mbps_60fps.info", ""}},
+            {Codec2VideoDecHidlTest::standardComp::h263,
+             {"", "bbb_h263_352x288_300kbps_12fps.h263", ""},
+             {"", "bbb_h263_352x288_300kbps_12fps.info", ""}},
+            {Codec2VideoDecHidlTest::standardComp::mpeg4,
+             {"", "bbb_mpeg4_352x288_512kbps_30fps.m4v", ""},
+             {"", "bbb_mpeg4_352x288_512kbps_30fps.info", ""}},
+            {Codec2VideoDecHidlTest::standardComp::vp8,
+             {"bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_640x360_2mbps_30fps.vp8", ""},
+             {"bbb_vp8_176x144_240kbps_60fps.info", "bbb_vp8_640x360_2mbps_30fps.info", ""}},
+            {Codec2VideoDecHidlTest::standardComp::vp9,
+             {"bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9",
+              "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9"},
+             {"bbb_vp9_176x144_285kbps_60fps.info", "bbb_vp9_640x360_1600kbps_30fps.info",
+              "bbb_vp9_704x480_280kbps_24fps_altref_2.info"}},
+            {Codec2VideoDecHidlTest::standardComp::av1,
+             {"bbb_av1_640_360.av1", "bbb_av1_176_144.av1", ""},
+             {"bbb_av1_640_360.info", "bbb_av1_176_144.info", ""}},
     };
 
     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@@ -337,13 +317,11 @@
 }
 
 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
-                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::mutex& queueLock, std::condition_variable& queueCondition,
                    std::list<std::unique_ptr<C2Work>>& workQueue,
-                   std::list<uint64_t>& flushedIndices,
-                   std::shared_ptr<C2BlockPool>& linearPool,
-                   std::ifstream& eleStream,
-                   android::Vector<FrameInfo>* Info,
-                   int offset, int range, bool signalEOS = true) {
+                   std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
+                   std::ifstream& eleStream, android::Vector<FrameInfo>* Info, int offset,
+                   int range, bool signalEOS = true) {
     typedef std::unique_lock<std::mutex> ULock;
     int frameID = offset;
     int maxRetry = 0;
@@ -367,8 +345,7 @@
         }
         int64_t timestamp = (*Info)[frameID].timestamp;
         if ((*Info)[frameID].flags) flags = (1 << ((*Info)[frameID].flags - 1));
-        if (signalEOS && ((frameID == (int)Info->size() - 1) ||
-                          (frameID == (offset + range - 1))))
+        if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1))))
             flags |= C2FrameData::FLAG_END_OF_STREAM;
 
         work->input.flags = (C2FrameData::flags_t)flags;
@@ -390,10 +367,9 @@
         auto alignedSize = ALIGN(size, PAGE_SIZE);
         if (size) {
             std::shared_ptr<C2LinearBlock> block;
-            ASSERT_EQ(C2_OK,
-                    linearPool->fetchLinearBlock(
-                        alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
-                        &block));
+            ASSERT_EQ(C2_OK, linearPool->fetchLinearBlock(
+                                     alignedSize,
+                                     {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
             ASSERT_TRUE(block);
 
             // Write View
@@ -424,16 +400,16 @@
     }
 }
 
-TEST_F(Codec2VideoDecHidlTest, validateCompName) {
-    if (mDisableTest) return;
+TEST_P(Codec2VideoDecHidlTest, validateCompName) {
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ALOGV("Checks if the given component is a valid video component");
     validateComponent(mComponent, mCompName, mDisableTest);
     ASSERT_EQ(mDisableTest, false);
 }
 
-TEST_F(Codec2VideoDecHidlTest, configureTunnel) {
+TEST_P(Codec2VideoDecHidlTest, configureTunnel) {
     description("Attempts to configure tunneling");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ALOGV("Checks if the component can be configured for tunneling");
     native_handle_t* sidebandStream{};
     c2_status_t err = mComponent->configureVideoTunnel(0, &sidebandStream);
@@ -449,7 +425,7 @@
     BufferQueue::createBufferQueue(&producer, &consumer);
 
     class DummyConsumerListener : public BnConsumerListener {
-    public:
+      public:
         DummyConsumerListener() : BnConsumerListener() {}
         void onFrameAvailable(const BufferItem&) override {}
         void onBuffersReleased() override {}
@@ -458,37 +434,39 @@
     consumer->consumerConnect(new DummyConsumerListener(), false);
 
     class DummyProducerListener : public BnProducerListener {
-    public:
+      public:
         DummyProducerListener() : BnProducerListener() {}
         virtual void onBufferReleased() override {}
         virtual bool needsReleaseNotify() override { return false; }
         virtual void onBuffersDiscarded(const std::vector<int32_t>&) override {}
     };
     IGraphicBufferProducer::QueueBufferOutput qbo{};
-    producer->connect(new DummyProducerListener(),
-                      NATIVE_WINDOW_API_MEDIA,
-                      false,
-                      &qbo);
+    producer->connect(new DummyProducerListener(), NATIVE_WINDOW_API_MEDIA, false, &qbo);
 
     ASSERT_EQ(producer->setSidebandStream(nativeHandle), NO_ERROR);
 }
 
 class Codec2VideoDecDecodeTest
-    : public Codec2VideoDecHidlTest,
-      public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
+    : public Codec2VideoDecHidlTestBase,
+      public ::testing::WithParamInterface<
+              std::tuple<std::string, std::string, std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
 };
 
 // Bitstream Test
 TEST_P(Codec2VideoDecDecodeTest, DecodeTest) {
     description("Decodes input file");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
-    uint32_t streamIndex = GetParam().first;
-    bool signalEOS = GetParam().second;
+    uint32_t streamIndex = std::stoi(std::get<2>(GetParam()));
+    bool signalEOS = !std::get<2>(GetParam()).compare("true");
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info, streamIndex);
 
     eleInfo.open(info);
@@ -504,9 +482,9 @@
         if (!(eleInfo >> bytesCount)) break;
         eleInfo >> flags;
         eleInfo >> timestamp;
-        bool codecConfig = flags ?
-            ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
-        if (mTimestampDevTest && !codecConfig)
+        bool codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+        bool nonDisplayFrame = ((flags & FLAG_NON_DISPLAY_FRAME) != 0);
+        if (mTimestampDevTest && !codecConfig && !nonDisplayFrame)
             mTimestampUslist.push_back(timestamp);
         Info.push_back({bytesCount, flags, timestamp});
     }
@@ -519,52 +497,42 @@
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
-    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, (int)Info.size(), signalEOS));
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                          (int)Info.size(), signalEOS));
 
     // If EOS is not sent, sending empty input with EOS flag
     size_t infoSize = Info.size();
     if (!signalEOS) {
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
-        ASSERT_NO_FATAL_FAILURE(
-            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
-                            C2FrameData::FLAG_END_OF_STREAM, false));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                                                C2FrameData::FLAG_END_OF_STREAM, false));
         infoSize += 1;
     }
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     if (!mEos) {
         ALOGV("Waiting for input consumption");
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     }
 
     eleStream.close();
     if (mFramesReceived != infoSize) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
-              infoSize);
+        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, infoSize);
         ASSERT_TRUE(false);
     }
 
     if (mTimestampDevTest) EXPECT_EQ(mTimestampUslist.empty(), true);
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
-// DecodeTest with StreamIndex and EOS / No EOS
-INSTANTIATE_TEST_CASE_P(StreamIndexAndEOS, Codec2VideoDecDecodeTest,
-                        ::testing::Values(std::make_pair(0, false),
-                                          std::make_pair(0, true),
-                                          std::make_pair(1, false),
-                                          std::make_pair(1, true)));
 
 // Adaptive Test
-TEST_F(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
+TEST_P(Codec2VideoDecHidlTest, AdaptiveDecodeTest) {
     description("Adaptive Decode Test");
-    if (mDisableTest) return;
-    if (!(mCompName == avc || mCompName == hevc || mCompName == vp8 ||
-          mCompName == vp9 || mCompName == mpeg2))
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
+    if (!(mCompName == avc || mCompName == hevc || mCompName == vp8 || mCompName == vp9 ||
+          mCompName == mpeg2))
         return;
 
     typedef std::unique_lock<std::mutex> ULock;
@@ -578,9 +546,13 @@
         char mURL[512], info[512];
         std::ifstream eleStream, eleInfo;
 
-        strcpy(mURL, gEnv->getRes().c_str());
-        strcpy(info, gEnv->getRes().c_str());
+        strcpy(mURL, sResourceDir.c_str());
+        strcpy(info, sResourceDir.c_str());
         GetURLForComponent(mCompName, mURL, info, i % STREAM_COUNT);
+        if (!(strcmp(mURL, sResourceDir.c_str())) || !(strcmp(info, sResourceDir.c_str()))) {
+            ALOGV("Stream not available, skipping this index");
+            continue;
+        }
 
         eleInfo.open(info);
         ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
@@ -594,12 +566,13 @@
             eleInfo >> timestamp;
             timestamp += timestampOffset;
             Info.push_back({bytesCount, flags, timestamp});
-            bool codecConfig = flags ?
-                ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+            bool codecConfig =
+                    flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+            bool nonDisplayFrame = ((flags & FLAG_NON_DISPLAY_FRAME) != 0);
 
             {
                 ULock l(mQueueLock);
-                if (mTimestampDevTest && !codecConfig)
+                if (mTimestampDevTest && !codecConfig && !nonDisplayFrame)
                     mTimestampUslist.push_back(timestamp);
             }
             if (timestampMax < timestamp) timestampMax = timestamp;
@@ -612,10 +585,9 @@
         ALOGV("mURL : %s", mURL);
         eleStream.open(mURL, std::ifstream::binary);
         ASSERT_EQ(eleStream.is_open(), true);
-        ASSERT_NO_FATAL_FAILURE(
-            decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                          mFlushedIndices, mLinearPool, eleStream, &Info,
-                          offset, (int)(Info.size() - offset), false));
+        ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                              mFlushedIndices, mLinearPool, eleStream, &Info,
+                                              offset, (int)(Info.size() - offset), false));
 
         eleStream.close();
         offset = (int)Info.size();
@@ -650,13 +622,11 @@
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     ALOGV("Waiting for input consumption");
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
 
     if (mFramesReceived != ((Info.size()) + 1)) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
-              Info.size() + 1);
+        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, Info.size() + 1);
         ASSERT_TRUE(false);
     }
 
@@ -664,15 +634,15 @@
 }
 
 // thumbnail test
-TEST_F(Codec2VideoDecHidlTest, ThumbnailTest) {
+TEST_P(Codec2VideoDecHidlTest, ThumbnailTest) {
     description("Test Request for thumbnail");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info);
 
     eleInfo.open(info);
@@ -703,11 +673,10 @@
         } while (!(flags & SYNC_FRAME));
         eleStream.open(mURL, std::ifstream::binary);
         ASSERT_EQ(eleStream.is_open(), true);
-        ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-            mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-            mFlushedIndices, mLinearPool, eleStream, &Info, 0, j + 1));
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+        ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                              mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                              j + 1));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
         eleStream.close();
         EXPECT_GE(mFramesReceived, 1U);
         ASSERT_EQ(mEos, true);
@@ -716,9 +685,9 @@
     ASSERT_EQ(mComponent->release(), C2_OK);
 }
 
-TEST_F(Codec2VideoDecHidlTest, EOSTest) {
+TEST_P(Codec2VideoDecHidlTest, EOSTest) {
     description("Test empty input buffer with EOS flag");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     typedef std::unique_lock<std::mutex> ULock;
     ASSERT_EQ(mComponent->start(), C2_OK);
     std::unique_ptr<C2Work> work;
@@ -756,16 +725,16 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2VideoDecHidlTest, FlushTest) {
+TEST_P(Codec2VideoDecHidlTest, FlushTest) {
     description("Tests Flush calls");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     typedef std::unique_lock<std::mutex> ULock;
     ASSERT_EQ(mComponent->start(), C2_OK);
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info);
 
     eleInfo.open(info);
@@ -790,28 +759,24 @@
     // frame after this so that the below section can be covered for all
     // components
     uint32_t numFramesFlushed = 128;
-    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, numFramesFlushed, false));
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                          numFramesFlushed, false));
     // flush
     std::list<std::unique_ptr<C2Work>> flushedWork;
-    c2_status_t err =
-        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-                               (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
 
     {
         // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
-            auto frameIndexIt =
-                std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
-                          work->input.ordinal.frameIndex.peeku());
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+            auto frameIndexIt = std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
+                                          work->input.ordinal.frameIndex.peeku());
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -835,27 +800,24 @@
         index++;
     }
     if (keyFrame) {
-        ASSERT_NO_FATAL_FAILURE(
-            decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                          mFlushedIndices, mLinearPool, eleStream, &Info, index,
-                          (int)Info.size() - index));
+        ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                              mFlushedIndices, mLinearPool, eleStream, &Info, index,
+                                              (int)Info.size() - index));
     }
     eleStream.close();
     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-                               (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
     {
         // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
             uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
-            std::list<uint64_t>::iterator frameIndexIt = std::find(
-                mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+            std::list<uint64_t>::iterator frameIndexIt =
+                    std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -867,15 +829,15 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) {
+TEST_P(Codec2VideoDecHidlTest, DecodeTestEmptyBuffersInserted) {
     description("Decode with multiple empty input frames");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     char mURL[512], info[512];
     std::ifstream eleStream, eleInfo;
 
-    strcpy(mURL, gEnv->getRes().c_str());
-    strcpy(info, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
+    strcpy(info, sResourceDir.c_str());
     GetURLForComponent(mCompName, mURL, info);
 
     eleInfo.open(info);
@@ -890,15 +852,16 @@
     // and empty input frames at an interval of 5 frames.
     while (1) {
         if (!(frameId % 5)) {
-            if (!(frameId % 20)) flags = 32;
-            else flags = 0;
+            if (!(frameId % 20))
+                flags = 32;
+            else
+                flags = 0;
             bytesCount = 0;
         } else {
             if (!(eleInfo >> bytesCount)) break;
             eleInfo >> flags;
             eleInfo >> timestamp;
-            codecConfig = flags ?
-                ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+            codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
         }
         Info.push_back({bytesCount, flags, timestamp});
         frameId++;
@@ -909,39 +872,62 @@
     ALOGV("mURL : %s", mURL);
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
-    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
-        mComponent, mQueueLock, mQueueCondition, mWorkQueue, mFlushedIndices,
-        mLinearPool, eleStream, &Info, 0, (int)Info.size()));
+    ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mLinearPool, eleStream, &Info, 0,
+                                          (int)Info.size()));
 
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     if (!mEos) {
         ALOGV("Waiting for input consumption");
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
     }
 
     eleStream.close();
     if (mFramesReceived != Info.size()) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived,
-              Info.size());
+        ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, Info.size());
         ASSERT_TRUE(false);
     }
 }
 
+INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2VideoDecHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+// DecodeTest with StreamIndex and EOS / No EOS
+INSTANTIATE_TEST_SUITE_P(StreamIndexAndEOS, Codec2VideoDecDecodeTest,
+                         testing::ValuesIn(kDecodeTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
 }  // anonymous namespace
 
 // TODO : Video specific configuration Test
 int main(int argc, char** argv) {
-    gEnv = new ComponentTestEnvironment();
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "C2 Test result = " << status;
+    kTestParameters = getTestParameters(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER);
+    for (auto params : kTestParameters) {
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "false"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "true"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "false"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "true"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "2", "false"));
+        kDecodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "2", "true"));
     }
-    return status;
-}
+
+    // Set the resource directory based on command line args.
+    // Test will fail to set up if the argument is not set.
+    for (int i = 1; i < argc; i++) {
+        if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
+            sResourceDir = argv[i + 1];
+            break;
+        }
+    }
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.xml b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.xml
new file mode 100644
index 0000000..63e7a69
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the"License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an"AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalMediaC2V1_0TargetVideoDecTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="vts_media_c2_v1_0_video_dec_test" value="/data/local/tmp/vts_media_c2_v1_0_video_dec_test" />
+
+        <!-- Files used for video testing -->
+        <option name="push-file" key="bbb_avc_176x144_300kbps_60fps.h264" value="/data/local/tmp/media/bbb_avc_176x144_300kbps_60fps.h264" />
+        <option name="push-file" key="bbb_avc_640x360_768kbps_30fps.h264" value="/data/local/tmp/media/bbb_avc_640x360_768kbps_30fps.h264" />
+        <option name="push-file" key="bbb_avc_176x144_300kbps_60fps.info" value="/data/local/tmp/media/bbb_avc_176x144_300kbps_60fps.info" />
+        <option name="push-file" key="bbb_avc_640x360_768kbps_30fps.info" value="/data/local/tmp/media/bbb_avc_640x360_768kbps_30fps.info" />
+        <option name="push-file" key="bbb_hevc_176x144_176kbps_60fps.hevc" value="/data/local/tmp/media/bbb_hevc_176x144_176kbps_60fps.hevc" />
+        <option name="push-file" key="bbb_hevc_640x360_1600kbps_30fps.hevc" value="/data/local/tmp/media/bbb_hevc_640x360_1600kbps_30fps.hevc" />
+        <option name="push-file" key="bbb_hevc_176x144_176kbps_60fps.info" value="/data/local/tmp/media/bbb_hevc_176x144_176kbps_60fps.info" />
+        <option name="push-file" key="bbb_hevc_640x360_1600kbps_30fps.info" value="/data/local/tmp/media/bbb_hevc_640x360_1600kbps_30fps.info" />
+        <option name="push-file" key="bbb_mpeg2_176x144_105kbps_25fps.m2v" value="/data/local/tmp/media/bbb_mpeg2_176x144_105kbps_25fps.m2v" />
+        <option name="push-file" key="bbb_mpeg2_352x288_1mbps_60fps.m2v" value="/data/local/tmp/media/bbb_mpeg2_352x288_1mbps_60fps.m2v" />
+        <option name="push-file" key="bbb_mpeg2_176x144_105kbps_25fps.info" value="/data/local/tmp/media/bbb_mpeg2_176x144_105kbps_25fps.info" />
+        <option name="push-file" key="bbb_mpeg2_352x288_1mbps_60fps.info" value="/data/local/tmp/media/bbb_mpeg2_352x288_1mbps_60fps.info" />
+        <option name="push-file" key="bbb_h263_352x288_300kbps_12fps.h263" value="/data/local/tmp/media/bbb_h263_352x288_300kbps_12fps.h263" />
+        <option name="push-file" key="bbb_h263_352x288_300kbps_12fps.info" value="/data/local/tmp/media/bbb_h263_352x288_300kbps_12fps.info" />
+        <option name="push-file" key="bbb_mpeg4_352x288_512kbps_30fps.m4v" value="/data/local/tmp/media/bbb_mpeg4_352x288_512kbps_30fps.m4v" />
+        <option name="push-file" key="bbb_mpeg4_352x288_512kbps_30fps.info" value="/data/local/tmp/media/bbb_mpeg4_352x288_512kbps_30fps.info" />
+        <option name="push-file" key="bbb_vp8_176x144_240kbps_60fps.vp8" value="/data/local/tmp/media/bbb_vp8_176x144_240kbps_60fps.vp8" />
+        <option name="push-file" key="bbb_vp8_640x360_2mbps_30fps.vp8" value="/data/local/tmp/media/bbb_vp8_640x360_2mbps_30fps.vp8" />
+        <option name="push-file" key="bbb_vp8_176x144_240kbps_60fps.info" value="/data/local/tmp/media/bbb_vp8_176x144_240kbps_60fps.info" />
+        <option name="push-file" key="bbb_vp8_640x360_2mbps_30fps.info" value="/data/local/tmp/media/bbb_vp8_640x360_2mbps_30fps.info" />
+        <option name="push-file" key="bbb_vp9_176x144_285kbps_60fps.vp9" value="/data/local/tmp/media/bbb_vp9_176x144_285kbps_60fps.vp9" />
+        <option name="push-file" key="bbb_vp9_640x360_1600kbps_30fps.vp9" value="/data/local/tmp/media/bbb_vp9_640x360_1600kbps_30fps.vp9" />
+        <option name="push-file" key="bbb_vp9_176x144_285kbps_60fps.info" value="/data/local/tmp/media/bbb_vp9_176x144_285kbps_60fps.info" />
+        <option name="push-file" key="bbb_vp9_640x360_1600kbps_30fps.info" value="/data/local/tmp/media/bbb_vp9_640x360_1600kbps_30fps.info" />
+        <option name="push-file" key="bbb_av1_640_360.av1" value="/data/local/tmp/media/bbb_av1_640_360.av1" />
+        <option name="push-file" key="bbb_av1_176_144.av1" value="/data/local/tmp/media/bbb_av1_176_144.av1" />
+        <option name="push-file" key="bbb_av1_640_360.info" value="/data/local/tmp/media/bbb_av1_640_360.info" />
+        <option name="push-file" key="bbb_av1_176_144.info" value="/data/local/tmp/media/bbb_av1_176_144.info" />
+        <option name="push-file" key="bbb_vp9_704x480_280kbps_24fps_altref_2.vp9" value="/data/local/tmp/media/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9" />
+        <option name="push-file" key="bbb_vp9_704x480_280kbps_24fps_altref_2.info" value="/data/local/tmp/media/bbb_vp9_704x480_280kbps_24fps_altref_2.info" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="vts_media_c2_v1_0_video_dec_test" />
+        <option name="native-test-flag" value="-P /data/local/tmp/media/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index 15f6acd..ecc56f5 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -19,73 +19,63 @@
 
 #include <android-base/logging.h>
 #include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
 #include <stdio.h>
 #include <fstream>
 
-#include <codec2/hidl/client.h>
 #include <C2AllocatorIon.h>
-#include <C2Config.h>
-#include <C2Debug.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <codec2/hidl/client.h>
 
 using android::C2AllocatorIon;
 
-#include <VtsHalHidlTargetTestBase.h>
-#include "media_c2_video_hidl_test_common.h"
 #include "media_c2_hidl_test_common.h"
+#include "media_c2_video_hidl_test_common.h"
 
 class GraphicBuffer : public C2Buffer {
-public:
-  explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock> &block)
-      : C2Buffer({block->share(C2Rect(block->width(), block->height()),
-                               ::C2Fence())}) {}
+  public:
+    explicit GraphicBuffer(const std::shared_ptr<C2GraphicBlock>& block)
+        : C2Buffer({block->share(C2Rect(block->width(), block->height()), ::C2Fence())}) {}
 };
 
-static ComponentTestEnvironment* gEnv = nullptr;
+static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
+        kEncodeTestParameters;
+static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
+        kEncodeResolutionTestParameters;
+
+// Resource directory
+static std::string sResourceDir = "";
 
 namespace {
 
-class Codec2VideoEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
-    typedef ::testing::VtsHalHidlTargetTestBase Super;
-
-   public:
-    ::std::string getTestCaseInfo() const override {
-        return ::std::string() +
-                "Component: " + gEnv->getComponent().c_str() + " | " +
-                "Instance: " + gEnv->getInstance().c_str() + " | " +
-                "Res: " + gEnv->getRes().c_str();
-    }
-
+class Codec2VideoEncHidlTestBase : public ::testing::Test {
+  public:
     // google.codec2 Video test setup
     virtual void SetUp() override {
-        Super::SetUp();
+        getParams();
         mDisableTest = false;
         ALOGV("Codec2VideoEncHidlTest SetUp");
         mClient = android::Codec2Client::CreateFromService(
-            gEnv->getInstance().c_str(),
-            !bool(android::Codec2Client::CreateFromService("default", true)));
+                mInstanceName.c_str(),
+                !bool(android::Codec2Client::CreateFromService("default", true)));
         ASSERT_NE(mClient, nullptr);
-        mListener.reset(new CodecListener(
-            [this](std::list<std::unique_ptr<C2Work>>& workItems) {
-                handleWorkDone(workItems);
-            }));
+        mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
+            handleWorkDone(workItems);
+        }));
         ASSERT_NE(mListener, nullptr);
         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
             mWorkQueue.emplace_back(new C2Work);
         }
-        mClient->createComponent(gEnv->getComponent().c_str(), mListener,
-                                 &mComponent);
+        mClient->createComponent(mComponentName, mListener, &mComponent);
         ASSERT_NE(mComponent, nullptr);
 
-        std::shared_ptr<C2AllocatorStore> store =
-            android::GetCodec2PlatformAllocatorStore();
-        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC,
-                                       &mGraphicAllocator),
+        std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
+        CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mGraphicAllocator),
                  C2_OK);
-        mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator,
-                                                           mBlockPoolId++);
+        mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++);
         ASSERT_NE(mGraphicPool, nullptr);
 
         mCompName = unknown_comp;
@@ -95,17 +85,15 @@
         };
 
         const StringToName kStringToName[] = {
-            {"h263", h263}, {"avc", avc}, {"mpeg4", mpeg4},
-            {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
+                {"h263", h263}, {"avc", avc}, {"mpeg4", mpeg4},
+                {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
         };
 
-        const size_t kNumStringToName =
-            sizeof(kStringToName) / sizeof(kStringToName[0]);
+        const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
 
         // Find the component type
-        std::string comp = std::string(gEnv->getComponent());
         for (size_t i = 0; i < kNumStringToName; ++i) {
-            if (strcasestr(comp.c_str(), kStringToName[i].Name)) {
+            if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
                 mCompName = kStringToName[i].CompName;
                 break;
             }
@@ -115,6 +103,7 @@
         mFramesReceived = 0;
         mFailedWorkReceived = 0;
         mTimestampUs = 0u;
+        mOutputSize = 0u;
         mTimestampDevTest = false;
         if (mCompName == unknown_comp) mDisableTest = true;
         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
@@ -126,9 +115,11 @@
             mComponent->release();
             mComponent = nullptr;
         }
-        Super::TearDown();
     }
 
+    // Get the test parameters from GetParam call.
+    virtual void getParams() {}
+
     bool setupConfigParam(int32_t nWidth, int32_t nHeight);
 
     // callback function to process onWorkDone received by Listener
@@ -139,11 +130,9 @@
                 // previous timestamp
                 typedef std::unique_lock<std::mutex> ULock;
                 if (!mTimestampUslist.empty()) {
-                    EXPECT_GE((work->worklets.front()
-                                   ->output.ordinal.timestamp.peeku()),
+                    EXPECT_GE((work->worklets.front()->output.ordinal.timestamp.peeku()),
                               mTimestampUs);
-                    mTimestampUs = work->worklets.front()
-                                       ->output.ordinal.timestamp.peeku();
+                    mTimestampUs = work->worklets.front()->output.ordinal.timestamp.peeku();
                     // Currently this lock is redundant as no mTimestampUslist is only initialized
                     // before queuing any work to component. Once AdaptiveTest is added similar to
                     // the one in video decoders, this is needed.
@@ -151,8 +140,7 @@
 
                     if (mTimestampDevTest) {
                         bool tsHit = false;
-                        std::list<uint64_t>::iterator it =
-                            mTimestampUslist.begin();
+                        std::list<uint64_t>::iterator it = mTimestampUslist.begin();
                         while (it != mTimestampUslist.end()) {
                             if (*it == mTimestampUs) {
                                 mTimestampUslist.erase(it);
@@ -163,21 +151,28 @@
                         }
                         if (tsHit == false) {
                             if (mTimestampUslist.empty() == false) {
-                                EXPECT_EQ(tsHit, true)
-                                    << "TimeStamp not recognized";
+                                EXPECT_EQ(tsHit, true) << "TimeStamp not recognized";
                             } else {
-                                std::cout
-                                    << "[   INFO   ] Received non-zero "
-                                       "output / TimeStamp not recognized \n";
+                                std::cout << "[   INFO   ] Received non-zero "
+                                             "output / TimeStamp not recognized \n";
                             }
                         }
                     }
                 }
 
                 if (work->result != C2_OK) mFailedWorkReceived++;
-                workDone(mComponent, work, mFlushedIndices, mQueueLock,
-                         mQueueCondition, mWorkQueue, mEos, mCsd,
-                         mFramesReceived);
+                if (!work->worklets.front()->output.buffers.empty()) {
+                    mOutputSize += work->worklets.front()
+                                           ->output.buffers[0]
+                                           ->data()
+                                           .linearBlocks()
+                                           .front()
+                                           .map()
+                                           .get()
+                                           .capacity();
+                }
+                workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
+                         mEos, mCsd, mFramesReceived);
             }
         }
     }
@@ -192,6 +187,8 @@
         unknown_comp,
     };
 
+    std::string mInstanceName;
+    std::string mComponentName;
     bool mEos;
     bool mCsd;
     bool mDisableTest;
@@ -201,6 +198,7 @@
     uint32_t mFramesReceived;
     uint32_t mFailedWorkReceived;
     uint64_t mTimestampUs;
+    uint64_t mOutputSize;
 
     std::list<uint64_t> mTimestampUslist;
     std::list<uint64_t> mFlushedIndices;
@@ -217,15 +215,23 @@
     std::shared_ptr<android::Codec2Client::Listener> mListener;
     std::shared_ptr<android::Codec2Client::Component> mComponent;
 
-   protected:
+  protected:
     static void description(const std::string& description) {
         RecordProperty("description", description);
     }
 };
 
-void validateComponent(
-    const std::shared_ptr<android::Codec2Client::Component>& component,
-    Codec2VideoEncHidlTest::standardComp compName, bool& disableTest) {
+class Codec2VideoEncHidlTest
+    : public Codec2VideoEncHidlTestBase,
+      public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
+};
+
+void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
+                       Codec2VideoEncHidlTest::standardComp compName, bool& disableTest) {
     // Validate its a C2 Component
     if (component->getName().find("c2") == std::string::npos) {
         ALOGE("Not a c2 component");
@@ -240,14 +246,12 @@
         return;
     }
     std::vector<std::unique_ptr<C2Param>> queried;
-    c2_status_t c2err =
-        component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
-                         C2_DONT_BLOCK, &queried);
+    c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+                                         C2_DONT_BLOCK, &queried);
     if (c2err != C2_OK && queried.size() == 0) {
         ALOGE("Query media type failed => %d", c2err);
     } else {
-        std::string inputDomain =
-            ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
+        std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
         if (inputDomain.find("video/") == std::string::npos) {
             ALOGE("Expected Video Component");
             disableTest = true;
@@ -265,12 +269,11 @@
 }
 
 // Set Default config param.
-bool Codec2VideoEncHidlTest::setupConfigParam(int32_t nWidth, int32_t nHeight) {
+bool Codec2VideoEncHidlTestBase::setupConfigParam(int32_t nWidth, int32_t nHeight) {
     std::vector<std::unique_ptr<C2SettingResult>> failures;
     C2StreamPictureSizeInfo::input inputSize(0u, nWidth, nHeight);
     std::vector<C2Param*> configParam{&inputSize};
-    c2_status_t status =
-        mComponent->config(configParam, C2_DONT_BLOCK, &failures);
+    c2_status_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
     if (status == C2_OK && failures.size() == 0u) return true;
     return false;
 }
@@ -281,19 +284,16 @@
 }
 
 void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
-                   std::mutex &queueLock, std::condition_variable& queueCondition,
+                   std::mutex& queueLock, std::condition_variable& queueCondition,
                    std::list<std::unique_ptr<C2Work>>& workQueue,
-                   std::list<uint64_t>& flushedIndices,
-                   std::shared_ptr<C2BlockPool>& graphicPool,
-                   std::ifstream& eleStream, bool& disableTest,
-                   uint32_t frameID, uint32_t nFrames, uint32_t nWidth,
-                   int32_t nHeight, bool flushed = false, bool signalEOS = true) {
+                   std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& graphicPool,
+                   std::ifstream& eleStream, bool& disableTest, uint32_t frameID, uint32_t nFrames,
+                   uint32_t nWidth, int32_t nHeight, bool flushed = false, bool signalEOS = true) {
     typedef std::unique_lock<std::mutex> ULock;
 
     uint32_t maxRetry = 0;
     int bytesCount = nWidth * nHeight * 3 >> 1;
     int32_t timestampIncr = ENCODER_TIMESTAMP_INCREMENT;
-    uint64_t timestamp = 0;
     c2_status_t err = C2_OK;
     while (1) {
         if (nFrames == 0) break;
@@ -313,15 +313,14 @@
         if (!work && (maxRetry >= MAX_RETRY)) {
             ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
         }
-        if (signalEOS && (nFrames == 1))
-            flags |= C2FrameData::FLAG_END_OF_STREAM;
+        if (signalEOS && (nFrames == 1)) flags |= C2FrameData::FLAG_END_OF_STREAM;
         if (flushed) {
             flags |= SYNC_FRAME;
             flushed = false;
         }
 
         work->input.flags = (C2FrameData::flags_t)flags;
-        work->input.ordinal.timestamp = timestamp;
+        work->input.ordinal.timestamp = frameID * timestampIncr;
         work->input.ordinal.frameIndex = frameID;
         {
             ULock l(queueLock);
@@ -335,9 +334,9 @@
             ASSERT_EQ(eleStream.gcount(), bytesCount);
         }
         std::shared_ptr<C2GraphicBlock> block;
-        err = graphicPool->fetchGraphicBlock(
-                nWidth, nHeight, HAL_PIXEL_FORMAT_YV12,
-                {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+        err = graphicPool->fetchGraphicBlock(nWidth, nHeight, HAL_PIXEL_FORMAT_YV12,
+                                             {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
+                                             &block);
         if (err != C2_OK) {
             fprintf(stderr, "fetchGraphicBlock failed : %d\n", err);
             disableTest = true;
@@ -374,33 +373,40 @@
         ASSERT_EQ(component->queue(&items), C2_OK);
         ALOGV("Frame #%d size = %d queued", frameID, bytesCount);
         nFrames--;
-        timestamp += timestampIncr;
         frameID++;
         maxRetry = 0;
     }
 }
 
-TEST_F(Codec2VideoEncHidlTest, validateCompName) {
-    if (mDisableTest) return;
+TEST_P(Codec2VideoEncHidlTest, validateCompName) {
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ALOGV("Checks if the given component is a valid video component");
     validateComponent(mComponent, mCompName, mDisableTest);
     ASSERT_EQ(mDisableTest, false);
 }
 
-class Codec2VideoEncEncodeTest : public Codec2VideoEncHidlTest,
-                                 public ::testing::WithParamInterface<bool> {
+class Codec2VideoEncEncodeTest
+    : public Codec2VideoEncHidlTestBase,
+      public ::testing::WithParamInterface<
+              std::tuple<std::string, std::string, std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
 };
 
 TEST_P(Codec2VideoEncEncodeTest, EncodeTest) {
     description("Encodes input file");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     char mURL[512];
     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
-    bool signalEOS = GetParam();
+    bool signalEOS = !std::get<2>(GetParam()).compare("true");
+    // Send an empty frame to receive CSD data from encoder.
+    bool sendEmptyFirstFrame = !std::get<3>(GetParam()).compare("true");
 
-    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
     GetURLForComponent(mURL);
 
     std::ifstream eleStream;
@@ -412,25 +418,32 @@
     mTimestampDevTest = true;
     mFlushedIndices.clear();
     mTimestampUslist.clear();
-    uint32_t inputFrames = ENC_NUM_FRAMES;
+    int32_t inputFrames = ENC_NUM_FRAMES + (sendEmptyFirstFrame ? 1 : 0);
     uint32_t timestamp = 0;
+
     // Add input timestamp to timestampUslist
     while (inputFrames) {
         if (mTimestampDevTest) mTimestampUslist.push_back(timestamp);
         timestamp += ENCODER_TIMESTAMP_INCREMENT;
         inputFrames--;
     }
+
     if (!setupConfigParam(nWidth, nHeight)) {
         std::cout << "[   WARN   ] Test Skipped \n";
         return;
     }
     ASSERT_EQ(mComponent->start(), C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
-                      0, ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
+
+    if (sendEmptyFirstFrame) {
+        ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue, 0, false));
+        inputFrames += 1;
+    }
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
+                                          inputFrames, ENC_NUM_FRAMES, nWidth, nHeight, false,
+                                          signalEOS));
     // mDisableTest will be set if buffer was not fetched properly.
-    // This may happen when resolution is not proper but config suceeded
+    // This may happen when resolution is not proper but config succeeded
     // In this cases, we skip encoding the input stream
     if (mDisableTest) {
         std::cout << "[   WARN   ] Test Disabled \n";
@@ -439,27 +452,23 @@
     }
 
     // If EOS is not sent, sending empty input with EOS flag
-    inputFrames = ENC_NUM_FRAMES;
+    inputFrames += ENC_NUM_FRAMES;
     if (!signalEOS) {
-        ASSERT_NO_FATAL_FAILURE(
-            waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
-        ASSERT_NO_FATAL_FAILURE(
-            testInputBuffer(mComponent, mQueueLock, mWorkQueue,
-                            C2FrameData::FLAG_END_OF_STREAM, false));
+        ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
+        ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                                                C2FrameData::FLAG_END_OF_STREAM, false));
         inputFrames += 1;
     }
 
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     ALOGD("Waiting for input consumption");
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
 
     eleStream.close();
     if (mFramesReceived != inputFrames) {
         ALOGE("Input buffer count and Output buffer count mismatch");
-        ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived,
-              inputFrames);
+        ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived, inputFrames);
         ASSERT_TRUE(false);
     }
 
@@ -475,13 +484,9 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-// EncodeTest with EOS / No EOS
-INSTANTIATE_TEST_CASE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
-                        ::testing::Values(true, false));
-
-TEST_F(Codec2VideoEncHidlTest, EOSTest) {
+TEST_P(Codec2VideoEncHidlTest, EOSTest) {
     description("Test empty input buffer with EOS flag");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
     ASSERT_EQ(mComponent->start(), C2_OK);
 
     typedef std::unique_lock<std::mutex> ULock;
@@ -519,15 +524,15 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2VideoEncHidlTest, FlushTest) {
+TEST_P(Codec2VideoEncHidlTest, FlushTest) {
     description("Test Request for flush");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     typedef std::unique_lock<std::mutex> ULock;
     char mURL[512];
     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
     int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
-    strcpy(mURL, gEnv->getRes().c_str());
+    strcpy(mURL, sResourceDir.c_str());
     GetURLForComponent(mURL);
 
     if (!setupConfigParam(nWidth, nHeight)) {
@@ -544,12 +549,11 @@
     eleStream.open(mURL, std::ifstream::binary);
     ASSERT_EQ(eleStream.is_open(), true);
     ALOGV("mURL : %s", mURL);
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
-                      0, numFramesFlushed, nWidth, nHeight));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
+                                          numFramesFlushed, nWidth, nHeight));
     // mDisableTest will be set if buffer was not fetched properly.
-    // This may happen when resolution is not proper but config suceeded
+    // This may happen when resolution is not proper but config succeeded
     // In this cases, we skip encoding the input stream
     if (mDisableTest) {
         std::cout << "[   WARN   ] Test Disabled \n";
@@ -558,23 +562,20 @@
     }
 
     std::list<std::unique_ptr<C2Work>> flushedWork;
-    c2_status_t err =
-        mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
+    c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
     uint64_t frameIndex;
     {
-        //Update mFlushedIndices based on the index received from flush()
+        // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
             frameIndex = work->input.ordinal.frameIndex.peeku();
-            std::list<uint64_t>::iterator frameIndexIt = std::find(
-                mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+            std::list<uint64_t>::iterator frameIndexIt =
+                    std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -583,14 +584,13 @@
         }
     }
     mFlushedIndices.clear();
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
-                      numFramesFlushed, numFrames - numFramesFlushed,
-                      nWidth, nHeight, true));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
+                                          numFramesFlushed, numFrames - numFramesFlushed, nWidth,
+                                          nHeight, true));
     eleStream.close();
     // mDisableTest will be set if buffer was not fetched properly.
-    // This may happen when resolution is not proper but config suceeded
+    // This may happen when resolution is not proper but config succeeded
     // In this cases, we skip encoding the input stream
     if (mDisableTest) {
         std::cout << "[   WARN   ] Test Disabled \n";
@@ -600,19 +600,17 @@
 
     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
     ASSERT_EQ(err, C2_OK);
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
-            (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
+                                                   (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
     {
-        //Update mFlushedIndices based on the index received from flush()
+        // Update mFlushedIndices based on the index received from flush()
         ULock l(mQueueLock);
         for (std::unique_ptr<C2Work>& work : flushedWork) {
             ASSERT_NE(work, nullptr);
             frameIndex = work->input.ordinal.frameIndex.peeku();
-            std::list<uint64_t>::iterator frameIndexIt = std::find(
-                mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
-            if (!mFlushedIndices.empty() &&
-                (frameIndexIt != mFlushedIndices.end())) {
+            std::list<uint64_t>::iterator frameIndexIt =
+                    std::find(mFlushedIndices.begin(), mFlushedIndices.end(), frameIndex);
+            if (!mFlushedIndices.empty() && (frameIndexIt != mFlushedIndices.end())) {
                 mFlushedIndices.erase(frameIndexIt);
                 work->input.buffers.clear();
                 work->worklets.clear();
@@ -624,9 +622,9 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-TEST_F(Codec2VideoEncHidlTest, InvalidBufferTest) {
+TEST_P(Codec2VideoEncHidlTest, InvalidBufferTest) {
     description("Tests feeding larger/smaller input buffer");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     std::ifstream eleStream;
     int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH / 2;
@@ -638,28 +636,24 @@
     }
     ASSERT_EQ(mComponent->start(), C2_OK);
 
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
-                      0, 1, nWidth, nHeight, false, false));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
+                                          1, nWidth, nHeight, false, false));
 
     // Feed larger input buffer.
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
-                      1, 1, nWidth*2, nHeight*2, false, false));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 1,
+                                          1, nWidth * 2, nHeight * 2, false, false));
 
     // Feed smaller input buffer.
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
-                      2, 1, nWidth/2, nHeight/2, false, true));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 2,
+                                          1, nWidth / 2, nHeight / 2, false, true));
 
     // blocking call to ensures application to Wait till all the inputs are
     // consumed
     ALOGD("Waiting for input consumption");
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
 
     if (mFramesReceived != 3) {
         std::cout << "[   WARN   ] Component didn't receive all buffers back \n";
@@ -674,17 +668,23 @@
     ASSERT_EQ(mComponent->stop(), C2_OK);
 }
 
-class Codec2VideoEncResolutionTest : public Codec2VideoEncHidlTest,
-        public ::testing::WithParamInterface<std::pair<int32_t, int32_t> > {
+class Codec2VideoEncResolutionTest
+    : public Codec2VideoEncHidlTestBase,
+      public ::testing::WithParamInterface<
+              std::tuple<std::string, std::string, std::string, std::string>> {
+    void getParams() {
+        mInstanceName = std::get<0>(GetParam());
+        mComponentName = std::get<1>(GetParam());
+    }
 };
 
 TEST_P(Codec2VideoEncResolutionTest, ResolutionTest) {
     description("Tests encoding at different resolutions");
-    if (mDisableTest) return;
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
 
     std::ifstream eleStream;
-    int32_t nWidth = GetParam().first;
-    int32_t nHeight = GetParam().second;
+    int32_t nWidth = std::stoi(std::get<2>(GetParam()));
+    int32_t nHeight = std::stoi(std::get<3>(GetParam()));
     ALOGD("Trying encode for width %d height %d", nWidth, nHeight);
     mEos = false;
 
@@ -694,13 +694,12 @@
     }
     ASSERT_EQ(mComponent->start(), C2_OK);
 
-    ASSERT_NO_FATAL_FAILURE(
-        encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
-                      mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
-                      0, MAX_INPUT_BUFFERS, nWidth, nHeight, false, true));
+    ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                          mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
+                                          MAX_INPUT_BUFFERS, nWidth, nHeight, false, true));
 
     // mDisableTest will be set if buffer was not fetched properly.
-    // This may happen when resolution is not proper but config suceeded
+    // This may happen when resolution is not proper but config succeeded
     // In this cases, we skip encoding the input stream
     if (mDisableTest) {
         std::cout << "[   WARN   ] Test Disabled \n";
@@ -709,31 +708,146 @@
     }
 
     ALOGD("Waiting for input consumption");
-    ASSERT_NO_FATAL_FAILURE(
-        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
+    ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
 
     ASSERT_EQ(mEos, true);
     ASSERT_EQ(mComponent->stop(), C2_OK);
     ASSERT_EQ(mComponent->reset(), C2_OK);
 }
 
-INSTANTIATE_TEST_CASE_P(NonStdSizes, Codec2VideoEncResolutionTest, ::testing::Values(
-    std::make_pair(52, 18),
-    std::make_pair(365, 365),
-    std::make_pair(484, 362),
-    std::make_pair(244, 488)));
+INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2VideoEncHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_SUITE_P(NonStdSizes, Codec2VideoEncResolutionTest,
+                         ::testing::ValuesIn(kEncodeResolutionTestParameters));
+
+// EncodeTest with EOS / No EOS
+INSTANTIATE_TEST_SUITE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
+                         ::testing::ValuesIn(kEncodeTestParameters));
+
+TEST_P(Codec2VideoEncHidlTest, AdaptiveBitrateTest) {
+    description("Encodes input file for different bitrates");
+    if (mDisableTest) GTEST_SKIP() << "Test is disabled";
+
+    char mURL[512];
+
+    strcpy(mURL, sResourceDir.c_str());
+    GetURLForComponent(mURL);
+
+    std::ifstream eleStream;
+    eleStream.open(mURL, std::ifstream::binary);
+    ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
+    ALOGV("mURL : %s", mURL);
+
+    mFlushedIndices.clear();
+
+    int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
+    int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
+    if (!setupConfigParam(nWidth, nHeight)) {
+        std::cout << "[   WARN   ] Test Skipped \n";
+        return;
+    }
+    ASSERT_EQ(mComponent->start(), C2_OK);
+
+    uint64_t prevOutputSize = 0u;
+    uint32_t bitrateValues[] = {100000, 64000, 200000};
+    uint32_t prevBitrate = 0;
+    int32_t inputFrameId = 0;
+
+    for (uint32_t curBitrate : bitrateValues) {
+        // Configuring bitrate
+        std::vector<std::unique_ptr<C2SettingResult>> failures;
+        C2StreamBitrateInfo::output bitrate(0u, curBitrate);
+        std::vector<C2Param*> configParam{&bitrate};
+        c2_status_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
+        if (status != C2_OK && failures.size() != 0u) {
+            ALOGW("BitRate Config failed, using previous bitrate");
+        }
+
+        ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+                                              mFlushedIndices, mGraphicPool, eleStream,
+                                              mDisableTest, inputFrameId, ENC_NUM_FRAMES, nWidth,
+                                              nHeight, false, false));
+        // mDisableTest will be set if buffer was not fetched properly.
+        // This may happen when resolution is not proper but config succeeded
+        // In this cases, we skip encoding the input stream
+        if (mDisableTest) {
+            std::cout << "[   WARN   ] Test Disabled \n";
+            ASSERT_EQ(mComponent->stop(), C2_OK);
+            return;
+        }
+        inputFrameId += ENC_NUM_FRAMES;
+        // blocking call to ensures application to Wait till all the inputs are
+        // consumed
+        ALOGD("Waiting for input consumption");
+        waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
+
+        // Change in bitrate may result in different outputSize
+        if (prevBitrate >= curBitrate) {
+            EXPECT_LE(mOutputSize, prevOutputSize);
+        } else {
+            EXPECT_GE(mOutputSize, prevOutputSize);
+        }
+        prevBitrate = curBitrate;
+        prevOutputSize = mOutputSize;
+        // Reset the file pointer and output size
+        mOutputSize = 0;
+        eleStream.seekg(0, eleStream.beg);
+    }
+
+    // Sending empty input with EOS flag
+    ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+                                            C2FrameData::FLAG_END_OF_STREAM, false));
+    inputFrameId += 1;
+    waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
+
+    eleStream.close();
+    if (mFramesReceived != inputFrameId) {
+        ALOGE("Input buffer count and Output buffer count mismatch");
+        ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived, inputFrameId);
+        ASSERT_TRUE(false);
+    }
+
+    ASSERT_EQ(mComponent->stop(), C2_OK);
+}
 
 }  // anonymous namespace
 
 int main(int argc, char** argv) {
-    gEnv = new ComponentTestEnvironment();
-    ::testing::AddGlobalTestEnvironment(gEnv);
-    ::testing::InitGoogleTest(&argc, argv);
-    gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "C2 Test result = " << status;
+    kTestParameters = getTestParameters(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER);
+    for (auto params : kTestParameters) {
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "true"));
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "false"));
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "true"));
+        kEncodeTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "false"));
+
+        kEncodeResolutionTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "52", "18"));
+        kEncodeResolutionTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "365", "365"));
+        kEncodeResolutionTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "484", "362"));
+        kEncodeResolutionTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "244", "488"));
+        kEncodeResolutionTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "852", "608"));
+        kEncodeResolutionTestParameters.push_back(
+                std::make_tuple(std::get<0>(params), std::get<1>(params), "1400", "442"));
     }
-    return status;
+
+    // Set the resource directory based on command line args.
+    // Test will fail to set up if the argument is not set.
+    for (int i = 1; i < argc; i++) {
+        if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
+            sResourceDir = argv[i + 1];
+            break;
+        }
+    }
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
 }
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.xml b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.xml
new file mode 100644
index 0000000..260a616
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the"License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an"AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalMediaC2V1_0TargetVideoEncTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="vts_media_c2_v1_0_video_enc_test" value="/data/local/tmp/vts_media_c2_v1_0_video_enc_test" />
+
+        <!-- Files used for video testing -->
+        <option name="push-file" key="bbb_352x288_420p_30fps_32frames.yuv" value="/data/local/tmp/media/bbb_352x288_420p_30fps_32frames.yuv" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="vts_media_c2_v1_0_video_enc_test" />
+        <option name="native-test-flag" value="-P /data/local/tmp/media/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
index e37ca38..9c1a5cb 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
@@ -22,6 +22,7 @@
 #define ENC_DEFAULT_FRAME_WIDTH 352
 #define ENC_DEFAULT_FRAME_HEIGHT 288
 #define MAX_ITERATIONS 128
+#define FLAG_NON_DISPLAY_FRAME (1 << 4)
 
 #define ALIGN(_sz, _align) ((_sz + (_align - 1)) & ~(_align - 1))
 
@@ -29,5 +30,4 @@
  * Common video utils
  */
 
-
 #endif  // MEDIA_C2_VIDEO_HIDL_TEST_COMMON_H
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 0acab49..7e4352d 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -219,6 +219,7 @@
                 if (success) {
                     break;
                 }
+                invalidate();
                 using namespace std::chrono_literals;
                 static constexpr auto kServiceRetryPeriod = 5s;
                 LOG(INFO) << "Failed to retrieve component traits from service "
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index cc132de..1e4560c 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1406,6 +1406,9 @@
         // TODO: convert err into status_t
         mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
     }
+    // Assure buffers are not owned when stop() was called without flush().
+    std::list<std::unique_ptr<C2Work>> flushedWork;
+    mChannel->flush(flushedWork);
 
     {
         Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
@@ -1948,6 +1951,13 @@
             inputSurface->getHalInterface()));
 }
 
+static void MaybeLogUnrecognizedName(const char *func, const std::string &name) {
+    thread_local std::set<std::string> sLogged{};
+    if (sLogged.insert(name).second) {
+        ALOGW("%s: Unrecognized interface name: %s", func, name.c_str());
+    }
+}
+
 static status_t GetCommonAllocatorIds(
         const std::vector<std::string> &names,
         C2Allocator::type_t type,
@@ -1961,26 +1971,33 @@
     if (names.empty()) {
         return OK;
     }
-    std::shared_ptr<Codec2Client::Interface> intf{
-        Codec2Client::CreateInterfaceByName(names[0].c_str())};
-    std::vector<std::unique_ptr<C2Param>> params;
-    c2_status_t err = intf->query(
-            {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, &params);
-    if (err == C2_OK && params.size() == 1u) {
-        C2PortAllocatorsTuning::input *allocators =
-            C2PortAllocatorsTuning::input::From(params[0].get());
-        if (allocators && allocators->flexCount() > 0) {
-            ids->insert(allocators->m.values, allocators->m.values + allocators->flexCount());
+    bool firstIteration = true;
+    for (const std::string &name : names) {
+        std::shared_ptr<Codec2Client::Interface> intf{
+            Codec2Client::CreateInterfaceByName(name.c_str())};
+        if (!intf) {
+            MaybeLogUnrecognizedName(__FUNCTION__, name);
+            continue;
         }
-    }
-    if (ids->empty()) {
-        // The component does not advertise allocators. Use default.
-        ids->insert(defaultAllocatorId);
-    }
-    for (size_t i = 1; i < names.size(); ++i) {
-        intf = Codec2Client::CreateInterfaceByName(names[i].c_str());
-        err = intf->query(
+        std::vector<std::unique_ptr<C2Param>> params;
+        c2_status_t err = intf->query(
                 {}, {C2PortAllocatorsTuning::input::PARAM_TYPE}, C2_MAY_BLOCK, &params);
+        if (firstIteration) {
+            firstIteration = false;
+            if (err == C2_OK && params.size() == 1u) {
+                C2PortAllocatorsTuning::input *allocators =
+                    C2PortAllocatorsTuning::input::From(params[0].get());
+                if (allocators && allocators->flexCount() > 0) {
+                    ids->insert(allocators->m.values,
+                                allocators->m.values + allocators->flexCount());
+                }
+            }
+            if (ids->empty()) {
+                // The component does not advertise allocators. Use default.
+                ids->insert(defaultAllocatorId);
+            }
+            continue;
+        }
         bool filtered = false;
         if (err == C2_OK && params.size() == 1u) {
             C2PortAllocatorsTuning::input *allocators =
@@ -2033,6 +2050,10 @@
     for (const std::string &name : names) {
         std::shared_ptr<Codec2Client::Interface> intf{
             Codec2Client::CreateInterfaceByName(name.c_str())};
+        if (!intf) {
+            MaybeLogUnrecognizedName(__FUNCTION__, name);
+            continue;
+        }
         std::vector<C2FieldSupportedValuesQuery> fields;
         fields.push_back(C2FieldSupportedValuesQuery::Possible(
                 C2ParamField{&sUsage, &sUsage.value}));
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 6b389d5..3773528 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -44,6 +44,7 @@
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/SkipCutBuffer.h>
 #include <media/MediaCodecBuffer.h>
+#include <mediadrm/ICrypto.h>
 #include <system/window.h>
 
 #include "CCodecBufferChannel.h"
@@ -1084,7 +1085,7 @@
                 // TODO: handle this without going into array mode
                 forceArrayMode = true;
             } else {
-                input->buffers.reset(new GraphicInputBuffers(numInputSlots, mName));
+                input->buffers.reset(new GraphicInputBuffers(mName));
             }
         } else {
             if (hasCryptoOrDescrambler()) {
@@ -1252,7 +1253,7 @@
             if (outputSurface || !buffersBoundToCodec) {
                 output->buffers.reset(new GraphicOutputBuffers(mName));
             } else {
-                output->buffers.reset(new RawGraphicOutputBuffers(numOutputSlots, mName));
+                output->buffers.reset(new RawGraphicOutputBuffers(mName));
             }
         } else {
             output->buffers.reset(new LinearOutputBuffers(mName));
@@ -1704,8 +1705,8 @@
         }
     }
 
-    if (!buffer && !flags) {
-        ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
+    if (!buffer && !flags && outputFormat == nullptr) {
+        ALOGV("[%s] onWorkDone: nothing to report from the work (%lld)",
               mName, work->input.ordinal.frameIndex.peekull());
         return true;
     }
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 265eeb7..a9120c4 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/SkipCutBuffer.h>
+#include <mediadrm/ICrypto.h>
 
 #include "CCodecBuffers.h"
 
@@ -121,26 +122,37 @@
 
 // OutputBuffers
 
+OutputBuffers::OutputBuffers(const char *componentName, const char *name)
+    : CCodecBuffers(componentName, name) { }
+
+OutputBuffers::~OutputBuffers() = default;
+
 void OutputBuffers::initSkipCutBuffer(
         int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
     CHECK(mSkipCutBuffer == nullptr);
     mDelay = delay;
     mPadding = padding;
     mSampleRate = sampleRate;
-    setSkipCutBuffer(delay, padding, channelCount);
+    mChannelCount = channelCount;
+    setSkipCutBuffer(delay, padding);
 }
 
 void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
     if (mSkipCutBuffer == nullptr) {
         return;
     }
+    if (mSampleRate == sampleRate && mChannelCount == channelCount) {
+        return;
+    }
     int32_t delay = mDelay;
     int32_t padding = mPadding;
     if (sampleRate != mSampleRate) {
         delay = ((int64_t)delay * sampleRate) / mSampleRate;
         padding = ((int64_t)padding * sampleRate) / mSampleRate;
     }
-    setSkipCutBuffer(delay, padding, channelCount);
+    mSampleRate = sampleRate;
+    mChannelCount = channelCount;
+    setSkipCutBuffer(delay, padding);
 }
 
 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
@@ -153,20 +165,23 @@
     mSkipCutBuffer = scb;
 }
 
-void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
+void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
     if (mSkipCutBuffer != nullptr) {
         size_t prevSize = mSkipCutBuffer->size();
         if (prevSize != 0u) {
             ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
         }
     }
-    mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
+    mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
 }
 
 // LocalBufferPool
 
-std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
-    return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
+constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
+constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
+
+std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
+    return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
 }
 
 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
@@ -186,6 +201,11 @@
             mUsedSize -= mPool.back().capacity();
             mPool.pop_back();
         }
+        while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
+            ALOGD("Increasing local buffer pool capacity from %zu to %zu",
+                  mPoolCapacity, mPoolCapacity * 2);
+            mPoolCapacity *= 2;
+        }
         if (mUsedSize + capacity > mPoolCapacity) {
             ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
                     mUsedSize, capacity, mPoolCapacity);
@@ -255,6 +275,7 @@
     std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
     if (!result) {
         result = clientBuffer->asC2Buffer();
+        clientBuffer->clearC2BufferRefs();
         mBuffers[index].compBuffer = result;
     }
     if (c2buffer) {
@@ -373,6 +394,7 @@
     std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
     if (!result) {
         result = clientBuffer->asC2Buffer();
+        clientBuffer->clearC2BufferRefs();
         mBuffers[index].compBuffer = result;
     }
     if (c2buffer) {
@@ -769,11 +791,10 @@
 // GraphicInputBuffers
 
 GraphicInputBuffers::GraphicInputBuffers(
-        size_t numInputSlots, const char *componentName, const char *name)
+        const char *componentName, const char *name)
     : InputBuffers(componentName, name),
       mImpl(mName),
-      mLocalBufferPool(LocalBufferPool::Create(
-              kMaxLinearBufferSize * numInputSlots)) { }
+      mLocalBufferPool(LocalBufferPool::Create()) { }
 
 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
     sp<Codec2Buffer> newBuffer = createNewBuffer();
@@ -934,7 +955,7 @@
         case C2BufferData::GRAPHIC: {
             // This is only called for RawGraphicOutputBuffers.
             mAlloc = [format = mFormat,
-                      lbp = LocalBufferPool::Create(kMaxLinearBufferSize * mImpl.arraySize())] {
+                      lbp = LocalBufferPool::Create()] {
                 return ConstGraphicBlockBuffer::AllocateEmpty(
                         format,
                         [lbp](size_t capacity) {
@@ -1071,10 +1092,9 @@
 // RawGraphicOutputBuffers
 
 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
-        size_t numOutputSlots, const char *componentName, const char *name)
+        const char *componentName, const char *name)
     : FlexOutputBuffers(componentName, name),
-      mLocalBufferPool(LocalBufferPool::Create(
-              kMaxLinearBufferSize * numOutputSlots)) { }
+      mLocalBufferPool(LocalBufferPool::Create()) { }
 
 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
     if (buffer == nullptr) {
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index bae08e0..6244acd 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -28,6 +28,8 @@
 
 namespace android {
 
+struct ICrypto;
+class MemoryDealer;
 class SkipCutBuffer;
 
 constexpr size_t kLinearBufferSize = 1048576;
@@ -156,9 +158,8 @@
 
 class OutputBuffers : public CCodecBuffers {
 public:
-    OutputBuffers(const char *componentName, const char *name = "Output")
-        : CCodecBuffers(componentName, name) { }
-    virtual ~OutputBuffers() = default;
+    OutputBuffers(const char *componentName, const char *name = "Output");
+    virtual ~OutputBuffers();
 
     /**
      * Register output C2Buffer from the component and obtain corresponding
@@ -228,8 +229,9 @@
     int32_t mDelay;
     int32_t mPadding;
     int32_t mSampleRate;
+    int32_t mChannelCount;
 
-    void setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount);
+    void setSkipCutBuffer(int32_t skip, int32_t cut);
 
     DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
 };
@@ -242,11 +244,9 @@
     /**
      * Create a new LocalBufferPool object.
      *
-     * \param poolCapacity  max total size of buffers managed by this pool.
-     *
      * \return  a newly created pool object.
      */
-    static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity);
+    static std::shared_ptr<LocalBufferPool> Create();
 
     /**
      * Return an ABuffer object whose size is at least |capacity|.
@@ -678,8 +678,7 @@
 
 class GraphicInputBuffers : public InputBuffers {
 public:
-    GraphicInputBuffers(
-            size_t numInputSlots, const char *componentName, const char *name = "2D-BB-Input");
+    GraphicInputBuffers(const char *componentName, const char *name = "2D-BB-Input");
     ~GraphicInputBuffers() override = default;
 
     bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
@@ -891,8 +890,7 @@
 
 class RawGraphicOutputBuffers : public FlexOutputBuffers {
 public:
-    RawGraphicOutputBuffers(
-            size_t numOutputSlots, const char *componentName, const char *name = "2D-BB-Output");
+    RawGraphicOutputBuffers(const char *componentName, const char *name = "2D-BB-Output");
     ~RawGraphicOutputBuffers() override = default;
 
     sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 051f88a..96f86e8 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -617,6 +617,11 @@
             return C2Value();
         }));
 
+    add(ConfigMapper(KEY_PIXEL_ASPECT_RATIO_WIDTH,  C2_PARAMKEY_PIXEL_ASPECT_RATIO, "width")
+        .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
+    add(ConfigMapper(KEY_PIXEL_ASPECT_RATIO_HEIGHT, C2_PARAMKEY_PIXEL_ASPECT_RATIO, "height")
+        .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
+
     add(ConfigMapper(KEY_CHANNEL_COUNT, C2_PARAMKEY_CHANNEL_COUNT,       "value")
         .limitTo(D::AUDIO)); // read back to both formats
     add(ConfigMapper(KEY_CHANNEL_COUNT, C2_PARAMKEY_CODED_CHANNEL_COUNT, "value")
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index b6d18e2..25e7da9 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "Codec2Buffer"
 #include <utils/Log.h>
 
+#include <android/hardware/cas/native/1.0/types.h>
+#include <android/hardware/drm/1.0/types.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <media/hardware/HardwareAPI.h>
 #include <media/stagefright/CodecBase.h>
@@ -25,6 +27,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
+#include <mediadrm/ICrypto.h>
 #include <nativebase/nativebase.h>
 #include <ui/Fence.h>
 
@@ -111,7 +114,11 @@
 }
 
 std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
-    return std::move(mBufferRef);
+    return mBufferRef;
+}
+
+void DummyContainerBuffer::clearC2BufferRefs() {
+    mBufferRef.reset();
 }
 
 bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
@@ -187,7 +194,11 @@
 }
 
 std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
-    return std::move(mBufferRef);
+    return mBufferRef;
+}
+
+void ConstLinearBlockBuffer::clearC2BufferRefs() {
+    mBufferRef.reset();
 }
 
 // GraphicView2MediaImageConverter
@@ -689,8 +700,12 @@
 }
 
 std::shared_ptr<C2Buffer> ConstGraphicBlockBuffer::asC2Buffer() {
+    return mBufferRef;
+}
+
+void ConstGraphicBlockBuffer::clearC2BufferRefs() {
     mView.reset();
-    return std::move(mBufferRef);
+    mBufferRef.reset();
 }
 
 bool ConstGraphicBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index 09475ef..dc788cd 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -20,16 +20,29 @@
 
 #include <C2Buffer.h>
 
-#include <android/hardware/cas/native/1.0/types.h>
-#include <android/hardware/drm/1.0/types.h>
 #include <binder/IMemory.h>
 #include <media/hardware/VideoAPI.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/MediaCodecBuffer.h>
-#include <mediadrm/ICrypto.h>
 
 namespace android {
 
+namespace hardware {
+class HidlMemory;
+namespace cas {
+namespace native {
+namespace V1_0 {
+struct SharedBuffer;
+}  // namespace V1_0
+}  // namespace native
+}  // namespace cas
+namespace drm {
+namespace V1_0 {
+struct SharedBuffer;
+}  // namespace V1_0
+}  // namespace drm
+}  // namespace hardware
+
 /**
  * Copies a graphic view into a media image.
  *
@@ -59,6 +72,8 @@
 
     sp<ABuffer> getImageData() const { return mImageData; }
 
+    virtual void clearC2BufferRefs() {}
+
 protected:
     /**
      * canCopy() implementation for linear buffers.
@@ -102,6 +117,7 @@
             const std::shared_ptr<C2Buffer> &buffer = nullptr);
 
     std::shared_ptr<C2Buffer> asC2Buffer() override;
+    void clearC2BufferRefs() override;
     bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
     bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
 
@@ -161,6 +177,7 @@
     virtual ~ConstLinearBlockBuffer() = default;
 
     std::shared_ptr<C2Buffer> asC2Buffer() override;
+    void clearC2BufferRefs() override;
 
 private:
     ConstLinearBlockBuffer(
@@ -280,6 +297,7 @@
     virtual ~ConstGraphicBlockBuffer() = default;
 
     std::shared_ptr<C2Buffer> asC2Buffer() override;
+    void clearC2BufferRefs() override;
     bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
     bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
 
diff --git a/media/codec2/sfplugin/tests/Android.bp b/media/codec2/sfplugin/tests/Android.bp
index fe5fa68..8d1a9c3 100644
--- a/media/codec2/sfplugin/tests/Android.bp
+++ b/media/codec2/sfplugin/tests/Android.bp
@@ -2,12 +2,13 @@
     name: "ccodec_unit_test",
 
     srcs: [
+        "CCodecBuffers_test.cpp",
         "CCodecConfig_test.cpp",
         "ReflectedParamUpdater_test.cpp",
     ],
 
     defaults: [
-        "libcodec2-hidl-defaults@1.0",
+        "libcodec2-impl-defaults",
         "libcodec2-internal-defaults",
     ],
 
@@ -16,14 +17,24 @@
     ],
 
     shared_libs: [
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
         "libcodec2",
         "libcodec2_client",
+        "libhidlbase",
+        "libfmq",
+        "libmedia_omx",
         "libsfplugin_ccodec",
         "libsfplugin_ccodec_utils",
         "libstagefright_foundation",
         "libutils",
     ],
 
+    static_libs: [
+        "libcodec2_hidl@1.0",
+        "libstagefright_bufferpool@2.0",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
new file mode 100644
index 0000000..5bee605
--- /dev/null
+++ b/media/codec2/sfplugin/tests/CCodecBuffers_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CCodecBuffers.h"
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/MediaCodecConstants.h>
+
+#include <C2PlatformSupport.h>
+
+namespace android {
+
+TEST(RawGraphicOutputBuffersTest, ChangeNumSlots) {
+    constexpr int32_t kWidth = 3840;
+    constexpr int32_t kHeight = 2160;
+
+    std::shared_ptr<RawGraphicOutputBuffers> buffers =
+        std::make_shared<RawGraphicOutputBuffers>("test");
+    sp<AMessage> format{new AMessage};
+    format->setInt32("width", kWidth);
+    format->setInt32("height", kHeight);
+    buffers->setFormat(format);
+
+    std::shared_ptr<C2BlockPool> pool;
+    ASSERT_EQ(OK, GetCodec2BlockPool(C2BlockPool::BASIC_GRAPHIC, nullptr, &pool));
+
+    // Register 4 buffers
+    std::vector<sp<MediaCodecBuffer>> clientBuffers;
+    auto registerBuffer = [&buffers, &clientBuffers, &pool] {
+        std::shared_ptr<C2GraphicBlock> block;
+        ASSERT_EQ(OK, pool->fetchGraphicBlock(
+                kWidth, kHeight, HAL_PIXEL_FORMAT_YCbCr_420_888,
+                C2MemoryUsage{C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
+        std::shared_ptr<C2Buffer> c2Buffer = C2Buffer::CreateGraphicBuffer(block->share(
+                block->crop(), C2Fence{}));
+        size_t index;
+        sp<MediaCodecBuffer> clientBuffer;
+        ASSERT_EQ(OK, buffers->registerBuffer(c2Buffer, &index, &clientBuffer));
+        ASSERT_NE(nullptr, clientBuffer);
+        while (clientBuffers.size() <= index) {
+            clientBuffers.emplace_back();
+        }
+        ASSERT_EQ(nullptr, clientBuffers[index]) << "index = " << index;
+        clientBuffers[index] = clientBuffer;
+    };
+    for (int i = 0; i < 4; ++i) {
+        registerBuffer();
+    }
+
+    // Release 2 buffers
+    auto releaseBuffer = [&buffers, &clientBuffers, kWidth, kHeight](int index) {
+        std::shared_ptr<C2Buffer> c2Buffer;
+        ASSERT_TRUE(buffers->releaseBuffer(clientBuffers[index], &c2Buffer))
+                << "index = " << index;
+        clientBuffers[index] = nullptr;
+        // Sanity checks
+        ASSERT_TRUE(c2Buffer->data().linearBlocks().empty());
+        ASSERT_EQ(1u, c2Buffer->data().graphicBlocks().size());
+        C2ConstGraphicBlock block = c2Buffer->data().graphicBlocks().front();
+        ASSERT_EQ(kWidth, block.width());
+        ASSERT_EQ(kHeight, block.height());
+    };
+    for (int i = 0, index = 0; i < 2 && index < clientBuffers.size(); ++index) {
+        if (clientBuffers[index] == nullptr) {
+            continue;
+        }
+        releaseBuffer(index);
+        ++i;
+    }
+
+    // Simulate # of slots 4->16
+    for (int i = 2; i < 16; ++i) {
+        registerBuffer();
+    }
+
+    // Release everything
+    for (int index = 0; index < clientBuffers.size(); ++index) {
+        if (clientBuffers[index] == nullptr) {
+            continue;
+        }
+        releaseBuffer(index);
+    }
+}
+
+} // namespace android
diff --git a/media/codec2/sfplugin/tests/CCodecConfig_test.cpp b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
index 7b445a0..c9caa01 100644
--- a/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
+++ b/media/codec2/sfplugin/tests/CCodecConfig_test.cpp
@@ -24,6 +24,8 @@
 #include <codec2/hidl/client.h>
 #include <util/C2InterfaceHelper.h>
 
+#include <media/stagefright/MediaCodecConstants.h>
+
 namespace {
 
 enum ExtendedC2ParamIndexKind : C2Param::type_index_t {
@@ -56,9 +58,15 @@
 
     CCodecConfigTest()
         : mReflector{std::make_shared<C2ReflectorHelper>()} {
+    }
+
+    void init(
+            C2Component::domain_t domain,
+            C2Component::kind_t kind,
+            const char *mediaType) {
         sp<hardware::media::c2::V1_0::utils::CachedConfigurable> cachedConfigurable =
             new hardware::media::c2::V1_0::utils::CachedConfigurable(
-                    std::make_unique<Configurable>(mReflector));
+                    std::make_unique<Configurable>(mReflector, domain, kind, mediaType));
         cachedConfigurable->init(std::make_shared<Cache>());
         mConfigurable = std::make_shared<Codec2Client::Configurable>(cachedConfigurable);
     }
@@ -71,9 +79,13 @@
 
     class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf {
     public:
-        explicit Configurable(const std::shared_ptr<C2ReflectorHelper> &reflector)
+        Configurable(
+                const std::shared_ptr<C2ReflectorHelper> &reflector,
+                C2Component::domain_t domain,
+                C2Component::kind_t kind,
+                const char *mediaType)
             : ConfigurableC2Intf("name", 0u),
-              mImpl(reflector) {
+              mImpl(reflector, domain, kind, mediaType) {
         }
 
         c2_status_t query(
@@ -104,11 +116,68 @@
     private:
         class Impl : public C2InterfaceHelper {
         public:
-            explicit Impl(const std::shared_ptr<C2ReflectorHelper> &reflector)
+            Impl(const std::shared_ptr<C2ReflectorHelper> &reflector,
+                    C2Component::domain_t domain,
+                    C2Component::kind_t kind,
+                    const char *mediaType)
                 : C2InterfaceHelper{reflector} {
+
                 setDerivedInstance(this);
 
                 addParameter(
+                        DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN)
+                        .withConstValue(new C2ComponentDomainSetting(domain))
+                        .build());
+
+                addParameter(
+                        DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
+                        .withConstValue(new C2ComponentKindSetting(kind))
+                        .build());
+
+                addParameter(
+                        DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT)
+                        .withConstValue(new C2PortStreamCountTuning::input(1))
+                        .build());
+
+                addParameter(
+                        DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT)
+                        .withConstValue(new C2PortStreamCountTuning::output(1))
+                        .build());
+
+                const char *rawMediaType = "";
+                switch (domain) {
+                    case C2Component::DOMAIN_IMAGE: [[fallthrough]];
+                    case C2Component::DOMAIN_VIDEO:
+                        rawMediaType = MIMETYPE_VIDEO_RAW;
+                        break;
+                    case C2Component::DOMAIN_AUDIO:
+                        rawMediaType = MIMETYPE_AUDIO_RAW;
+                        break;
+                    default:
+                        break;
+                }
+                bool isEncoder = kind == C2Component::KIND_ENCODER;
+                std::string inputMediaType{isEncoder ? rawMediaType : mediaType};
+                std::string outputMediaType{isEncoder ? mediaType : rawMediaType};
+
+                auto allocSharedString = [](const auto &param, const std::string &str) {
+                    typedef typename std::remove_reference<decltype(param)>::type::element_type T;
+                    std::shared_ptr<T> ret = T::AllocShared(str.length() + 1);
+                    strcpy(ret->m.value, str.c_str());
+                    return ret;
+                };
+
+                addParameter(
+                        DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
+                        .withConstValue(allocSharedString(mInputMediaType, inputMediaType))
+                        .build());
+
+                addParameter(
+                        DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
+                        .withConstValue(allocSharedString(mOutputMediaType, outputMediaType))
+                        .build());
+
+                addParameter(
                         DefineParam(mInt32Input, C2_PARAMKEY_VENDOR_INT32)
                         .withDefault(new C2PortVendorInt32Info::input(0))
                         .withFields({C2F(mInt32Input, value).any()})
@@ -129,12 +198,29 @@
                         .withSetter(Setter<decltype(mStringInput)::element_type>)
                         .build());
 
-                // TODO: SDK params
+                addParameter(
+                        DefineParam(mPixelAspectRatio, C2_PARAMKEY_PIXEL_ASPECT_RATIO)
+                        .withDefault(new C2StreamPixelAspectRatioInfo::output(0u, 1, 1))
+                        .withFields({
+                            C2F(mPixelAspectRatio, width).any(),
+                            C2F(mPixelAspectRatio, height).any(),
+                        })
+                        .withSetter(Setter<C2StreamPixelAspectRatioInfo::output>)
+                        .build());
+
+                // TODO: more SDK params
             }
         private:
+            std::shared_ptr<C2ComponentDomainSetting> mDomain;
+            std::shared_ptr<C2ComponentKindSetting> mKind;
+            std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount;
+            std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount;
+            std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
+            std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
             std::shared_ptr<C2PortVendorInt32Info::input> mInt32Input;
             std::shared_ptr<C2StreamVendorInt64Info::output> mInt64Output;
             std::shared_ptr<C2PortVendorStringInfo::input> mStringInput;
+            std::shared_ptr<C2StreamPixelAspectRatioInfo::output> mPixelAspectRatio;
 
             template<typename T>
             static C2R Setter(bool, C2P<T> &) {
@@ -163,6 +249,10 @@
 }
 
 TEST_F(CCodecConfigTest, SetVendorParam) {
+    // Test at audio domain, as video domain has a few local parameters that
+    // interfere with the testing.
+    init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
+
     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
 
     sp<AMessage> format{new AMessage};
@@ -172,7 +262,7 @@
 
     std::vector<std::unique_ptr<C2Param>> configUpdate;
     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
-            mConfigurable, format, D::IS_INPUT | D::IS_OUTPUT, C2_MAY_BLOCK, &configUpdate));
+            mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
 
     ASSERT_EQ(3u, configUpdate.size());
     C2PortVendorInt32Info::input *i32 =
@@ -192,6 +282,10 @@
 }
 
 TEST_F(CCodecConfigTest, VendorParamUpdate_Unsubscribed) {
+    // Test at audio domain, as video domain has a few local parameters that
+    // interfere with the testing.
+    init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
+
     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
 
     std::vector<std::unique_ptr<C2Param>> configUpdate;
@@ -204,7 +298,7 @@
     configUpdate.push_back(std::move(str));
 
     // The vendor parameters are not yet subscribed
-    ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
+    ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::ALL));
 
     int32_t vendorInt32{0};
     ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
@@ -226,6 +320,10 @@
 }
 
 TEST_F(CCodecConfigTest, VendorParamUpdate_AllSubscribed) {
+    // Test at audio domain, as video domain has a few local parameters that
+    // interfere with the testing.
+    init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
+
     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
 
     // Force subscribe to all vendor params
@@ -240,7 +338,7 @@
     configUpdate.push_back(C2Param::Copy(i64));
     configUpdate.push_back(std::move(str));
 
-    ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
+    ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
 
     int32_t vendorInt32{0};
     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
@@ -265,6 +363,10 @@
 }
 
 TEST_F(CCodecConfigTest, VendorParamUpdate_PartiallySubscribed) {
+    // Test at audio domain, as video domain has a few local parameters that
+    // interfere with the testing.
+    init(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER, MIMETYPE_AUDIO_AAC);
+
     ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
 
     // Subscribe to example.int32 only
@@ -273,7 +375,7 @@
     format->setInt32(KEY_VENDOR_INT32, 0);
     configUpdate.clear();
     ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
-            mConfigurable, format, D::IS_INPUT | D::IS_OUTPUT, C2_MAY_BLOCK, &configUpdate));
+            mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
     ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
 
     C2PortVendorInt32Info::input i32(kCodec2Int32);
@@ -286,7 +388,7 @@
     configUpdate.push_back(std::move(str));
 
     // Only example.i32 should be updated
-    ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
+    ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
 
     int32_t vendorInt32{0};
     ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
@@ -308,4 +410,51 @@
             << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
 }
 
+TEST_F(CCodecConfigTest, SetPixelAspectRatio) {
+    init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
+
+    ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+    sp<AMessage> format{new AMessage};
+    format->setInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, 12);
+    format->setInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, 11);
+
+    std::vector<std::unique_ptr<C2Param>> configUpdate;
+    ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
+            mConfigurable, format, D::ALL, C2_MAY_BLOCK, &configUpdate));
+
+    ASSERT_EQ(1u, configUpdate.size());
+    C2StreamPixelAspectRatioInfo::output *par =
+        FindParam<std::remove_pointer<decltype(par)>::type>(configUpdate);
+    ASSERT_NE(nullptr, par);
+    ASSERT_EQ(12, par->width);
+    ASSERT_EQ(11, par->height);
+}
+
+TEST_F(CCodecConfigTest, PixelAspectRatioUpdate) {
+    init(C2Component::DOMAIN_VIDEO, C2Component::KIND_DECODER, MIMETYPE_VIDEO_AVC);
+
+    ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
+
+    std::vector<std::unique_ptr<C2Param>> configUpdate;
+    C2StreamPixelAspectRatioInfo::output par(0u, 12, 11);
+    configUpdate.push_back(C2Param::Copy(par));
+
+    ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::ALL));
+
+    int32_t parWidth{0};
+    ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
+            << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+    ASSERT_EQ(12, parWidth);
+    ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_WIDTH, &parWidth))
+            << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+
+    int32_t parHeight{0};
+    ASSERT_TRUE(mConfig.mOutputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
+            << "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
+    ASSERT_EQ(11, parHeight);
+    ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_PIXEL_ASPECT_RATIO_HEIGHT, &parHeight))
+            << "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
+}
+
 } // namespace android
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 3ac3d89..e1e1377 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -520,6 +520,22 @@
             break;
         }
 
+        case static_cast<uint32_t>(PixelFormat4::BLOB): {
+            void *pointer = nullptr;
+            // TODO: fence
+            status_t err = GraphicBufferMapper::get().lock(
+                                const_cast<native_handle_t*>(mBuffer), grallocUsage,
+                                { (int32_t)rect.left, (int32_t)rect.top,
+                                  (int32_t)rect.width, (int32_t)rect.height },
+                                &pointer);
+            if (err) {
+                ALOGE("failed transaction: lock(BLOB)");
+                return C2_CORRUPTED;
+            }
+            *addr = (uint8_t *)pointer;
+            break;
+        }
+
         case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
             // fall-through
         case static_cast<uint32_t>(PixelFormat4::YV12):
diff --git a/media/codec2/vndk/util/C2InterfaceUtils.cpp b/media/codec2/vndk/util/C2InterfaceUtils.cpp
index 61ec911..0c1729b 100644
--- a/media/codec2/vndk/util/C2InterfaceUtils.cpp
+++ b/media/codec2/vndk/util/C2InterfaceUtils.cpp
@@ -216,9 +216,14 @@
     if (limit.contains(minMask) && contains(minMask)) {
         values[0] = minMask;
         // keep only flags that are covered by limit
-        std::remove_if(values.begin(), values.end(), [&limit, minMask](const C2Value::Primitive &v) -> bool {
-            T value = v.ref<ValueType>() | minMask;
-            return value == minMask || !limit.contains(value); });
+        values.erase(std::remove_if(values.begin(), values.end(),
+                                    [&limit, minMask](
+                                        const C2Value::Primitive &v) -> bool {
+                                      T value = v.ref<ValueType>() | minMask;
+                                      return value == minMask ||
+                                             !limit.contains(value);
+                                    }),
+                     values.end());
         // we also need to do it vice versa
         for (const C2Value::Primitive &v : _mValues) {
             T value = v.ref<ValueType>() | minMask;
@@ -264,24 +269,33 @@
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedValueSet<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedRange<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedFlags<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 3675611..826c1a0 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -9,6 +9,7 @@
     ],
 
     shared_libs: [
+        "libbase",
         "libbinder_ndk",
     ],
 
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 5329bd1..0617e88 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -24,6 +24,7 @@
 // libFLAC parser
 #include "FLAC/stream_decoder.h"
 
+#include <android-base/properties.h>
 #include <android/binder_ibinder.h> // for AIBinder_getCallingUid
 #include <audio_utils/primitives.h>
 #include <media/MediaExtractorPluginApi.h>
@@ -47,7 +48,8 @@
 // (Note: duplicated with WAVExtractor.cpp)
 static inline bool shouldExtractorOutputFloat(int bitsPerSample)
 {
-    return bitsPerSample > 16 && AIBinder_getCallingUid() == AID_MEDIA;
+    return bitsPerSample > 16 && AIBinder_getCallingUid() == AID_MEDIA
+                              && android::base::GetBoolProperty("media.extractor.float", true);
 }
 
 class FLACParser;
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index bdb724b..b8255fc 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -10,7 +10,7 @@
 
     static_libs: [
         "libmedia_midiiowrapper",
-        "libsonivox",
+        "libsonivoxwithoutjet",
         "libstagefright_foundation",
         "libwatchdog",
     ],
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 044c4d0..a051648 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -339,7 +339,12 @@
 }
 
 void BlockIterator::advance_l() {
-    for (;;) {
+    for (int i = 0;; i++) {
+        if (i == 1000) {
+            ALOGE("no block found after %d iterations, stopping", i);
+            mCluster = NULL;
+            break;
+        }
         long res = mCluster->GetEntry(mBlockEntryIndex, mBlockEntry);
         ALOGV("GetEntry returned %ld", res);
 
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index a838ae6..5165822 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -227,17 +227,17 @@
 
 private:
     static const size_t kMaxFrameSize;
-    AMediaFormat *mMeta;
-    DataSourceHelper *mDataSource;
-    off64_t mFirstFramePos;
-    uint32_t mFixedHeader;
-    off64_t mCurrentPos;
-    int64_t mCurrentTimeUs;
-    bool mStarted;
-    MP3Seeker *mSeeker;
+    AMediaFormat *mMeta = NULL;
+    DataSourceHelper *mDataSource = NULL;
+    off64_t mFirstFramePos = 0;
+    uint32_t mFixedHeader = 0;
+    off64_t mCurrentPos = 0;
+    int64_t mCurrentTimeUs = 0;
+    bool mStarted = false;
+    MP3Seeker *mSeeker = NULL;
 
-    int64_t mBasisTimeUs;
-    int64_t mSamplesRead;
+    int64_t mBasisTimeUs = 0;
+    int64_t mSamplesRead = 0;
 
     MP3Source(const MP3Source &);
     MP3Source &operator=(const MP3Source &);
@@ -251,11 +251,7 @@
 
 MP3Extractor::MP3Extractor(
         DataSourceHelper *source, Mp3Meta *meta)
-    : mInitCheck(NO_INIT),
-      mDataSource(source),
-      mFirstFramePos(-1),
-      mFixedHeader(0),
-      mSeeker(NULL) {
+    : mDataSource(source) {
 
     off64_t pos = 0;
     off64_t post_id3_pos;
@@ -442,6 +438,7 @@
 //  (8000 samples/sec * 8 bits/byte)) + 1 padding byte/frame = 2881 bytes/frame.
 // Set our max frame size to the nearest power of 2 above this size (aka, 4kB)
 const size_t MP3Source::kMaxFrameSize = (1 << 12); /* 4096 bytes */
+
 MP3Source::MP3Source(
         AMediaFormat *meta, DataSourceHelper *source,
         off64_t first_frame_pos, uint32_t fixed_header,
@@ -450,12 +447,7 @@
       mDataSource(source),
       mFirstFramePos(first_frame_pos),
       mFixedHeader(fixed_header),
-      mCurrentPos(0),
-      mCurrentTimeUs(0),
-      mStarted(false),
-      mSeeker(seeker),
-      mBasisTimeUs(0),
-      mSamplesRead(0) {
+      mSeeker(seeker) {
 }
 
 MP3Source::~MP3Source() {
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 1e38ab7..a2345da 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -45,13 +45,13 @@
     virtual const char * name() { return "MP3Extractor"; }
 
 private:
-    status_t mInitCheck;
+    status_t mInitCheck = NO_INIT;
 
-    DataSourceHelper *mDataSource;
-    off64_t mFirstFramePos;
-    AMediaFormat *mMeta;
-    uint32_t mFixedHeader;
-    MP3Seeker *mSeeker;
+    DataSourceHelper *mDataSource = NULL;
+    off64_t mFirstFramePos = -1;
+    AMediaFormat *mMeta = NULL;
+    uint32_t mFixedHeader = 0;
+    MP3Seeker *mSeeker = NULL;
 
     MP3Extractor(const MP3Extractor &);
     MP3Extractor &operator=(const MP3Extractor &);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index ce82861..54f1fa2 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -19,6 +19,7 @@
 
 #include <ctype.h>
 #include <inttypes.h>
+#include <algorithm>
 #include <memory>
 #include <stdint.h>
 #include <stdlib.h>
@@ -112,6 +113,7 @@
     const Trex *mTrex;
     off64_t mFirstMoofOffset;
     off64_t mCurrentMoofOffset;
+    off64_t mCurrentMoofSize;
     off64_t mNextMoofOffset;
     uint32_t mCurrentTime; // in media timescale ticks
     int32_t mLastParsedTrackId;
@@ -149,9 +151,13 @@
     bool mIsAudio;
     sp<ItemTable> mItemTable;
 
-    // Start offset from composition time to presentation time.
-    // Support shift only for video tracks through mElstShiftStartTicks for now.
+    /* Shift start offset (move to earlier time) when media_time > 0,
+     * in media time scale.
+     */
     uint64_t mElstShiftStartTicks;
+    /* Initial start offset (move to later time), empty edit list entry
+     * in media time scale.
+     */
     uint64_t mElstInitialEmptyEditTicks;
 
     size_t parseNALSize(const uint8_t *data) const;
@@ -160,8 +166,9 @@
     status_t parseTrackFragmentRun(off64_t offset, off64_t size);
     status_t parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size);
     status_t parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size);
-    status_t parseClearEncryptedSizes(off64_t offset, bool isSubsampleEncryption, uint32_t flags);
-    status_t parseSampleEncryption(off64_t offset);
+    status_t parseClearEncryptedSizes(off64_t offset, bool isSampleEncryption,
+            uint32_t flags, off64_t size);
+    status_t parseSampleEncryption(off64_t offset, off64_t size);
     // returns -1 for invalid layer ID
     int32_t parseHEVCLayerId(const uint8_t *data, size_t size);
 
@@ -1070,6 +1077,8 @@
                     // drop it now to reduce our footprint
                     free(mLastTrack->mTx3gBuffer);
                     mLastTrack->mTx3gBuffer = NULL;
+                    mLastTrack->mTx3gFilled = 0;
+                    mLastTrack->mTx3gSize = 0;
                 }
 
                 const char *mime;
@@ -1215,7 +1224,6 @@
                 off64_t entriesoffset = data_offset + 8;
                 uint64_t segment_duration;
                 int64_t media_time;
-                uint64_t empty_edit_ticks = 0;
                 bool empty_edit_present = false;
                 for (int i = 0; i < entry_count; ++i) {
                     switch (version) {
@@ -1247,45 +1255,33 @@
                     }
                     // Empty edit entry would have to be first entry.
                     if (media_time == -1 && i == 0) {
-                        int64_t durationUs;
-                        if (AMediaFormat_getInt64(mFileMetaData, AMEDIAFORMAT_KEY_DURATION,
-                                                  &durationUs)) {
-                            empty_edit_ticks = segment_duration;
-                            ALOGV("initial empty edit ticks: %" PRIu64, empty_edit_ticks);
-                            empty_edit_present = true;
-                        }
-                    }
-                    // Process second entry only when the first entry was an empty edit entry.
-                    if (empty_edit_present && i == 1) {
-                        int64_t durationUs;
-                        if (AMediaFormat_getInt64(mLastTrack->meta, AMEDIAFORMAT_KEY_DURATION,
-                                                  &durationUs) &&
-                            mHeaderTimescale != 0) {
-                            // Support only segment_duration<=track_duration and media_time==0 case.
-                            uint64_t segmentDurationUs =
-                                    segment_duration * 1000000 / mHeaderTimescale;
-                            if (segmentDurationUs == 0 || segmentDurationUs > durationUs ||
-                                media_time != 0) {
-                                ALOGW("for now, unsupported second entry in empty edit list");
-                            }
-                        }
+                        empty_edit_present = true;
+                        ALOGV("initial empty edit ticks: %" PRIu64, segment_duration);
+                        /* In movie header timescale, and needs to be converted to media timescale
+                         * after we get that from a track's 'mdhd' atom,
+                         * which at times come after 'elst'.
+                         */
+                        mLastTrack->elst_initial_empty_edit_ticks = segment_duration;
+                    } else if (media_time >= 0 && i == 0) {
+                        ALOGV("first edit list entry - from gapless playback files");
+                        mLastTrack->elst_media_time = media_time;
+                        mLastTrack->elst_segment_duration = segment_duration;
+                        ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64,
+                              segment_duration, media_time);
+                        // media_time is in media timescale as are STTS/CTTS entries.
+                        mLastTrack->elst_shift_start_ticks = media_time;
+                    } else if (empty_edit_present && i == 1) {
+                        // Process second entry only when the first entry was an empty edit entry.
+                        ALOGV("second edit list entry");
+                        mLastTrack->elst_shift_start_ticks = media_time;
+                    } else {
+                        ALOGW("for now, unsupported entry in edit list %" PRIu32, entry_count);
                     }
                 }
                 // save these for later, because the elst atom might precede
                 // the atoms that actually gives us the duration and sample rate
                 // needed to calculate the padding and delay values
                 mLastTrack->elst_needs_processing = true;
-                if (empty_edit_present) {
-                    /* In movie header timescale, and needs to be converted to media timescale once
-                     * we get that from a track's 'mdhd' atom, which at times come after 'elst'.
-                     */
-                    mLastTrack->elst_initial_empty_edit_ticks = empty_edit_ticks;
-                } else {
-                    mLastTrack->elst_media_time = media_time;
-                    mLastTrack->elst_segment_duration = segment_duration;
-                    ALOGV("segment_duration: %" PRIu64 " media_time: %" PRId64, segment_duration,
-                          media_time);
-                }
             }
             break;
         }
@@ -2791,6 +2787,10 @@
             // if those apps are compensating for it, we'd break them with such a change
             //
 
+            if (mLastTrack->mTx3gBuffer == NULL) {
+                mLastTrack->mTx3gSize = 0;
+                mLastTrack->mTx3gFilled = 0;
+            }
             if (mLastTrack->mTx3gSize - mLastTrack->mTx3gFilled < chunk_size) {
                 size_t growth = kTx3gGrowth;
                 if (growth < chunk_size) {
@@ -2898,7 +2898,7 @@
                 return ERROR_MALFORMED;
             }
 
-            parseID3v2MetaData(data_offset + 6);
+            parseID3v2MetaData(data_offset + 6, chunk_data_size - 6);
 
             break;
         }
@@ -4169,8 +4169,19 @@
     return OK;
 }
 
-void MPEG4Extractor::parseID3v2MetaData(off64_t offset) {
-    ID3 id3(mDataSource, true /* ignorev1 */, offset);
+void MPEG4Extractor::parseID3v2MetaData(off64_t offset, uint64_t size) {
+    uint8_t *buffer = new (std::nothrow) uint8_t[size];
+    if (buffer == NULL) {
+        return;
+    }
+    if (mDataSource->readAt(offset, buffer, size) != (ssize_t)size) {
+        delete[] buffer;
+        buffer = NULL;
+        return;
+    }
+
+    ID3 id3(buffer, size, true /* ignorev1 */);
+    delete[] buffer;
 
     if (id3.isValid()) {
         struct Map {
@@ -4324,9 +4335,9 @@
         }
     }
 
-    // media_time is in media timescale as are STTS/CTTS entries.
-    track->elst_shift_start_ticks = track->elst_media_time;
     ALOGV("track->elst_shift_start_ticks :%" PRIu64, track->elst_shift_start_ticks);
+
+    uint64_t elst_initial_empty_edit_ticks = 0;
     if (mHeaderTimescale != 0) {
         // Convert empty_edit_ticks from movie timescale to media timescale.
         uint64_t elst_initial_empty_edit_ticks_mul = 0, elst_initial_empty_edit_ticks_add = 0;
@@ -4337,15 +4348,15 @@
             ALOGE("track->elst_initial_empty_edit_ticks overflow");
             return nullptr;
         }
-        track->elst_initial_empty_edit_ticks = elst_initial_empty_edit_ticks_add / mHeaderTimescale;
-        ALOGV("track->elst_initial_empty_edit_ticks :%" PRIu64,
-              track->elst_initial_empty_edit_ticks);
+        elst_initial_empty_edit_ticks = elst_initial_empty_edit_ticks_add / mHeaderTimescale;
     }
+    ALOGV("elst_initial_empty_edit_ticks in MediaTimeScale :%" PRIu64,
+          elst_initial_empty_edit_ticks);
 
     MPEG4Source* source =
             new MPEG4Source(track->meta, mDataSource, track->timescale, track->sampleTable,
                             mSidxEntries, trex, mMoofOffset, itemTable,
-                            track->elst_shift_start_ticks, track->elst_initial_empty_edit_ticks);
+                            track->elst_shift_start_ticks, elst_initial_empty_edit_ticks);
     if (source->init() != OK) {
         delete source;
         return NULL;
@@ -4850,6 +4861,7 @@
       mTrex(trex),
       mFirstMoofOffset(firstMoofOffset),
       mCurrentMoofOffset(firstMoofOffset),
+      mCurrentMoofSize(0),
       mNextMoofOffset(-1),
       mCurrentTime(0),
       mDefaultEncryptedByteBlock(0),
@@ -5100,6 +5112,9 @@
         case FOURCC("moof"): {
             off64_t stop_offset = *offset + chunk_size;
             *offset = data_offset;
+            if (chunk_type == FOURCC("moof")) {
+                mCurrentMoofSize = chunk_data_size;
+            }
             while (*offset < stop_offset) {
                 status_t err = parseChunk(offset);
                 if (err != OK) {
@@ -5188,7 +5203,7 @@
 
         case FOURCC("senc"): {
             status_t err;
-            if ((err = parseSampleEncryption(data_offset)) != OK) {
+            if ((err = parseSampleEncryption(data_offset, chunk_data_size)) != OK) {
                 return err;
             }
             *offset += chunk_size;
@@ -5381,11 +5396,11 @@
 
     drmoffset += mCurrentMoofOffset;
 
-    return parseClearEncryptedSizes(drmoffset, false, 0);
+    return parseClearEncryptedSizes(drmoffset, false, 0, mCurrentMoofSize);
 }
 
 status_t MPEG4Source::parseClearEncryptedSizes(
-        off64_t offset, bool isSubsampleEncryption, uint32_t flags) {
+        off64_t offset, bool isSampleEncryption, uint32_t flags, off64_t size) {
 
     int32_t ivlength;
     if (!AMediaFormat_getInt32(mFormat, AMEDIAFORMAT_KEY_CRYPTO_DEFAULT_IV_SIZE, &ivlength)) {
@@ -5399,11 +5414,15 @@
     }
 
     uint32_t sampleCount = mCurrentSampleInfoCount;
-    if (isSubsampleEncryption) {
+    if (isSampleEncryption) {
+        if (size < 4) {
+            return ERROR_MALFORMED;
+        }
         if (!mDataSource->getUInt32(offset, &sampleCount)) {
             return ERROR_IO;
         }
         offset += 4;
+        size -= 4;
     }
 
     // read CencSampleAuxiliaryDataFormats
@@ -5418,14 +5437,18 @@
         }
 
         memset(smpl->iv, 0, 16);
+        if (size < ivlength) {
+            return ERROR_MALFORMED;
+        }
         if (mDataSource->readAt(offset, smpl->iv, ivlength) != ivlength) {
             return ERROR_IO;
         }
 
         offset += ivlength;
+        size -= ivlength;
 
         bool readSubsamples;
-        if (isSubsampleEncryption) {
+        if (isSampleEncryption) {
             readSubsamples = flags & 2;
         } else {
             int32_t smplinfosize = mCurrentDefaultSampleInfoSize;
@@ -5437,13 +5460,20 @@
 
         if (readSubsamples) {
             uint16_t numsubsamples;
+            if (size < 2) {
+                return ERROR_MALFORMED;
+            }
             if (!mDataSource->getUInt16(offset, &numsubsamples)) {
                 return ERROR_IO;
             }
             offset += 2;
+            size -= 2;
             for (size_t j = 0; j < numsubsamples; j++) {
                 uint16_t numclear;
                 uint32_t numencrypted;
+                if (size < 6) {
+                    return ERROR_MALFORMED;
+                }
                 if (!mDataSource->getUInt16(offset, &numclear)) {
                     return ERROR_IO;
                 }
@@ -5452,6 +5482,7 @@
                     return ERROR_IO;
                 }
                 offset += 4;
+                size -= 6;
                 smpl->clearsizes.add(numclear);
                 smpl->encryptedsizes.add(numencrypted);
             }
@@ -5464,12 +5495,15 @@
     return OK;
 }
 
-status_t MPEG4Source::parseSampleEncryption(off64_t offset) {
+status_t MPEG4Source::parseSampleEncryption(off64_t offset, off64_t chunk_data_size) {
     uint32_t flags;
+    if (chunk_data_size < 4) {
+        return ERROR_MALFORMED;
+    }
     if (!mDataSource->getUInt32(offset, &flags)) { // actually version + flags
         return ERROR_MALFORMED;
     }
-    return parseClearEncryptedSizes(offset + 4, true, flags);
+    return parseClearEncryptedSizes(offset + 4, true, flags, chunk_data_size - 4);
 }
 
 status_t MPEG4Source::parseTrackFragmentHeader(off64_t offset, off64_t size) {
@@ -5846,7 +5880,7 @@
     ReadOptions::SeekMode mode;
 
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
-
+        ALOGV("seekTimeUs:%" PRId64, seekTimeUs);
         if (mIsHeif) {
             CHECK(mSampleTable == NULL);
             CHECK(mItemTable != NULL);
@@ -5885,9 +5919,22 @@
                     break;
             }
             if( mode != ReadOptions::SEEK_FRAME_INDEX) {
-                seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
-                ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRIu64, seekTimeUs,
-                      mElstShiftStartTicks);
+                int64_t elstInitialEmptyEditUs = 0, elstShiftStartUs = 0;
+                if (mElstInitialEmptyEditTicks > 0) {
+                    elstInitialEmptyEditUs = ((long double)mElstInitialEmptyEditTicks * 1000000) /
+                                             mTimescale;
+                    /* Sample's composition time from ctts/stts entries are non-negative(>=0).
+                     * Hence, lower bound on seekTimeUs is 0.
+                     */
+                    seekTimeUs = std::max(seekTimeUs - elstInitialEmptyEditUs, (int64_t)0);
+                }
+                if (mElstShiftStartTicks > 0) {
+                    elstShiftStartUs = ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
+                    seekTimeUs += elstShiftStartUs;
+                }
+                ALOGV("shifted seekTimeUs:%" PRId64 ", elstInitialEmptyEditUs:%" PRIu64
+                      ", elstShiftStartUs:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs,
+                      elstShiftStartUs);
             }
 
             uint32_t sampleIndex;
@@ -5933,7 +5980,16 @@
 
             if (mode == ReadOptions::SEEK_CLOSEST
                 || mode == ReadOptions::SEEK_FRAME_INDEX) {
-                sampleTime -= mElstShiftStartTicks;
+                if (mElstInitialEmptyEditTicks > 0) {
+                    sampleTime += mElstInitialEmptyEditTicks;
+                }
+                if (mElstShiftStartTicks > 0){
+                    if (sampleTime > mElstShiftStartTicks) {
+                        sampleTime -= mElstShiftStartTicks;
+                    } else {
+                        sampleTime = 0;
+                    }
+                }
                 targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
             }
 
@@ -5976,12 +6032,12 @@
             if(err == OK) {
                 if (mElstInitialEmptyEditTicks > 0) {
                     cts += mElstInitialEmptyEditTicks;
-                } else {
+                }
+                if (mElstShiftStartTicks > 0) {
                     // cts can be negative. for example, initial audio samples for gapless playback.
                     cts -= (int64_t)mElstShiftStartTicks;
                 }
             }
-
         } else {
             err = mItemTable->getImageOffsetAndSize(
                     options && options->getSeekTo(&seekTimeUs, &mode) ?
@@ -6261,10 +6317,23 @@
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
-
-        seekTimeUs += ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
-        ALOGV("shifted seekTimeUs :%" PRId64 ", mElstShiftStartTicks:%" PRIu64, seekTimeUs,
-              mElstShiftStartTicks);
+        ALOGV("seekTimeUs:%" PRId64, seekTimeUs);
+        int64_t elstInitialEmptyEditUs = 0, elstShiftStartUs = 0;
+        if (mElstInitialEmptyEditTicks > 0) {
+            elstInitialEmptyEditUs = ((long double)mElstInitialEmptyEditTicks * 1000000) /
+                                     mTimescale;
+            /* Sample's composition time from ctts/stts entries are non-negative(>=0).
+             * Hence, lower bound on seekTimeUs is 0.
+             */
+            seekTimeUs = std::max(seekTimeUs - elstInitialEmptyEditUs, (int64_t)0);
+        }
+        if (mElstShiftStartTicks > 0){
+            elstShiftStartUs = ((long double)mElstShiftStartTicks * 1000000) / mTimescale;
+            seekTimeUs += elstShiftStartUs;
+        }
+        ALOGV("shifted seekTimeUs:%" PRId64 ", elstInitialEmptyEditUs:%" PRIu64
+              ", elstShiftStartUs:%" PRIu64, seekTimeUs, elstInitialEmptyEditUs,
+              elstShiftStartUs);
 
         int numSidxEntries = mSegments.size();
         if (numSidxEntries != 0) {
@@ -6355,7 +6424,8 @@
 
         if (mElstInitialEmptyEditTicks > 0) {
             cts += mElstInitialEmptyEditTicks;
-        } else {
+        }
+        if (mElstShiftStartTicks > 0) {
             // cts can be negative. for example, initial audio samples for gapless playback.
             cts -= (int64_t)mElstShiftStartTicks;
         }
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 53ec6bc..1e49d50 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -88,9 +88,9 @@
          */
         int64_t elst_media_time;
         uint64_t elst_segment_duration;
-        // Shift start offset only when media_time > 0.
+        // Shift start offset (move to earlier time) when media_time > 0.
         uint64_t elst_shift_start_ticks;
-        // Initial start offset, empty edit list entry.
+        // Initial start offset (move to later time), from empty edit list entry.
         uint64_t elst_initial_empty_edit_ticks;
         bool subsample_encryption;
 
@@ -161,7 +161,7 @@
     status_t parseITunesMetaData(off64_t offset, size_t size);
     status_t parseColorInfo(off64_t offset, size_t size);
     status_t parse3GPPMetaData(off64_t offset, size_t size, int depth);
-    void parseID3v2MetaData(off64_t offset);
+    void parseID3v2MetaData(off64_t offset, uint64_t size);
     status_t parseQTMetaKey(off64_t data_offset, size_t data_size);
     status_t parseQTMetaVal(int32_t keyId, off64_t data_offset, size_t data_size);
 
diff --git a/media/extractors/tests/Android.bp b/media/extractors/tests/Android.bp
index fa39b64..b3afe2f 100644
--- a/media/extractors/tests/Android.bp
+++ b/media/extractors/tests/Android.bp
@@ -45,7 +45,7 @@
         "libstagefright_metadatautils",
 
         "libmedia_midiiowrapper",
-        "libsonivox",
+        "libsonivoxwithoutjet",
         "libvorbisidec",
         "libwebm",
         "libFLAC",
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 8ce5c3f..5d38a81 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -10,6 +10,7 @@
     ],
 
     shared_libs: [
+        "libbase",
         "libbinder_ndk",
     ],
 
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 4fa7f27..d19447a 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -20,6 +20,7 @@
 
 #include "WAVExtractor.h"
 
+#include <android-base/properties.h>
 #include <android/binder_ibinder.h> // for AIBinder_getCallingUid
 #include <audio_utils/primitives.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -43,7 +44,8 @@
 // (Note: duplicated with FLACExtractor.cpp)
 static inline bool shouldExtractorOutputFloat(int bitsPerSample)
 {
-    return bitsPerSample > 16 && AIBinder_getCallingUid() == AID_MEDIA;
+    return bitsPerSample > 16 && AIBinder_getCallingUid() == AID_MEDIA
+                              && android::base::GetBoolProperty("media.extractor.float", true);
 }
 
 enum {
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index edc09a9..a47f189 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -406,6 +406,7 @@
      * Use this preset for capturing audio meant to be processed in real time
      * and played back for live performance (e.g karaoke).
      * The capture path will minimize latency and coupling with playback path.
+     * Available since API level 29.
      */
     AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE = 10,
 };
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 901c28f..717f31a 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -35,6 +35,9 @@
         "libaaudio_internal",
         "libaudioclient",
         "libaudioutils",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "liblog",
         "libcutils",
         "libutils",
@@ -75,6 +78,9 @@
     shared_libs: [
         "libaudioclient",
         "libaudioutils",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "liblog",
         "libcutils",
         "libutils",
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index f9da8b4..e8c91fc 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -98,8 +98,9 @@
                                                   pid_t clientThreadId) override;
 
     aaudio_result_t startClient(aaudio_handle_t streamHandle __unused,
-                                      const android::AudioClient& client __unused,
-                                      audio_port_handle_t *clientHandle) override {
+                                const android::AudioClient& client __unused,
+                                const audio_attributes_t *attr __unused,
+                                audio_port_handle_t *clientHandle __unused) override {
         return AAUDIO_ERROR_UNAVAILABLE;
     }
 
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index a64405b..9c28cc7 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -89,8 +89,9 @@
                                                   pid_t clientThreadId) = 0;
 
     virtual aaudio_result_t startClient(aaudio_handle_t streamHandle,
-                                      const android::AudioClient& client,
-                                      audio_port_handle_t *clientHandle) = 0;
+                                        const android::AudioClient& client,
+                                        const audio_attributes_t *attr,
+                                        audio_port_handle_t *clientHandle) = 0;
 
     virtual aaudio_result_t stopClient(aaudio_handle_t streamHandle,
                                        audio_port_handle_t clientHandle) = 0;
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 214f888..06f66d3 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -32,19 +32,12 @@
 #define RIDICULOUSLY_LARGE_FRAME_SIZE        4096
 
 AudioEndpoint::AudioEndpoint()
-    : mUpCommandQueue(nullptr)
-    , mDataQueue(nullptr)
-    , mFreeRunning(false)
+    : mFreeRunning(false)
     , mDataReadCounter(0)
     , mDataWriteCounter(0)
 {
 }
 
-AudioEndpoint::~AudioEndpoint() {
-    delete mDataQueue;
-    delete mUpCommandQueue;
-}
-
 // TODO Consider moving to a method in RingBufferDescriptor
 static aaudio_result_t AudioEndpoint_validateQueueDescriptor(const char *type,
                                                   const RingBufferDescriptor *descriptor) {
@@ -144,7 +137,7 @@
         return AAUDIO_ERROR_INTERNAL;
     }
 
-    mUpCommandQueue = new FifoBuffer(
+    mUpCommandQueue = std::make_unique<FifoBuffer>(
             descriptor->bytesPerFrame,
             descriptor->capacityInFrames,
             descriptor->readCounterAddress,
@@ -173,7 +166,7 @@
                                   ? &mDataWriteCounter
                                   : descriptor->writeCounterAddress;
 
-    mDataQueue = new FifoBuffer(
+    mDataQueue = std::make_unique<FifoBuffer>(
             descriptor->bytesPerFrame,
             descriptor->capacityInFrames,
             readCounterAddress,
@@ -194,18 +187,15 @@
     return mDataQueue->getEmptyRoomAvailable(wrappingBuffer);
 }
 
-int32_t AudioEndpoint::getEmptyFramesAvailable()
-{
+int32_t AudioEndpoint::getEmptyFramesAvailable() {
     return mDataQueue->getEmptyFramesAvailable();
 }
 
-int32_t AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer)
-{
+int32_t AudioEndpoint::getFullFramesAvailable(WrappingBuffer *wrappingBuffer) {
     return mDataQueue->getFullDataAvailable(wrappingBuffer);
 }
 
-int32_t AudioEndpoint::getFullFramesAvailable()
-{
+int32_t AudioEndpoint::getFullFramesAvailable() {
     return mDataQueue->getFullFramesAvailable();
 }
 
@@ -217,29 +207,24 @@
     mDataQueue->advanceReadIndex(deltaFrames);
 }
 
-void AudioEndpoint::setDataReadCounter(fifo_counter_t framesRead)
-{
+void AudioEndpoint::setDataReadCounter(fifo_counter_t framesRead) {
     mDataQueue->setReadCounter(framesRead);
 }
 
-fifo_counter_t AudioEndpoint::getDataReadCounter()
-{
+fifo_counter_t AudioEndpoint::getDataReadCounter() const {
     return mDataQueue->getReadCounter();
 }
 
-void AudioEndpoint::setDataWriteCounter(fifo_counter_t framesRead)
-{
+void AudioEndpoint::setDataWriteCounter(fifo_counter_t framesRead) {
     mDataQueue->setWriteCounter(framesRead);
 }
 
-fifo_counter_t AudioEndpoint::getDataWriteCounter()
-{
+fifo_counter_t AudioEndpoint::getDataWriteCounter() const {
     return mDataQueue->getWriteCounter();
 }
 
 int32_t AudioEndpoint::setBufferSizeInFrames(int32_t requestedFrames,
-                                            int32_t *actualFrames)
-{
+                                            int32_t *actualFrames) {
     if (requestedFrames < ENDPOINT_DATA_QUEUE_SIZE_MIN) {
         requestedFrames = ENDPOINT_DATA_QUEUE_SIZE_MIN;
     }
@@ -248,19 +233,17 @@
     return AAUDIO_OK;
 }
 
-int32_t AudioEndpoint::getBufferSizeInFrames() const
-{
+int32_t AudioEndpoint::getBufferSizeInFrames() const {
     return mDataQueue->getThreshold();
 }
 
-int32_t AudioEndpoint::getBufferCapacityInFrames() const
-{
+int32_t AudioEndpoint::getBufferCapacityInFrames() const {
     return (int32_t)mDataQueue->getBufferCapacityInFrames();
 }
 
 void AudioEndpoint::dump() const {
-    ALOGD("data readCounter  = %lld", (long long) mDataQueue->getReadCounter());
-    ALOGD("data writeCounter = %lld", (long long) mDataQueue->getWriteCounter());
+    ALOGD("data readCounter  = %lld", (long long) getDataReadCounter());
+    ALOGD("data writeCounter = %lld", (long long) getDataWriteCounter());
 }
 
 void AudioEndpoint::eraseDataMemory() {
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index f5b67e8..484d917 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -35,7 +35,6 @@
 
 public:
     AudioEndpoint();
-    virtual ~AudioEndpoint();
 
     /**
      * Configure based on the EndPointDescriptor_t.
@@ -67,11 +66,11 @@
      */
     void setDataReadCounter(android::fifo_counter_t framesRead);
 
-    android::fifo_counter_t getDataReadCounter();
+    android::fifo_counter_t getDataReadCounter() const;
 
     void setDataWriteCounter(android::fifo_counter_t framesWritten);
 
-    android::fifo_counter_t getDataWriteCounter();
+    android::fifo_counter_t getDataWriteCounter() const;
 
     /**
      * The result is not valid until after configure() is called.
@@ -94,8 +93,8 @@
     void dump() const;
 
 private:
-    android::FifoBuffer    *mUpCommandQueue;
-    android::FifoBuffer    *mDataQueue;
+    std::unique_ptr<android::FifoBuffer> mUpCommandQueue;
+    std::unique_ptr<android::FifoBuffer> mDataQueue;
     bool                    mFreeRunning;
     android::fifo_counter_t mDataReadCounter; // only used if free-running
     android::fifo_counter_t mDataWriteCounter; // only used if free-running
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index b6548e6..79fa5ed 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-// This file is used in both client and server processes.
-// This is needed to make sense of the logs more easily.
-#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
+#define LOG_TAG "AudioStreamInternal"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
@@ -28,6 +26,8 @@
 
 #include <aaudio/AAudio.h>
 #include <cutils/properties.h>
+
+#include <media/MediaMetricsItem.h>
 #include <utils/String16.h>
 #include <utils/Trace.h>
 
@@ -36,12 +36,20 @@
 #include "binding/AAudioStreamConfiguration.h"
 #include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
+#include "core/AudioGlobal.h"
 #include "core/AudioStreamBuilder.h"
 #include "fifo/FifoBuffer.h"
 #include "utility/AudioClock.h"
 
 #include "AudioStreamInternal.h"
 
+// We do this after the #includes because if a header uses ALOG.
+// it would fail on the reference to mInService.
+#undef LOG_TAG
+// This file is used in both client and server processes.
+// This is needed to make sense of the logs more easily.
+#define LOG_TAG (mInService ? "AudioStreamInternal_Service" : "AudioStreamInternal_Client")
+
 using android::String16;
 using android::Mutex;
 using android::WrappingBuffer;
@@ -58,7 +66,6 @@
 AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService)
         : AudioStream()
         , mClockModel()
-        , mAudioEndpoint()
         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
         , mInService(inService)
         , mServiceInterface(serviceInterface)
@@ -74,7 +81,6 @@
 aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
 
     aaudio_result_t result = AAUDIO_OK;
-    int32_t capacity;
     int32_t framesPerBurst;
     int32_t framesPerHardwareBurst;
     AAudioStreamRequest request;
@@ -139,6 +145,11 @@
         return mServiceStreamHandle;
     }
 
+    // This must match the key generated in oboeservice/AAudioServiceStreamBase.cpp
+    // so the client can have permission to log.
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM)
+            + std::to_string(mServiceStreamHandle);
+
     result = configurationOutput.validate();
     if (result != AAUDIO_OK) {
         goto error;
@@ -173,7 +184,8 @@
     }
 
     // Configure endpoint based on descriptor.
-    result = mAudioEndpoint.configure(&mEndpointDescriptor, getDirection());
+    mAudioEndpoint = std::make_unique<AudioEndpoint>();
+    result = mAudioEndpoint->configure(&mEndpointDescriptor, getDirection());
     if (result != AAUDIO_OK) {
         goto error;
     }
@@ -201,9 +213,10 @@
     }
     mFramesPerBurst = framesPerBurst; // only save good value
 
-    capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
-    if (capacity < mFramesPerBurst || capacity > MAX_BUFFER_CAPACITY_IN_FRAMES) {
-        ALOGE("%s - bufferCapacity out of range = %d", __func__, capacity);
+    mBufferCapacityInFrames = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
+    if (mBufferCapacityInFrames < mFramesPerBurst
+            || mBufferCapacityInFrames > MAX_BUFFER_CAPACITY_IN_FRAMES) {
+        ALOGE("%s - bufferCapacity out of range = %d", __func__, mBufferCapacityInFrames);
         result = AAUDIO_ERROR_OUT_OF_RANGE;
         goto error;
     }
@@ -230,7 +243,7 @@
         }
 
         const int32_t callbackBufferSize = mCallbackFrames * getBytesPerFrame();
-        mCallbackBuffer = new uint8_t[callbackBufferSize];
+        mCallbackBuffer = std::make_unique<uint8_t[]>(callbackBufferSize);
     }
 
     // For debugging and analyzing the distribution of MMAP timestamps.
@@ -239,7 +252,7 @@
     // You can use this offset to reduce glitching.
     // You can also use this offset to force glitching. By iterating over multiple
     // values you can reveal the distribution of the hardware timing jitter.
-    if (mAudioEndpoint.isFreeRunning()) { // MMAP?
+    if (mAudioEndpoint->isFreeRunning()) { // MMAP?
         int32_t offsetMicros = (getDirection() == AAUDIO_DIRECTION_OUTPUT)
                 ? AAudioProperty_getOutputMMapOffsetMicros()
                 : AAudioProperty_getInputMMapOffsetMicros();
@@ -251,7 +264,7 @@
         mTimeOffsetNanos = offsetMicros * AAUDIO_NANOS_PER_MICROSECOND;
     }
 
-    setBufferSize(capacity / 2); // Default buffer size to match Q
+    setBufferSize(mBufferCapacityInFrames / 2); // Default buffer size to match Q
 
     setState(AAUDIO_STREAM_STATE_OPEN);
 
@@ -274,13 +287,20 @@
         if (isActive() || currentState == AAUDIO_STREAM_STATE_DISCONNECTED) {
             requestStop();
         }
+
+        logBufferState();
+
         setState(AAUDIO_STREAM_STATE_CLOSING);
         aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
         mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
 
         mServiceInterface.closeStream(serviceStreamHandle);
-        delete[] mCallbackBuffer;
-        mCallbackBuffer = nullptr;
+        mCallbackBuffer.reset();
+
+        // Update local frame counters so we can query them after releasing the endpoint.
+        getFramesRead();
+        getFramesWritten();
+        mAudioEndpoint.reset();
         result = mEndPointParcelable.close();
         aaudio_result_t result2 = AudioStream::release_l();
         return (result != AAUDIO_OK) ? result : result2;
@@ -334,6 +354,12 @@
     drainTimestampsFromService();
 
     aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);
+    if (result == AAUDIO_ERROR_INVALID_HANDLE) {
+        ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__);
+        // Stealing was added in R. Coerce result to improve backward compatibility.
+        result = AAUDIO_ERROR_DISCONNECTED;
+        setState(AAUDIO_STREAM_STATE_DISCONNECTED);
+    }
 
     startTime = AudioClock::getNanoseconds();
     mClockModel.start(startTime);
@@ -377,7 +403,12 @@
     if (isDataCallbackSet()
             && (isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) {
         mCallbackEnabled.store(false);
-        return joinThread(NULL); // may temporarily unlock mStreamLock
+        aaudio_result_t result = joinThread(NULL); // may temporarily unlock mStreamLock
+        if (result == AAUDIO_ERROR_INVALID_HANDLE) {
+            ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__);
+            result = AAUDIO_OK;
+        }
+        return result;
     } else {
         return AAUDIO_OK;
     }
@@ -407,7 +438,12 @@
     setState(AAUDIO_STREAM_STATE_STOPPING);
     mAtomicInternalTimestamp.clear();
 
-    return mServiceInterface.stopStream(mServiceStreamHandle);
+    result = mServiceInterface.stopStream(mServiceStreamHandle);
+    if (result == AAUDIO_ERROR_INVALID_HANDLE) {
+        ALOGD("%s() INVALID_HANDLE, stream was probably stolen", __func__);
+        result = AAUDIO_OK;
+    }
+    return result;
 }
 
 aaudio_result_t AudioStreamInternal::registerThread() {
@@ -429,13 +465,14 @@
 }
 
 aaudio_result_t AudioStreamInternal::startClient(const android::AudioClient& client,
+                                                 const audio_attributes_t *attr,
                                                  audio_port_handle_t *portHandle) {
     ALOGV("%s() called", __func__);
     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
         return AAUDIO_ERROR_INVALID_STATE;
     }
     aaudio_result_t result =  mServiceInterface.startClient(mServiceStreamHandle,
-                                                            client, portHandle);
+                                                            client, attr, portHandle);
     ALOGV("%s(%d) returning %d", __func__, *portHandle, result);
     return result;
 }
@@ -538,7 +575,7 @@
         case AAUDIO_SERVICE_EVENT_DISCONNECTED:
             // Prevent hardware from looping on old data and making buzzing sounds.
             if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
-                mAudioEndpoint.eraseDataMemory();
+                mAudioEndpoint->eraseDataMemory();
             }
             result = AAUDIO_ERROR_DISCONNECTED;
             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
@@ -564,7 +601,10 @@
 
     while (result == AAUDIO_OK) {
         AAudioServiceMessage message;
-        if (mAudioEndpoint.readUpCommand(&message) != 1) {
+        if (!mAudioEndpoint) {
+            break;
+        }
+        if (mAudioEndpoint->readUpCommand(&message) != 1) {
             break; // no command this time, no problem
         }
         switch (message.what) {
@@ -592,7 +632,10 @@
 
     while (result == AAUDIO_OK) {
         AAudioServiceMessage message;
-        if (mAudioEndpoint.readUpCommand(&message) != 1) {
+        if (!mAudioEndpoint) {
+            break;
+        }
+        if (mAudioEndpoint->readUpCommand(&message) != 1) {
             break; // no command this time, no problem
         }
         switch (message.what) {
@@ -625,7 +668,7 @@
     const char * fifoName = "aaRdy";
     ATRACE_BEGIN(traceName);
     if (ATRACE_ENABLED()) {
-        int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+        int32_t fullFrames = mAudioEndpoint->getFullFramesAvailable();
         ATRACE_INT(fifoName, fullFrames);
     }
 
@@ -654,7 +697,7 @@
         if (timeoutNanoseconds == 0) {
             break; // don't block
         } else if (wakeTimeNanos != 0) {
-            if (!mAudioEndpoint.isFreeRunning()) {
+            if (!mAudioEndpoint->isFreeRunning()) {
                 // If there is software on the other end of the FIFO then it may get delayed.
                 // So wake up just a little after we expect it to be ready.
                 wakeTimeNanos += mWakeupDelayNanos;
@@ -679,12 +722,12 @@
                 ALOGW("processData(): past deadline by %d micros",
                       (int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND));
                 mClockModel.dump();
-                mAudioEndpoint.dump();
+                mAudioEndpoint->dump();
                 break;
             }
 
             if (ATRACE_ENABLED()) {
-                int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+                int32_t fullFrames = mAudioEndpoint->getFullFramesAvailable();
                 ATRACE_INT(fifoName, fullFrames);
                 int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos;
                 ATRACE_INT("aaSlpNs", (int32_t)sleepForNanos);
@@ -696,7 +739,7 @@
     }
 
     if (ATRACE_ENABLED()) {
-        int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
+        int32_t fullFrames = mAudioEndpoint->getFullFramesAvailable();
         ATRACE_INT(fifoName, fullFrames);
     }
 
@@ -713,12 +756,8 @@
 aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
     int32_t adjustedFrames = requestedFrames;
     const int32_t maximumSize = getBufferCapacity() - mFramesPerBurst;
-    // The buffer size can be set to zero.
-    // This means that the callback may be called when the internal buffer becomes empty.
-    // This will be fine on some devices in ideal circumstances and will result in the
-    // lowest possible latency.
-    // If there are glitches then they should be detected as XRuns and the size can be increased.
-    static const int32_t minimumSize = 0;
+    // Minimum size should be a multiple number of bursts.
+    const int32_t minimumSize = 1 * mFramesPerBurst;
 
     // Clip to minimum size so that rounding up will work better.
     adjustedFrames = std::max(minimumSize, adjustedFrames);
@@ -730,13 +769,19 @@
         // Round to the next highest burst size.
         int32_t numBursts = (adjustedFrames + mFramesPerBurst - 1) / mFramesPerBurst;
         adjustedFrames = numBursts * mFramesPerBurst;
+        // Clip just in case maximumSize is not a multiple of mFramesPerBurst.
+        adjustedFrames = std::min(maximumSize, adjustedFrames);
     }
 
-    // Clip against the actual size from the endpoint.
-    int32_t actualFrames = 0;
-    mAudioEndpoint.setBufferSizeInFrames(maximumSize, &actualFrames);
-    // actualFrames should be <= maximumSize
-    adjustedFrames = std::min(actualFrames, adjustedFrames);
+    if (mAudioEndpoint) {
+        // Clip against the actual size from the endpoint.
+        int32_t actualFrames = 0;
+        // Set to maximum size so we can write extra data when ready in order to reduce glitches.
+        // The amount we keep in the buffer is controlled by mBufferSizeInFrames.
+        mAudioEndpoint->setBufferSizeInFrames(maximumSize, &actualFrames);
+        // actualFrames should be <= actual maximum size of endpoint
+        adjustedFrames = std::min(actualFrames, adjustedFrames);
+    }
 
     mBufferSizeInFrames = adjustedFrames;
     ALOGV("%s(%d) returns %d", __func__, requestedFrames, adjustedFrames);
@@ -748,7 +793,7 @@
 }
 
 int32_t AudioStreamInternal::getBufferCapacity() const {
-    return mAudioEndpoint.getBufferCapacityInFrames();
+    return mBufferCapacityInFrames;
 }
 
 int32_t AudioStreamInternal::getFramesPerBurst() const {
@@ -761,5 +806,5 @@
 }
 
 bool AudioStreamInternal::isClockModelInControl() const {
-    return isActive() && mAudioEndpoint.isFreeRunning() && mClockModel.isRunning();
+    return isActive() && mAudioEndpoint->isFreeRunning() && mClockModel.isRunning();
 }
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 8843a8a..61591b3 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -90,6 +90,7 @@
     int64_t calculateReasonableTimeout();
 
     aaudio_result_t startClient(const android::AudioClient& client,
+                                const audio_attributes_t *attr,
                                 audio_port_handle_t *clientHandle);
 
     aaudio_result_t stopClient(audio_port_handle_t clientHandle);
@@ -154,7 +155,8 @@
 
     IsochronousClockModel    mClockModel;      // timing model for chasing the HAL
 
-    AudioEndpoint            mAudioEndpoint;   // source for reads or sink for writes
+    std::unique_ptr<AudioEndpoint> mAudioEndpoint;   // source for reads or sink for writes
+
     aaudio_handle_t          mServiceStreamHandle; // opaque handle returned from service
 
     int32_t                  mFramesPerBurst = MIN_FRAMES_PER_BURST; // frames per HAL transfer
@@ -163,7 +165,7 @@
     // Offset from underlying frame position.
     int64_t                  mFramesOffsetFromService = 0; // offset for timestamps
 
-    uint8_t                 *mCallbackBuffer = nullptr;
+    std::unique_ptr<uint8_t[]> mCallbackBuffer;
     int32_t                  mCallbackFrames = 0;
 
     // The service uses this for SHARED mode.
@@ -177,6 +179,9 @@
 
     float                    mStreamVolume = 1.0f;
 
+    int64_t                  mLastFramesWritten = 0;
+    int64_t                  mLastFramesRead = 0;
+
 private:
     /*
      * Asynchronous write with data conversion.
@@ -206,6 +211,8 @@
     int32_t                  mDeviceChannelCount = 0;
 
     int32_t                  mBufferSizeInFrames = 0; // local threshold to control latency
+    int32_t                  mBufferCapacityInFrames = 0;
+
 
 };
 
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 9684ee4..9fa2e40 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -42,8 +42,8 @@
 AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
 
 void AudioStreamInternalCapture::advanceClientToMatchServerPosition() {
-    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
-    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+    int64_t readCounter = mAudioEndpoint->getDataReadCounter();
+    int64_t writeCounter = mAudioEndpoint->getDataWriteCounter();
 
     // Bump offset so caller does not see the retrograde motion in getFramesRead().
     int64_t offset = readCounter - writeCounter;
@@ -53,7 +53,7 @@
 
     // Force readCounter to match writeCounter.
     // This is because we cannot change the write counter in the hardware.
-    mAudioEndpoint.setDataReadCounter(writeCounter);
+    mAudioEndpoint->setDataReadCounter(writeCounter);
 }
 
 // Write the data, block if needed and timeoutMillis > 0
@@ -86,7 +86,7 @@
     }
     // If we have gotten this far then we have at least one timestamp from server.
 
-    if (mAudioEndpoint.isFreeRunning()) {
+    if (mAudioEndpoint->isFreeRunning()) {
         //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
         // Update data queue based on the timing model.
         // Jitter in the DSP can cause late writes to the FIFO.
@@ -95,7 +95,7 @@
         // that the DSP could have written the data.
         int64_t estimatedRemoteCounter = mClockModel.convertLatestTimeToPosition(currentNanoTime);
         // TODO refactor, maybe use setRemoteCounter()
-        mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
+        mAudioEndpoint->setDataWriteCounter(estimatedRemoteCounter);
     }
 
     // This code assumes that we have already received valid timestamps.
@@ -108,8 +108,8 @@
 
     // If the capture buffer is full beyond capacity then consider it an overrun.
     // For shared streams, the xRunCount is passed up from the service.
-    if (mAudioEndpoint.isFreeRunning()
-        && mAudioEndpoint.getFullFramesAvailable() > mAudioEndpoint.getBufferCapacityInFrames()) {
+    if (mAudioEndpoint->isFreeRunning()
+        && mAudioEndpoint->getFullFramesAvailable() > mAudioEndpoint->getBufferCapacityInFrames()) {
         mXRunCount++;
         if (ATRACE_ENABLED()) {
             ATRACE_INT("aaOverRuns", mXRunCount);
@@ -143,7 +143,7 @@
                 // Calculate frame position based off of the readCounter because
                 // the writeCounter might have just advanced in the background,
                 // causing us to sleep until a later burst.
-                int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
+                int64_t nextPosition = mAudioEndpoint->getDataReadCounter() + mFramesPerBurst;
                 wakeTime = mClockModel.convertPositionToLatestTime(nextPosition);
             }
                 break;
@@ -166,7 +166,7 @@
     uint8_t *destination = (uint8_t *) buffer;
     int32_t framesLeft = numFrames;
 
-    mAudioEndpoint.getFullFramesAvailable(&wrappingBuffer);
+    mAudioEndpoint->getFullFramesAvailable(&wrappingBuffer);
 
     // Read data in one or two parts.
     for (int partIndex = 0; framesLeft > 0 && partIndex < WrappingBuffer::SIZE; partIndex++) {
@@ -208,26 +208,29 @@
     }
 
     int32_t framesProcessed = numFrames - framesLeft;
-    mAudioEndpoint.advanceReadIndex(framesProcessed);
+    mAudioEndpoint->advanceReadIndex(framesProcessed);
 
     //ALOGD("readNowWithConversion() returns %d", framesProcessed);
     return framesProcessed;
 }
 
 int64_t AudioStreamInternalCapture::getFramesWritten() {
-    const int64_t framesWrittenHardware = isClockModelInControl()
-            ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
-            : mAudioEndpoint.getDataWriteCounter();
-    // Add service offset and prevent retrograde motion.
-    mLastFramesWritten = std::max(mLastFramesWritten,
-                                  framesWrittenHardware + mFramesOffsetFromService);
+    if (mAudioEndpoint) {
+        const int64_t framesWrittenHardware = isClockModelInControl()
+                ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
+                : mAudioEndpoint->getDataWriteCounter();
+        // Add service offset and prevent retrograde motion.
+        mLastFramesWritten = std::max(mLastFramesWritten,
+                                      framesWrittenHardware + mFramesOffsetFromService);
+    }
     return mLastFramesWritten;
 }
 
 int64_t AudioStreamInternalCapture::getFramesRead() {
-    int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
-    //ALOGD("getFramesRead() returns %lld", (long long)frames);
-    return frames;
+    if (mAudioEndpoint) {
+        mLastFramesRead = mAudioEndpoint->getDataReadCounter() + mFramesOffsetFromService;
+    }
+    return mLastFramesRead;
 }
 
 // Read data from the stream and pass it to the callback for processing.
@@ -243,7 +246,7 @@
         int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
 
         // This is a BLOCKING READ!
-        result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos);
+        result = read(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
         if ((result != mCallbackFrames)) {
             ALOGE("callbackLoop: read() returned %d", result);
             if (result >= 0) {
@@ -255,7 +258,7 @@
         }
 
         // Call application using the AAudio callback interface.
-        callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames);
+        callbackResult = maybeCallDataCallback(mCallbackBuffer.get(), mCallbackFrames);
 
         if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
             ALOGD("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.h b/media/libaaudio/src/client/AudioStreamInternalCapture.h
index 294dbaf..6436a53 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.h
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.h
@@ -68,8 +68,6 @@
      * @return frames written or negative error
      */
     aaudio_result_t readNowWithConversion(void *buffer, int32_t numFrames);
-
-    int64_t       mLastFramesWritten = 0; // used to prevent retrograde motion
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 536009a..1303daf 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -87,8 +87,8 @@
 }
 
 void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
-    int64_t readCounter = mAudioEndpoint.getDataReadCounter();
-    int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
+    int64_t readCounter = mAudioEndpoint->getDataReadCounter();
+    int64_t writeCounter = mAudioEndpoint->getDataWriteCounter();
 
     // Bump offset so caller does not see the retrograde motion in getFramesRead().
     int64_t offset = writeCounter - readCounter;
@@ -98,7 +98,7 @@
 
     // Force writeCounter to match readCounter.
     // This is because we cannot change the read counter in the hardware.
-    mAudioEndpoint.setDataWriteCounter(readCounter);
+    mAudioEndpoint->setDataWriteCounter(readCounter);
 }
 
 void AudioStreamInternalPlay::onFlushFromServer() {
@@ -135,11 +135,11 @@
     // If we have gotten this far then we have at least one timestamp from server.
 
     // If a DMA channel or DSP is reading the other end then we have to update the readCounter.
-    if (mAudioEndpoint.isFreeRunning()) {
+    if (mAudioEndpoint->isFreeRunning()) {
         // Update data queue based on the timing model.
         int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
         // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter);
-        mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
+        mAudioEndpoint->setDataReadCounter(estimatedReadCounter);
     }
 
     if (mNeedCatchUp.isRequested()) {
@@ -151,7 +151,7 @@
 
     // If the read index passed the write index then consider it an underrun.
     // For shared streams, the xRunCount is passed up from the service.
-    if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getFullFramesAvailable() < 0) {
+    if (mAudioEndpoint->isFreeRunning() && mAudioEndpoint->getFullFramesAvailable() < 0) {
         mXRunCount++;
         if (ATRACE_ENABLED()) {
             ATRACE_INT("aaUnderRuns", mXRunCount);
@@ -170,7 +170,7 @@
     // Sleep if there is too much data in the buffer.
     // Calculate an ideal time to wake up.
     if (wakeTimePtr != nullptr
-            && (mAudioEndpoint.getFullFramesAvailable() >= getBufferSize())) {
+            && (mAudioEndpoint->getFullFramesAvailable() >= getBufferSize())) {
         // By default wake up a few milliseconds from now.  // TODO review
         int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
         aaudio_stream_state_t state = getState();
@@ -188,7 +188,7 @@
             {
                 // Sleep until the readCounter catches up and we only have
                 // the getBufferSize() frames of data sitting in the buffer.
-                int64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() - getBufferSize();
+                int64_t nextReadPosition = mAudioEndpoint->getDataWriteCounter() - getBufferSize();
                 wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
             }
                 break;
@@ -210,7 +210,7 @@
     uint8_t *byteBuffer = (uint8_t *) buffer;
     int32_t framesLeft = numFrames;
 
-    mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer);
+    mAudioEndpoint->getEmptyFramesAvailable(&wrappingBuffer);
 
     // Write data in one or two parts.
     int partIndex = 0;
@@ -236,24 +236,28 @@
         partIndex++;
     }
     int32_t framesWritten = numFrames - framesLeft;
-    mAudioEndpoint.advanceWriteIndex(framesWritten);
+    mAudioEndpoint->advanceWriteIndex(framesWritten);
 
     return framesWritten;
 }
 
 int64_t AudioStreamInternalPlay::getFramesRead() {
-    const int64_t framesReadHardware = isClockModelInControl()
-            ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
-            : mAudioEndpoint.getDataReadCounter();
-    // Add service offset and prevent retrograde motion.
-    mLastFramesRead = std::max(mLastFramesRead, framesReadHardware + mFramesOffsetFromService);
+    if (mAudioEndpoint) {
+        const int64_t framesReadHardware = isClockModelInControl()
+                ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
+                : mAudioEndpoint->getDataReadCounter();
+        // Add service offset and prevent retrograde motion.
+        mLastFramesRead = std::max(mLastFramesRead, framesReadHardware + mFramesOffsetFromService);
+    }
     return mLastFramesRead;
 }
 
 int64_t AudioStreamInternalPlay::getFramesWritten() {
-    const int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
-                               + mFramesOffsetFromService;
-    return framesWritten;
+    if (mAudioEndpoint) {
+        mLastFramesWritten = mAudioEndpoint->getDataWriteCounter()
+                             + mFramesOffsetFromService;
+    }
+    return mLastFramesWritten;
 }
 
 
@@ -268,11 +272,11 @@
     // result might be a frame count
     while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
         // Call application using the AAudio callback interface.
-        callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames);
+        callbackResult = maybeCallDataCallback(mCallbackBuffer.get(), mCallbackFrames);
 
         if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
             // Write audio data to stream. This is a BLOCKING WRITE!
-            result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
+            result = write(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
             if ((result != mCallbackFrames)) {
                 if (result >= 0) {
                     // Only wrote some of the frames requested. Must have timed out.
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.h b/media/libaaudio/src/client/AudioStreamInternalPlay.h
index cab2942..2e93157 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.h
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.h
@@ -92,8 +92,6 @@
     aaudio_result_t writeNowWithConversion(const void *buffer,
                                            int32_t numFrames);
 
-    int64_t                  mLastFramesRead = 0; // used to prevent retrograde motion
-
     AAudioFlowGraph          mFlowGraph;
 
 };
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index bd46d05..f0dcd44 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -47,6 +47,7 @@
         , mMarkerNanoTime(0)
         , mSampleRate(48000)
         , mFramesPerBurst(48)
+        , mBurstPeriodNanos(0) // this will be updated before use
         , mMaxMeasuredLatenessNanos(0)
         , mLatenessForDriftNanos(kInitialLatenessForDriftNanos)
         , mState(STATE_STOPPED)
@@ -57,9 +58,6 @@
     }
 }
 
-IsochronousClockModel::~IsochronousClockModel() {
-}
-
 void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) {
     ALOGV("setPositionAndTime, %lld, %lld", (long long) framePosition, (long long) nanoTime);
     mMarkerFramePosition = framePosition;
@@ -186,7 +184,7 @@
             // Calculate upper region that will trigger a drift forwards.
             mLatenessForDriftNanos = mMaxMeasuredLatenessNanos - (mMaxMeasuredLatenessNanos >> 4);
         } else { // decrease
-            // If these is an outlier in lateness then mMaxMeasuredLatenessNanos can go high
+            // If this is an outlier in lateness then mMaxMeasuredLatenessNanos can go high
             // and stay there. So we slowly reduce mMaxMeasuredLatenessNanos for better
             // long term stability. The two opposing forces will keep mMaxMeasuredLatenessNanos
             // within a reasonable range.
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 40f066b..6280013 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -35,7 +35,7 @@
 
 public:
     IsochronousClockModel();
-    virtual ~IsochronousClockModel();
+    virtual ~IsochronousClockModel() = default;
 
     void start(int64_t nanoTime);
     void stop(int64_t nanoTime);
@@ -130,6 +130,7 @@
 private:
 
     int32_t getLateTimeOffsetNanos() const;
+    void update();
 
     enum clock_model_state_t {
         STATE_STOPPED,
@@ -164,7 +165,6 @@
     // distribution of timestamps relative to earliest
     std::unique_ptr<android::audio_utils::Histogram>   mHistogramMicros;
 
-    void update();
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioGlobal.cpp b/media/libaaudio/src/core/AudioGlobal.cpp
index d299761..7f5d8d5 100644
--- a/media/libaaudio/src/core/AudioGlobal.cpp
+++ b/media/libaaudio/src/core/AudioGlobal.cpp
@@ -71,7 +71,42 @@
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_NO_SERVICE);
         AAUDIO_CASE_ENUM(AAUDIO_ERROR_INVALID_RATE);
     }
-    return "Unrecognized AAudio error.";
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertFormatToText(aaudio_format_t format) {
+      switch (format) {
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_UNSPECIFIED);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_INVALID);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_I16);
+        AAUDIO_CASE_ENUM(AAUDIO_FORMAT_PCM_FLOAT);
+    }
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertDirectionToText(aaudio_direction_t direction) {
+      switch (direction) {
+        AAUDIO_CASE_ENUM(AAUDIO_DIRECTION_INPUT);
+        AAUDIO_CASE_ENUM(AAUDIO_DIRECTION_OUTPUT);
+    }
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertPerformanceModeToText(aaudio_performance_mode_t mode) {
+      switch (mode) {
+        AAUDIO_CASE_ENUM(AAUDIO_PERFORMANCE_MODE_POWER_SAVING);
+        AAUDIO_CASE_ENUM(AAUDIO_PERFORMANCE_MODE_NONE);
+        AAUDIO_CASE_ENUM(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+    }
+    return "Unrecognized";
+}
+
+const char* AudioGlobal_convertSharingModeToText(aaudio_sharing_mode_t mode) {
+      switch (mode) {
+        AAUDIO_CASE_ENUM(AAUDIO_SHARING_MODE_SHARED);
+        AAUDIO_CASE_ENUM(AAUDIO_SHARING_MODE_EXCLUSIVE);
+    }
+    return "Unrecognized";
 }
 
 const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state) {
@@ -91,7 +126,7 @@
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_CLOSED);
         AAUDIO_CASE_ENUM(AAUDIO_STREAM_STATE_DISCONNECTED);
     }
-    return "Unrecognized AAudio state.";
+    return "Unrecognized";
 }
 
 #undef AAUDIO_CASE_ENUM
diff --git a/media/libaaudio/src/core/AudioGlobal.h b/media/libaaudio/src/core/AudioGlobal.h
index 312cef2..1e88d15 100644
--- a/media/libaaudio/src/core/AudioGlobal.h
+++ b/media/libaaudio/src/core/AudioGlobal.h
@@ -25,9 +25,12 @@
 aaudio_policy_t AudioGlobal_getMMapPolicy();
 aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy);
 
+const char* AudioGlobal_convertFormatToText(aaudio_format_t format);
+const char* AudioGlobal_convertDirectionToText(aaudio_direction_t direction);
+const char* AudioGlobal_convertPerformanceModeToText(aaudio_performance_mode_t mode);
 const char* AudioGlobal_convertResultToText(aaudio_result_t returnCode);
+const char* AudioGlobal_convertSharingModeToText(aaudio_sharing_mode_t mode);
 const char* AudioGlobal_convertStreamStateToText(aaudio_stream_state_t state);
-
 }
 
 #endif  // AAUDIO_AUDIOGLOBAL_H
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index f51db70..0644368 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -20,6 +20,9 @@
 
 #include <atomic>
 #include <stdint.h>
+
+#include <media/MediaMetricsItem.h>
+
 #include <aaudio/AAudio.h>
 
 #include "AudioStreamBuilder.h"
@@ -29,7 +32,6 @@
 
 namespace aaudio {
 
-
 // Sequential number assigned to streams solely for debugging purposes.
 static aaudio_stream_id_t AAudio_getNextStreamId() {
     static std::atomic <aaudio_stream_id_t> nextStreamId{1};
@@ -103,6 +105,26 @@
     return AAUDIO_OK;
 }
 
+void AudioStream::logOpen() {
+    if (mMetricsId.size() > 0) {
+        android::mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_PERFORMANCEMODE,
+                     AudioGlobal_convertPerformanceModeToText(getPerformanceMode()))
+                .set(AMEDIAMETRICS_PROP_SHARINGMODE,
+                     AudioGlobal_convertSharingModeToText(getSharingMode()))
+                .record();
+    }
+}
+
+void AudioStream::logBufferState() {
+    if (mMetricsId.size() > 0) {
+        android::mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSize())
+                .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getXRunCount())
+                .record();
+    }
+}
+
 aaudio_result_t AudioStream::systemStart() {
     std::lock_guard<std::mutex> lock(mStreamLock);
 
@@ -111,6 +133,33 @@
         return AAUDIO_ERROR_INVALID_STATE;
     }
 
+    switch (getState()) {
+        // Is this a good time to start?
+        case AAUDIO_STREAM_STATE_OPEN:
+        case AAUDIO_STREAM_STATE_PAUSING:
+        case AAUDIO_STREAM_STATE_PAUSED:
+        case AAUDIO_STREAM_STATE_STOPPING:
+        case AAUDIO_STREAM_STATE_STOPPED:
+        case AAUDIO_STREAM_STATE_FLUSHED:
+            break; // Proceed with starting.
+
+        // Already started?
+        case AAUDIO_STREAM_STATE_STARTING:
+        case AAUDIO_STREAM_STATE_STARTED:
+            ALOGW("%s() stream was already started, state = %s", __func__,
+                  AudioGlobal_convertStreamStateToText(getState()));
+            return AAUDIO_ERROR_INVALID_STATE;
+
+        // Don't start when the stream is dead!
+        case AAUDIO_STREAM_STATE_DISCONNECTED:
+        case AAUDIO_STREAM_STATE_CLOSING:
+        case AAUDIO_STREAM_STATE_CLOSED:
+        default:
+            ALOGW("%s() stream is dead, state = %s", __func__,
+                  AudioGlobal_convertStreamStateToText(getState()));
+            return AAUDIO_ERROR_INVALID_STATE;
+    }
+
     aaudio_result_t result = requestStart();
     if (result == AAUDIO_OK) {
         // We only call this for logging in "dumpsys audio". So ignore return code.
@@ -156,8 +205,8 @@
         case AAUDIO_STREAM_STATE_CLOSING:
         case AAUDIO_STREAM_STATE_CLOSED:
         default:
-            ALOGW("safePause() stream not running, state = %s",
-                  AudioGlobal_convertStreamStateToText(getState()));
+            ALOGW("%s() stream not running, state = %s",
+                  __func__, AudioGlobal_convertStreamStateToText(getState()));
             return AAUDIO_ERROR_INVALID_STATE;
     }
 
@@ -264,10 +313,22 @@
 
 void AudioStream::setState(aaudio_stream_state_t state) {
     ALOGD("%s(s#%d) from %d to %d", __func__, getId(), mState, state);
+    // Track transition to DISCONNECTED state.
+    if (state == AAUDIO_STREAM_STATE_DISCONNECTED && mState != state) {
+        android::mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT)
+                .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+                .record();
+    }
     // CLOSED is a final state
     if (mState == AAUDIO_STREAM_STATE_CLOSED) {
         ALOGE("%s(%d) tried to set to %d but already CLOSED", __func__, getId(), state);
 
+    // Once CLOSING, we can only move to CLOSED state.
+    } else if (mState == AAUDIO_STREAM_STATE_CLOSING
+               && state != AAUDIO_STREAM_STATE_CLOSED) {
+        ALOGE("%s(%d) tried to set to %d but already CLOSING", __func__, getId(), state);
+
     // Once DISCONNECTED, we can only move to CLOSING or CLOSED state.
     } else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
                && !(state == AAUDIO_STREAM_STATE_CLOSING
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 9bda41b..613a092 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -95,7 +95,6 @@
                                        int64_t *framePosition,
                                        int64_t *timeNanoseconds) = 0;
 
-
     /**
      * Update state machine.()
      * @return
@@ -114,6 +113,10 @@
      */
     virtual aaudio_result_t open(const AudioStreamBuilder& builder);
 
+    // log to MediaMetrics
+    virtual void logOpen();
+    void logBufferState();
+
     /**
      * Free any hardware or system resources from the open() call.
      * It is safe to call release_l() multiple times.
@@ -573,6 +576,8 @@
         mIsPrivacySensitive = privacySensitive;
     }
 
+    std::string mMetricsId; // set once during open()
+
 private:
 
     aaudio_result_t safeStop();
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 3a1e1c9..60dad84 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -193,10 +193,14 @@
                         *streamPtr = audioStream;
                     } else {
                         delete audioStream;
+                        audioStream = nullptr;
                     }
                 }
             }
         }
+        if (audioStream != nullptr) {
+            audioStream->logOpen();
+        }
     }
 
     return result;
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index abc3239..c062882 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -26,6 +26,7 @@
 #include <media/AudioTimestamp.h>
 #include <utils/String16.h>
 
+#include "core/AudioGlobal.h"
 #include "core/AudioStream.h"
 #include "legacy/AudioStreamLegacy.h"
 
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index da9205f..9c24b2b 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -128,6 +128,10 @@
         return mFramesRead.increment(frames);
     }
 
+    // This is used for exact matching by MediaMetrics. So do not change it.
+    // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_AAUDIO
+    static constexpr char     kCallerName[] = "aaudio";
+
     MonotonicCounter           mFramesWritten;
     MonotonicCounter           mFramesRead;
     MonotonicCounter           mTimestampPosition;
@@ -139,6 +143,7 @@
     const android::sp<StreamDeviceCallback>   mDeviceCallback;
 
     AtomicRequestor            mRequestDisconnect;
+
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 904edd1..853c0db 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -179,6 +179,9 @@
                 selectedDeviceId
         );
 
+        // Set it here so it can be logged by the destructor if the open failed.
+        mAudioRecord->setCallerName(kCallerName);
+
         // Did we get a valid track?
         status_t status = mAudioRecord->initCheck();
         if (status != OK) {
@@ -202,6 +205,9 @@
         }
     }
 
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD)
+            + std::to_string(mAudioRecord->getPortId());
+
     // Get the actual values from the AudioRecord.
     setSamplesPerFrame(mAudioRecord->channelCount());
 
@@ -286,6 +292,7 @@
     //  Then call it from here
     if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
         mAudioRecord->removeAudioDeviceCallback(mDeviceCallback);
+        logBufferState();
         mAudioRecord.clear();
         mFixedBlockWriter.close();
         return AudioStream::release_l();
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index d54d043..1120f05 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -173,6 +173,9 @@
             selectedDeviceId
     );
 
+    // Set it here so it can be logged by the destructor if the open failed.
+    mAudioTrack->setCallerName(kCallerName);
+
     // Did we get a valid track?
     status_t status = mAudioTrack->initCheck();
     if (status != NO_ERROR) {
@@ -181,6 +184,9 @@
         return AAudioConvert_androidToAAudioResult(status);
     }
 
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
+            + std::to_string(mAudioTrack->getPortId());
+
     doSetVolume();
 
     // Get the actual values from the AudioTrack.
@@ -215,6 +221,9 @@
             : (aaudio_session_id_t) mAudioTrack->getSessionId();
     setSessionId(actualSessionId);
 
+    mInitialBufferCapacity = getBufferCapacity();
+    mInitialFramesPerBurst = getFramesPerBurst();
+
     mAudioTrack->addAudioDeviceCallback(mDeviceCallback);
 
     // Update performance mode based on the actual stream flags.
@@ -245,6 +254,7 @@
 aaudio_result_t AudioStreamTrack::release_l() {
     if (getState() != AAUDIO_STREAM_STATE_CLOSING) {
         mAudioTrack->removeAudioDeviceCallback(mDeviceCallback);
+        logBufferState();
         // TODO Investigate why clear() causes a hang in test_various.cpp
         // if I call close() from a data callback.
         // But the same thing in AudioRecord is OK!
@@ -265,7 +275,16 @@
 
             // Stream got rerouted so we disconnect.
         case AudioTrack::EVENT_NEW_IAUDIOTRACK:
-            processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info);
+            // request stream disconnect if the restored AudioTrack has properties not matching
+            // what was requested initially
+            if (mAudioTrack->channelCount() != getSamplesPerFrame()
+                    || mAudioTrack->format() != getFormat()
+                    || mAudioTrack->getSampleRate() != getSampleRate()
+                    || mAudioTrack->getRoutedDeviceId() != getDeviceId()
+                    || getBufferCapacity() != mInitialBufferCapacity
+                    || getFramesPerBurst() != mInitialFramesPerBurst) {
+                processCallbackCommon(AAUDIO_CALLBACK_OPERATION_DISCONNECTED, info);
+            }
             break;
 
         default:
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 550f693..93a1ff4 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -104,6 +104,10 @@
 
     // TODO add 64-bit position reporting to AudioTrack and use it.
     aaudio_wrapping_frames_t         mPositionWhenPausing = 0;
+
+    // initial AudioTrack frame count and notification period
+    int32_t mInitialBufferCapacity = 0;
+    int32_t mInitialFramesPerBurst = 0;
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 73fd896..a6e5f70 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -226,3 +226,15 @@
         "libutils",
     ],
 }
+
+cc_test {
+    name: "test_steal_exclusive",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_steal_exclusive.cpp"],
+    shared_libs: [
+        "libaaudio",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/media/libaaudio/tests/test_steal_exclusive.cpp b/media/libaaudio/tests/test_steal_exclusive.cpp
new file mode 100644
index 0000000..2a05910
--- /dev/null
+++ b/media/libaaudio/tests/test_steal_exclusive.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This test starts an exclusive stream.
+ * Then a few seconds later it starts a second exclusive stream.
+ * The first stream should get stolen and they should both end up
+ * as SHARED streams.
+ * The test will print PASS or FAIL.
+ *
+ * If you plug in a headset during the test then you can get them to both
+ * open at almost the same time. This can result in a race condition.
+ * Both streams may try to automatically reopen their streams in EXCLUSIVE mode.
+ * The first stream will have its EXCLUSIVE stream stolen by the second stream.
+ * It will usually get disconnected between its Open and Start calls.
+ * This can also occur in normal use. But is unlikely because the window is very narrow.
+ * In this case, where two streams are responding to the same disconnect event,
+ * it will usually happen.
+ *
+ * Because the stream has not started, this condition will not trigger an onError callback.
+ * But the stream will get an error returned from AAudioStream_requestStart().
+ * The test uses this result to trigger a retry in the onError callback.
+ * That is the best practice for any app restarting a stream.
+ *
+ * You should see that both streams are advancing after the disconnect.
+ *
+ * The headset can connect using a 3.5 mm jack, or USB-C or Bluetooth.
+ *
+ * This test can be used with INPUT by using the -i command line option.
+ * Before running the test you will need to enter "adb root" so that
+ * you can have permission to record.
+ * Also the headset needs to have a microphone.
+ * Then the test should behave essentially the same.
+ */
+
+#include <atomic>
+#include <stdio.h>
+#include <thread>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+
+#define DEFAULT_TIMEOUT_NANOS  ((int64_t)1000000000)
+#define SOLO_DURATION_MSEC    2000
+#define DUET_DURATION_MSEC    8000
+#define SLEEP_DURATION_MSEC    500
+
+static const char * s_sharingModeToText(aaudio_sharing_mode_t mode) {
+    return (mode == AAUDIO_SHARING_MODE_EXCLUSIVE) ? "EXCLUSIVE"
+        : ((mode == AAUDIO_SHARING_MODE_SHARED)  ? "SHARED"
+            : AAudio_convertResultToText(mode));
+}
+
+static void s_myErrorCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        aaudio_result_t error);
+
+struct AudioEngine {
+    AAudioStream        *stream = nullptr;
+    std::thread         *thread = nullptr;
+    aaudio_direction_t   direction = AAUDIO_DIRECTION_OUTPUT;
+
+    // These counters are read and written by the callback and the main thread.
+    std::atomic<int32_t> framesRead{};
+    std::atomic<int32_t> framesCalled{};
+    std::atomic<int32_t> callbackCount{};
+
+    void reset() {
+        framesRead.store(0);
+        framesCalled.store(0);
+        callbackCount.store(0);
+    }
+};
+
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t s_myDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData,
+        int32_t numFrames
+) {
+    (void) audioData;
+    (void) numFrames;
+    AudioEngine *engine = (struct AudioEngine *)userData;
+    engine->callbackCount++;
+
+    engine->framesRead = (int32_t)AAudioStream_getFramesRead(stream);
+    engine->framesCalled += numFrames;
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+static aaudio_result_t s_OpenAudioStream(struct AudioEngine *engine,
+                                         aaudio_direction_t direction) {
+    AAudioStreamBuilder *builder = nullptr;
+    engine->direction = direction;
+
+    // Use an AAudioStreamBuilder to contain requested parameters.
+    aaudio_result_t result = AAudio_createStreamBuilder(&builder);
+    if (result != AAUDIO_OK) {
+        printf("AAudio_createStreamBuilder returned %s",
+               AAudio_convertResultToText(result));
+        return result;
+    }
+
+    // Request stream properties.
+    AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_FLOAT);
+    AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+    AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
+    AAudioStreamBuilder_setDirection(builder, direction);
+    AAudioStreamBuilder_setDataCallback(builder, s_myDataCallbackProc, engine);
+    AAudioStreamBuilder_setErrorCallback(builder, s_myErrorCallbackProc, engine);
+
+    // Create an AAudioStream using the Builder.
+    result = AAudioStreamBuilder_openStream(builder, &engine->stream);
+    AAudioStreamBuilder_delete(builder);
+    builder = nullptr;
+    if (result != AAUDIO_OK) {
+        printf("AAudioStreamBuilder_openStream returned %s",
+               AAudio_convertResultToText(result));
+    }
+
+    // See see what kind of stream we actually opened.
+    int32_t deviceId = AAudioStream_getDeviceId(engine->stream);
+    aaudio_sharing_mode_t actualSharingMode = AAudioStream_getSharingMode(engine->stream);
+    printf("-------- opened: deviceId = %3d, actualSharingMode = %s\n",
+           deviceId,
+           s_sharingModeToText(actualSharingMode));
+
+    return result;
+}
+
+static aaudio_result_t s_CloseAudioStream(struct AudioEngine *engine) {
+    aaudio_result_t result = AAUDIO_OK;
+    if (engine->stream != nullptr) {
+        result = AAudioStream_close(engine->stream);
+        if (result != AAUDIO_OK) {
+            printf("AAudioStream_close returned %s\n",
+                   AAudio_convertResultToText(result));
+        }
+        engine->stream = nullptr;
+    }
+    return result;
+}
+
+static void s_myRestartStreamProc(void *userData) {
+    printf("%s() - restart in separate thread\n", __func__);
+    AudioEngine *engine = (AudioEngine *) userData;
+    int retriesLeft = 1;
+    aaudio_result_t result;
+    do {
+        s_CloseAudioStream(engine);
+        s_OpenAudioStream(engine, engine->direction);
+        // It is possible for the stream to be disconnected, or stolen between the time
+        // it is opened and when it is started. If that happens then try again.
+        // If it was stolen then it should succeed the second time because there will already be
+        // a SHARED stream, which will not get stolen.
+        result = AAudioStream_requestStart(engine->stream);
+        printf("%s() - AAudioStream_requestStart() returns %s\n", __func__,
+                AAudio_convertResultToText(result));
+    } while (retriesLeft-- > 0 && result != AAUDIO_OK);
+}
+
+static void s_myErrorCallbackProc(
+        AAudioStream * /* stream */,
+        void *userData,
+        aaudio_result_t error) {
+    printf("%s() - error = %s\n", __func__, AAudio_convertResultToText(error));
+    // Handle error on a separate thread.
+    std::thread t(s_myRestartStreamProc, userData);
+    t.detach();
+}
+
+static void s_usage() {
+    printf("test_steal_exclusive [-i]\n");
+    printf("     -i direction INPUT, otherwise OUTPUT\n");
+}
+
+/**
+ * @return 0 is OK, -1 for error
+ */
+static int s_checkEnginePositions(AudioEngine *engine) {
+    if (engine->stream == nullptr) return 0; // race condition with onError procs!
+
+    const int64_t framesRead = AAudioStream_getFramesRead(engine->stream);
+    const int64_t framesWritten = AAudioStream_getFramesWritten(engine->stream);
+    const int32_t delta = (int32_t)(framesWritten - framesRead);
+    printf("playing framesRead = %7d, framesWritten = %7d"
+           ", delta = %4d, framesCalled = %6d, callbackCount = %4d\n",
+           (int32_t) framesRead,
+           (int32_t) framesWritten,
+           delta,
+           engine->framesCalled.load(),
+           engine->callbackCount.load()
+    );
+    if (delta > AAudioStream_getBufferCapacityInFrames(engine->stream)) {
+        printf("ERROR - delta > capacity\n");
+        return -1;
+    }
+    return 0;
+}
+
+int main(int argc, char **argv) {
+    (void) argc;
+    (void) argv;
+    struct AudioEngine victim;
+    struct AudioEngine thief;
+    aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT;
+    aaudio_result_t result = AAUDIO_OK;
+    int errorCount = 0;
+
+    // Make printf print immediately so that debug info is not stuck
+    // in a buffer if we hang or crash.
+    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+    printf("Test Stealing an EXCLUSIVE stream V1.0\n");
+    printf("\n");
+
+    for (int i = 1; i < argc; i++) {
+        const char *arg = argv[i];
+        if (arg[0] == '-') {
+            char option = arg[1];
+            switch (option) {
+                case 'i':
+                    direction = AAUDIO_DIRECTION_INPUT;
+                    break;
+                default:
+                    s_usage();
+                    exit(EXIT_FAILURE);
+                    break;
+            }
+        } else {
+            s_usage();
+            exit(EXIT_FAILURE);
+            break;
+        }
+    }
+
+    result = s_OpenAudioStream(&victim, direction);
+    if (result != AAUDIO_OK) {
+        printf("s_OpenAudioStream victim returned %s\n",
+               AAudio_convertResultToText(result));
+        errorCount++;
+    }
+    victim.reset();
+
+    // Start stream.
+    result = AAudioStream_requestStart(victim.stream);
+    printf("AAudioStream_requestStart(VICTIM) returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result);
+    if (result != AAUDIO_OK) {
+        errorCount++;
+    }
+
+    if (result == AAUDIO_OK) {
+        const int watchLoops = SOLO_DURATION_MSEC / SLEEP_DURATION_MSEC;
+        for (int i = watchLoops; i > 0; i--) {
+            errorCount += s_checkEnginePositions(&victim) ? 1 : 0;
+            usleep(SLEEP_DURATION_MSEC * 1000);
+        }
+    }
+
+    printf("Try to start the THIEF stream that may steal the VICTIM MMAP resource -----\n");
+    result = s_OpenAudioStream(&thief, direction);
+    if (result != AAUDIO_OK) {
+        printf("s_OpenAudioStream victim returned %s\n",
+               AAudio_convertResultToText(result));
+        errorCount++;
+    }
+    thief.reset();
+
+    // Start stream.
+    result = AAudioStream_requestStart(thief.stream);
+    printf("AAudioStream_requestStart(THIEF) returned %d >>>>>>>>>>>>>>>>>>>>>>\n", result);
+    if (result != AAUDIO_OK) {
+        errorCount++;
+    }
+    printf("You might enjoy plugging in a headset now to see what happens...\n");
+
+    if (result == AAUDIO_OK) {
+        const int watchLoops = DUET_DURATION_MSEC / SLEEP_DURATION_MSEC;
+        for (int i = watchLoops; i > 0; i--) {
+            printf("victim: ");
+            errorCount += s_checkEnginePositions(&victim) ? 1 : 0;
+            printf(" thief: ");
+            errorCount += s_checkEnginePositions(&thief) ? 1 : 0;
+            usleep(SLEEP_DURATION_MSEC * 1000);
+        }
+    }
+
+    // Check for PASS/FAIL
+    aaudio_sharing_mode_t victimSharingMode = AAudioStream_getSharingMode(victim.stream);
+    aaudio_sharing_mode_t thiefSharingMode = AAudioStream_getSharingMode(thief.stream);
+    printf("victimSharingMode = %s, thiefSharingMode = %s, - ",
+           s_sharingModeToText(victimSharingMode),
+           s_sharingModeToText(thiefSharingMode));
+    if ((victimSharingMode == AAUDIO_SHARING_MODE_SHARED)
+            && (thiefSharingMode == AAUDIO_SHARING_MODE_SHARED)) {
+        printf("Both modes are SHARED => PASS\n");
+    } else {
+        errorCount++;
+        printf("Both modes should be SHARED => FAIL!!\n");
+    }
+
+    const int64_t victimFramesRead = AAudioStream_getFramesRead(victim.stream);
+    const int64_t thiefFramesRead = AAudioStream_getFramesRead(thief.stream);
+    printf("victimFramesRead = %d, thiefFramesRead = %d, - ",
+           (int)victimFramesRead, (int)thiefFramesRead);
+    if (victimFramesRead > 0 && thiefFramesRead > 0) {
+        printf("Both streams are running => PASS\n");
+    } else {
+        errorCount++;
+        printf("Both streams should be running => FAIL!!\n");
+    }
+
+    result = AAudioStream_requestStop(victim.stream);
+    printf("AAudioStream_requestStop() returned %d <<<<<<<<<<<<<<<<<<<<<\n", result);
+    if (result != AAUDIO_OK) {
+        errorCount++;
+    }
+    result = AAudioStream_requestStop(thief.stream);
+    printf("AAudioStream_requestStop() returned %d <<<<<<<<<<<<<<<<<<<<<\n", result);
+    if (result != AAUDIO_OK) {
+        errorCount++;
+    }
+
+    s_CloseAudioStream(&victim);
+    s_CloseAudioStream(&thief);
+
+    printf("aaudio result = %d = %s\n", result, AAudio_convertResultToText(result));
+    printf("test %s\n", errorCount ? "FAILED" : "PASSED");
+
+    return errorCount ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/media/libaaudio/tests/test_various.cpp b/media/libaaudio/tests/test_various.cpp
index 5bb1046..1c26615 100644
--- a/media/libaaudio/tests/test_various.cpp
+++ b/media/libaaudio/tests/test_various.cpp
@@ -28,15 +28,20 @@
 
 // Callback function that does nothing.
 aaudio_data_callback_result_t NoopDataCallbackProc(
-        AAudioStream *stream,
-        void *userData,
+        AAudioStream * stream,
+        void * /* userData */,
         void *audioData,
         int32_t numFrames
 ) {
-    (void) stream;
-    (void) userData;
-    (void) audioData;
-    (void) numFrames;
+    int channels = AAudioStream_getChannelCount(stream);
+    int numSamples = channels * numFrames;
+    bool allZeros = true;
+    float * const floatData = reinterpret_cast<float *>(audioData);
+    for (int i = 0; i < numSamples; i++) {
+        allZeros &= (floatData[i] == 0.0f);
+        floatData[i] = 0.0f;
+    }
+    EXPECT_TRUE(allZeros);
     return AAUDIO_CALLBACK_RESULT_CONTINUE;
 }
 
@@ -56,6 +61,7 @@
                                         nullptr);
     AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
     AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode);
+    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT);
 
     // Create an AAudioStream using the Builder.
     ASSERT_EQ(AAUDIO_OK,
@@ -69,12 +75,33 @@
     EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_release(aaudioStream));
-    aaudio_stream_state_t state = AAudioStream_getState(aaudioStream);
-    EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
+    EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream));
 
     // We should be able to call this again without crashing.
     EXPECT_EQ(AAUDIO_OK, AAudioStream_release(aaudioStream));
-    state = AAudioStream_getState(aaudioStream);
+    EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream));
+
+    // We expect these not to crash.
+    AAudioStream_setBufferSizeInFrames(aaudioStream, 0);
+    AAudioStream_setBufferSizeInFrames(aaudioStream, 99999999);
+
+    // We should NOT be able to start or change a stream after it has been released.
+    EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, AAudioStream_requestStart(aaudioStream));
+    EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream));
+    EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, AAudioStream_requestPause(aaudioStream));
+    EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream));
+    EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, AAudioStream_requestStop(aaudioStream));
+    EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, AAudioStream_getState(aaudioStream));
+
+    // Does this crash?
+    EXPECT_LT(0, AAudioStream_getFramesRead(aaudioStream));
+    EXPECT_LT(0, AAudioStream_getFramesWritten(aaudioStream));
+
+    // Verify Closing State. Does this crash?
+    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
+                                                         AAUDIO_STREAM_STATE_UNKNOWN, &state,
+                                                         500 * NANOS_PER_MILLISECOND));
     EXPECT_EQ(AAUDIO_STREAM_STATE_CLOSING, state);
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
@@ -114,6 +141,7 @@
     // Request stream properties.
     AAudioStreamBuilder_setDataCallback(aaudioBuilder, NoopDataCallbackProc, nullptr);
     AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
+    AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_FLOAT);
 
     // Create an AAudioStream using the Builder.
     ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 65afc8d..0d20f20 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -21,6 +21,7 @@
         "AudioVolumeGroup.cpp",
     ],
     shared_libs: [
+        "capture_state_listener-aidl-cpp",
         "libaudiofoundation",
         "libaudioutils",
         "libbinder",
@@ -34,6 +35,9 @@
     ],
     include_dirs: ["system/media/audio_utils/include"],
     export_include_dirs: ["include"],
+    export_shared_lib_headers: [
+        "capture_state_listener-aidl-cpp",
+    ],
 }
 
 cc_library_shared {
@@ -73,6 +77,7 @@
         "TrackPlayerBase.cpp",
     ],
     shared_libs: [
+        "capture_state_listener-aidl-cpp",
         "libaudiofoundation",
         "libaudioutils",
         "libaudiopolicy",
@@ -148,3 +153,12 @@
     ],
     path: "aidl",
 }
+
+aidl_interface {
+    name: "capture_state_listener-aidl",
+    unstable: true,
+    local_include_dir: "aidl",
+    srcs: [
+        "aidl/android/media/ICaptureStateListener.aidl",
+    ],
+}
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index c183ab0..3ead6cb 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -151,11 +151,13 @@
     // audio flinger will not be retained. initCheck() will return the creation status
     // but all other APIs will return invalid operation.
     if (probe || iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
-        char typeBuffer[64], uuidBuffer[64];
+        char typeBuffer[64] = {}, uuidBuffer[64] = {};
         guidToString(type, typeBuffer, sizeof(typeBuffer));
         guidToString(uuid, uuidBuffer, sizeof(uuidBuffer));
         ALOGE_IF(!probe, "set(): AudioFlinger could not create effect %s / %s, status: %d",
-                typeBuffer, uuidBuffer, mStatus);
+                type != nullptr ? typeBuffer : "NULL",
+                uuid != nullptr ? uuidBuffer : "NULL",
+                mStatus);
         if (!probe && iEffect == 0) {
             mStatus = NO_INIT;
         }
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index f9d1798..0bbceef 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -170,6 +170,10 @@
 
     mediametrics::LogItem(mMetricsId)
         .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+        .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                mCallerName.empty()
+                ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                : mCallerName.c_str())
         .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
         .record();
 
@@ -394,8 +398,12 @@
     AutoMutex lock(mLock);
 
     status_t status = NO_ERROR;
-    mediametrics::Defer([&] {
+    mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                    mCallerName.empty()
+                    ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                    : mCallerName.c_str())
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mActive))
@@ -411,6 +419,9 @@
     mFramesReadServerOffset -= mFramesRead + framesFlushed;
     mFramesRead = 0;
     mProxy->clearTimestamp();  // timestamp is invalid until next server push
+    mPreviousTimestamp.clear();
+    mTimestampRetrogradePositionReported = false;
+    mTimestampRetrogradeTimeReported = false;
 
     // reset current position as seen by client to 0
     mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
@@ -467,7 +478,7 @@
 {
     const int64_t beginNs = systemTime();
     AutoMutex lock(mLock);
-    mediametrics::Defer([&] {
+    mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
@@ -600,6 +611,39 @@
                 timestamp->mPosition[i] += mFramesReadServerOffset;
             }
         }
+
+        bool timestampRetrogradeTimeReported = false;
+        bool timestampRetrogradePositionReported = false;
+        for (int i = 0; i < ExtendedTimestamp::LOCATION_MAX; ++i) {
+            if (timestamp->mTimeNs[i] >= 0 && mPreviousTimestamp.mTimeNs[i] >= 0) {
+                if (timestamp->mTimeNs[i] < mPreviousTimestamp.mTimeNs[i]) {
+                    if (!mTimestampRetrogradeTimeReported) {
+                        ALOGD("%s: retrograde time adjusting [%d] current:%lld to previous:%lld",
+                                __func__, i, (long long)timestamp->mTimeNs[i],
+                                (long long)mPreviousTimestamp.mTimeNs[i]);
+                        timestampRetrogradeTimeReported = true;
+                    }
+                    timestamp->mTimeNs[i] = mPreviousTimestamp.mTimeNs[i];
+                }
+                if (timestamp->mPosition[i] < mPreviousTimestamp.mPosition[i]) {
+                    if (!mTimestampRetrogradePositionReported) {
+                        ALOGD("%s: retrograde position"
+                                " adjusting [%d] current:%lld to previous:%lld",
+                                __func__, i, (long long)timestamp->mPosition[i],
+                                (long long)mPreviousTimestamp.mPosition[i]);
+                        timestampRetrogradePositionReported = true;
+                    }
+                    timestamp->mPosition[i] = mPreviousTimestamp.mPosition[i];
+                }
+            }
+        }
+        mPreviousTimestamp = *timestamp;
+        if (timestampRetrogradeTimeReported) {
+            mTimestampRetrogradeTimeReported = true;
+        }
+        if (timestampRetrogradePositionReported) {
+            mTimestampRetrogradePositionReported = true;
+        }
     }
     return status;
 }
@@ -1340,7 +1384,7 @@
 {
     status_t result = NO_ERROR;  // logged: make sure to set this before returning.
     const int64_t beginNs = systemTime();
-    mediametrics::Defer([&] {
+    mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index f030ab0..6357da4 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -18,6 +18,8 @@
 //#define LOG_NDEBUG 0
 
 #include <utils/Log.h>
+
+#include <android/media/BnCaptureStateListener.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <binder/IPCThreadState.h>
@@ -44,11 +46,16 @@
 dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
 record_config_callback AudioSystem::gRecordConfigCallback = NULL;
 
+// Required to be held while calling into gSoundTriggerCaptureStateListener.
+Mutex gSoundTriggerCaptureStateListenerLock;
+sp<AudioSystem::CaptureStateListener> gSoundTriggerCaptureStateListener = nullptr;
+
 // establish binder interface to AudioFlinger service
 const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
 {
     sp<IAudioFlinger> af;
     sp<AudioFlingerClient> afc;
+    bool reportNoError = false;
     {
         Mutex::Autolock _l(gLock);
         if (gAudioFlinger == 0) {
@@ -64,7 +71,7 @@
             if (gAudioFlingerClient == NULL) {
                 gAudioFlingerClient = new AudioFlingerClient();
             } else {
-                reportError(NO_ERROR);
+                reportNoError = true;
             }
             binder->linkToDeath(gAudioFlingerClient);
             gAudioFlinger = interface_cast<IAudioFlinger>(binder);
@@ -80,6 +87,7 @@
         af->registerClient(afc);
         IPCThreadState::self()->restoreCallingIdentity(token);
     }
+    if (reportNoError) reportError(NO_ERROR);
     return af;
 }
 
@@ -886,7 +894,6 @@
                                         audio_stream_type_t *stream,
                                         pid_t pid,
                                         uid_t uid,
-                                        const String16& opPackageName,
                                         const audio_config_t *config,
                                         audio_output_flags_t flags,
                                         audio_port_handle_t *selectedDeviceId,
@@ -896,7 +903,7 @@
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
     if (aps == 0) return NO_INIT;
     return aps->getOutputForAttr(attr, output, session, stream, pid, uid,
-                                 opPackageName, config,
+                                 config,
                                  flags, selectedDeviceId, portId, secondaryOutputs);
 }
 
@@ -1480,6 +1487,14 @@
     return aps->setA11yServicesUids(uids);
 }
 
+status_t AudioSystem::setCurrentImeUid(uid_t uid)
+{
+    const sp <IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return PERMISSION_DENIED;
+
+    return aps->setCurrentImeUid(uid);
+}
+
 bool AudioSystem::isHapticPlaybackSupported()
 {
     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
@@ -1616,6 +1631,48 @@
     return aps->getPreferredDeviceForStrategy(strategy, device);
 }
 
+class CaptureStateListenerImpl : public media::BnCaptureStateListener,
+                                 public IBinder::DeathRecipient {
+public:
+    binder::Status setCaptureState(bool active) override {
+        Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock);
+        gSoundTriggerCaptureStateListener->onStateChanged(active);
+        return binder::Status::ok();
+    }
+
+    void binderDied(const wp<IBinder>&) override {
+        Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock);
+        gSoundTriggerCaptureStateListener->onServiceDied();
+        gSoundTriggerCaptureStateListener = nullptr;
+    }
+};
+
+status_t AudioSystem::registerSoundTriggerCaptureStateListener(
+    const sp<CaptureStateListener>& listener) {
+    const sp<IAudioPolicyService>& aps =
+            AudioSystem::get_audio_policy_service();
+    if (aps == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    sp<CaptureStateListenerImpl> wrapper = new CaptureStateListenerImpl();
+
+    Mutex::Autolock _l(gSoundTriggerCaptureStateListenerLock);
+
+    bool active;
+    status_t status =
+        aps->registerSoundTriggerCaptureStateListener(wrapper, &active);
+    if (status != NO_ERROR) {
+        listener->onServiceDied();
+        return NO_ERROR;
+    }
+    gSoundTriggerCaptureStateListener = listener;
+    listener->onStateChanged(active);
+    sp<IBinder> binder = IInterface::asBinder(aps);
+    binder->linkToDeath(wrapper);
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 
 int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 2f95886..ca80dc4 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -73,7 +73,7 @@
 static inline struct timespec convertNsToTimespec(int64_t ns) {
     struct timespec tv;
     tv.tv_sec = static_cast<time_t>(ns / NANOS_PER_SECOND);
-    tv.tv_nsec = static_cast<long>(ns % NANOS_PER_SECOND);
+    tv.tv_nsec = static_cast<int64_t>(ns % NANOS_PER_SECOND);
     return tv;
 }
 
@@ -301,6 +301,10 @@
 
     mediametrics::LogItem(mMetricsId)
         .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+        .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                mCallerName.empty()
+                ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                : mCallerName.c_str())
         .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
         .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)mStatus)
         .record();
@@ -639,8 +643,12 @@
     AutoMutex lock(mLock);
 
     status_t status = NO_ERROR; // logged: make sure to set this before returning.
-    mediametrics::Defer([&] {
+    mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_CALLERNAME,
+                    mCallerName.empty()
+                    ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
+                    : mCallerName.c_str())
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
@@ -772,12 +780,14 @@
     const int64_t beginNs = systemTime();
 
     AutoMutex lock(mLock);
-    mediametrics::Defer([&]() {
+    mediametrics::Defer defer([&]() {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
             .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
-            .record(); });
+            .record();
+        logBufferSizeUnderruns();
+    });
 
     ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
 
@@ -832,7 +842,7 @@
 {
     const int64_t beginNs = systemTime();
     AutoMutex lock(mLock);
-    mediametrics::Defer([&]() {
+    mediametrics::Defer defer([&]() {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
@@ -873,7 +883,7 @@
 {
     const int64_t beginNs = systemTime();
     AutoMutex lock(mLock);
-    mediametrics::Defer([&]() {
+    mediametrics::Defer defer([&]() {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
@@ -1107,6 +1117,7 @@
     if (mOutput == AUDIO_IO_HANDLE_NONE || mProxy.get() == 0) {
         return NO_INIT;
     }
+
     return (ssize_t) mProxy->getBufferSizeInFrames();
 }
 
@@ -1128,6 +1139,16 @@
     return NO_ERROR;
 }
 
+void AudioTrack::logBufferSizeUnderruns() {
+    LOG_ALWAYS_FATAL_IF(mMetricsId.size() == 0, "mMetricsId is empty!");
+    ALOGD("%s(), mMetricsId = %s", __func__, mMetricsId.c_str());
+    // FIXME THis hangs! Why?
+//    android::mediametrics::LogItem(mMetricsId)
+//            .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSizeInFrames())
+//            .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getUnderrunCount())
+//            .record();
+}
+
 ssize_t AudioTrack::setBufferSizeInFrames(size_t bufferSizeInFrames)
 {
     AutoMutex lock(mLock);
@@ -1138,7 +1159,13 @@
     if (!audio_is_linear_pcm(mFormat)) {
         return INVALID_OPERATION;
     }
-    return (ssize_t) mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
+
+    ssize_t originalBufferSize = mProxy->getBufferSizeInFrames();
+    ssize_t finalBufferSize  = mProxy->setBufferSizeInFrames((uint32_t) bufferSizeInFrames);
+    if (originalBufferSize != finalBufferSize) {
+        logBufferSizeUnderruns();
+    }
+    return finalBufferSize;
 }
 
 status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
@@ -1767,7 +1794,7 @@
     } else if (waitCount > 0) {
         time_t ms = WAIT_PERIOD_MS * (time_t) waitCount;
         timeout.tv_sec = ms / 1000;
-        timeout.tv_nsec = (long) (ms % 1000) * 1000000;
+        timeout.tv_nsec = (ms % 1000) * 1000000;
         requested = &timeout;
     } else {
         ALOGE("%s(%d): invalid waitCount %d", __func__, mPortId, waitCount);
@@ -2410,7 +2437,7 @@
 {
     status_t result = NO_ERROR;  // logged: make sure to set this before returning.
     const int64_t beginNs = systemTime();
-    mediametrics::Defer([&] {
+    mediametrics::Defer defer([&] {
         mediametrics::LogItem(mMetricsId)
             .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE)
             .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(systemTime() - beginNs))
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index f1213a3..60af84b 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -22,6 +22,7 @@
 #include <math.h>
 #include <sys/types.h>
 
+#include <android/media/ICaptureStateListener.h>
 #include <binder/IPCThreadState.h>
 #include <binder/Parcel.h>
 #include <media/AudioEffect.h>
@@ -32,6 +33,8 @@
 
 namespace android {
 
+using media::ICaptureStateListener;
+
 enum {
     SET_DEVICE_CONNECTION_STATE = IBinder::FIRST_CALL_TRANSACTION,
     GET_DEVICE_CONNECTION_STATE,
@@ -114,6 +117,8 @@
     GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY,
     GET_DEVICES_FOR_ATTRIBUTES,
     AUDIO_MODULES_UPDATED,  // oneway
+    SET_CURRENT_IME_UID,
+    REGISTER_SOUNDTRIGGER_CAPTURE_STATE_LISTENER,
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -215,7 +220,6 @@
                               audio_stream_type_t *stream,
                               pid_t pid,
                               uid_t uid,
-                              const String16& opPackageName,
                               const audio_config_t *config,
                               audio_output_flags_t flags,
                               audio_port_handle_t *selectedDeviceId,
@@ -254,7 +258,6 @@
             }
             data.writeInt32(pid);
             data.writeInt32(uid);
-            data.writeString16(opPackageName);
             data.write(config, sizeof(audio_config_t));
             data.writeInt32(static_cast <uint32_t>(flags));
             data.writeInt32(*selectedDeviceId);
@@ -1147,6 +1150,18 @@
         return static_cast <status_t> (reply.readInt32());
     }
 
+    virtual status_t setCurrentImeUid(uid_t uid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        data.writeInt32(uid);
+        status_t status = remote()->transact(SET_CURRENT_IME_UID, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast <status_t> (reply.readInt32());
+    }
+
     virtual bool isHapticPlaybackSupported()
     {
         Parcel data, reply;
@@ -1459,6 +1474,27 @@
         data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
         remote()->transact(AUDIO_MODULES_UPDATED, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    status_t registerSoundTriggerCaptureStateListener(
+            const sp<media::ICaptureStateListener>& listener,
+            bool* result) override {
+        Parcel data, reply;
+        status_t status;
+        status =
+            data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        if (status != NO_ERROR) return status;
+        status = data.writeStrongBinder(IInterface::asBinder(listener));
+        if (status != NO_ERROR) return status;
+        status =
+            remote()->transact(REGISTER_SOUNDTRIGGER_CAPTURE_STATE_LISTENER,
+                               data,
+                               &reply,
+                               0);
+        if (status != NO_ERROR) return status;
+        status = reply.readBool(result);
+        if (status != NO_ERROR) return status;
+        return NO_ERROR;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1531,7 +1567,9 @@
         case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY:
         case GET_DEVICES_FOR_ATTRIBUTES:
         case SET_ALLOWED_CAPTURE_POLICY:
-        case AUDIO_MODULES_UPDATED: {
+        case AUDIO_MODULES_UPDATED:
+        case SET_CURRENT_IME_UID:
+        case REGISTER_SOUNDTRIGGER_CAPTURE_STATE_LISTENER: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1656,11 +1694,6 @@
             }
             pid_t pid = (pid_t)data.readInt32();
             uid_t uid = (uid_t)data.readInt32();
-            String16 opPackageName;
-            status = data.readString16(&opPackageName);
-            if (status != NO_ERROR) {
-                return status;
-            }
             audio_config_t config;
             memset(&config, 0, sizeof(audio_config_t));
             data.read(&config, sizeof(audio_config_t));
@@ -1672,7 +1705,7 @@
             std::vector<audio_io_handle_t> secondaryOutputs;
             status = getOutputForAttr(&attr,
                     &output, session, &stream, pid, uid,
-                    opPackageName, &config,
+                    &config,
                     flags, &selectedDeviceId, &portId, &secondaryOutputs);
             reply->writeInt32(status);
             status = reply->write(&attr, sizeof(audio_attributes_t));
@@ -2687,6 +2720,43 @@
             return NO_ERROR;
         } break;
 
+        case SET_CURRENT_IME_UID: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            int32_t uid;
+            status_t status = data.readInt32(&uid);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            status = setCurrentImeUid(uid);
+            reply->writeInt32(static_cast <int32_t>(status));
+            return NO_ERROR;
+        }
+
+        case REGISTER_SOUNDTRIGGER_CAPTURE_STATE_LISTENER: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            sp<IBinder> binder = data.readStrongBinder();
+            if (binder == nullptr) {
+                return BAD_VALUE;
+            }
+            sp<ICaptureStateListener>
+                listener = interface_cast<ICaptureStateListener>(
+                binder);
+            if (listener == nullptr) {
+                return BAD_VALUE;
+            }
+            bool ret;
+            status_t status =
+                registerSoundTriggerCaptureStateListener(listener, &ret);
+            LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
+                                "Server returned unexpected status code: %d",
+                                status);
+            status = reply->writeBool(ret);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            return NO_ERROR;
+        } break;
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 536b00d..050ad65 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1262,7 +1262,9 @@
             AUDIO_UID_INVALID,
             -1,
             &attr);
-
+    // Set caller name so it can be logged in destructor.
+    // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR
+    mpAudioTrack->setCallerName("tonegenerator");
     if (status != NO_ERROR) {
         ALOGE("AudioTrack(%p) set failed with error %d", mpAudioTrack.get(), status);
         mpAudioTrack.clear();
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/media_c2_audio_hidl_test_common.h b/media/libaudioclient/aidl/android/media/ICaptureStateListener.aidl
similarity index 74%
rename from media/codec2/hidl/1.0/vts/functional/audio/media_c2_audio_hidl_test_common.h
rename to media/libaudioclient/aidl/android/media/ICaptureStateListener.aidl
index 4d773ce..8502282 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/media_c2_audio_hidl_test_common.h
+++ b/media/libaudioclient/aidl/android/media/ICaptureStateListener.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
-#define MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
+package android.media;
 
-
-#endif  // MEDIA_C2_AUDIO_HIDL_TEST_COMMON_H
+interface ICaptureStateListener {
+    void setCaptureState(boolean active);
+}
diff --git a/media/libaudioclient/include/media/AudioAttributes.h b/media/libaudioclient/include/media/AudioAttributes.h
index 0a35e9e..001c629 100644
--- a/media/libaudioclient/include/media/AudioAttributes.h
+++ b/media/libaudioclient/include/media/AudioAttributes.h
@@ -28,7 +28,7 @@
 {
 public:
     AudioAttributes() = default;
-    AudioAttributes(const audio_attributes_t &attributes) : mAttributes(attributes) {}
+    AudioAttributes(const audio_attributes_t &attributes) : mAttributes(attributes) {} // NOLINT
     AudioAttributes(volume_group_t groupId,
                     audio_stream_type_t stream,
                     const audio_attributes_t &attributes) :
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index 5c300ed..2f66658 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -277,6 +277,19 @@
      */
             status_t getMetrics(mediametrics::Item * &item);
 
+    /*
+     * Set name of API that is using this object.
+     * For example "aaudio" or "opensles".
+     * This may be logged or reported as part of MediaMetrics.
+     */
+            void setCallerName(const std::string &name) {
+                mCallerName = name;
+            }
+
+            std::string getCallerName() const {
+                return mCallerName;
+            };
+
     /* After it's created the track is not active. Call start() to
      * make it active. If set, the callback will start being called.
      * If event is not AudioSystem::SYNC_EVENT_NONE, the capture start will be delayed until
@@ -711,6 +724,10 @@
 
     bool                    mInOverrun;         // whether recorder is currently in overrun state
 
+    ExtendedTimestamp       mPreviousTimestamp{}; // used to detect retrograde motion
+    bool                    mTimestampRetrogradePositionReported = false; // reduce log spam
+    bool                    mTimestampRetrogradeTimeReported = false;     // reduce log spam
+
 private:
     class DeathNotifier : public IBinder::DeathRecipient {
     public:
@@ -772,6 +789,7 @@
     };
     MediaMetrics mMediaMetrics;
     std::string mMetricsId;  // GUARDED_BY(mLock), could change in createRecord_l().
+    std::string mCallerName; // for example "aaudio"
 };
 
 }; // namespace android
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index aebc875..19c2cbd 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -241,7 +241,6 @@
                                      audio_stream_type_t *stream,
                                      pid_t pid,
                                      uid_t uid,
-                                     const String16& opPackageName,
                                      const audio_config_t *config,
                                      audio_output_flags_t flags,
                                      audio_port_handle_t *selectedDeviceId,
@@ -400,6 +399,7 @@
 
     static status_t setAssistantUid(uid_t uid);
     static status_t setA11yServicesUids(const std::vector<uid_t>& uids);
+    static status_t setCurrentImeUid(uid_t uid);
 
     static bool     isHapticPlaybackSupported();
 
@@ -436,6 +436,30 @@
     static status_t getDeviceForStrategy(product_strategy_t strategy,
             AudioDeviceTypeAddr &device);
 
+    // A listener for capture state changes.
+    class CaptureStateListener : public RefBase {
+    public:
+        // Called whenever capture state changes.
+        virtual void onStateChanged(bool active) = 0;
+        // Called whenever the service dies (and hence our listener is no longer
+        // registered).
+        virtual void onServiceDied() = 0;
+
+        virtual ~CaptureStateListener() = default;
+    };
+
+    // Regiseters a listener for sound trigger capture state changes.
+    // There may only be one such listener registered at any point.
+    // The listener onStateChanged() method will be invoked sychronously from
+    // this call with the initial value.
+    // The listener onServiceDied() method will be invoked sychronously from
+    // this call if initial attempt to register failed.
+    // If the audio policy service cannot be reached, this method will return
+    // PERMISSION_DENIED and will not invoke the callback, otherwise, it will
+    // return NO_ERROR.
+    static status_t registerSoundTriggerCaptureStateListener(
+            const sp<CaptureStateListener>& listener);
+
     // ----------------------------------------------------------------------------
 
     class AudioVolumeGroupCallback : public RefBase
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 4adaaea..17af7d4 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -410,6 +410,19 @@
      */
             status_t getMetrics(mediametrics::Item * &item);
 
+    /*
+     * Set name of API that is using this object.
+     * For example "aaudio" or "opensles".
+     * This may be logged or reported as part of MediaMetrics.
+     */
+            void setCallerName(const std::string &name) {
+                mCallerName = name;
+            }
+
+            std::string getCallerName() const {
+                return mCallerName;
+            };
+
     /* After it's created the track is not active. Call start() to
      * make it active. If set, the callback will start being called.
      * If the track was previously paused, volume is ramped up over the first mix buffer.
@@ -947,7 +960,7 @@
     class AudioTrackThread : public Thread
     {
     public:
-        AudioTrackThread(AudioTrack& receiver);
+        explicit AudioTrackThread(AudioTrack& receiver);
 
         // Do not call Thread::requestExitAndWait() without first calling requestExit().
         // Thread::requestExitAndWait() is not virtual, and the implementation doesn't do enough.
@@ -1226,7 +1239,7 @@
 private:
     class DeathNotifier : public IBinder::DeathRecipient {
     public:
-        DeathNotifier(AudioTrack* audioTrack) : mAudioTrack(audioTrack) { }
+        explicit DeathNotifier(AudioTrack* audioTrack) : mAudioTrack(audioTrack) { }
     protected:
         virtual void        binderDied(const wp<IBinder>& who);
     private:
@@ -1259,6 +1272,9 @@
     };
     MediaMetrics mMediaMetrics;
     std::string mMetricsId;  // GUARDED_BY(mLock), could change in createTrack_l().
+    std::string mCallerName; // for example "aaudio"
+
+    void logBufferSizeUnderruns();
 
 private:
     class AudioTrackCallback : public media::BnAudioTrackCallback {
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index c9d9716..612ce7a 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -71,7 +71,6 @@
             if (clientInfo.readFromParcel(parcel) != NO_ERROR) {
                 return DEAD_OBJECT;
             }
-            opPackageName = parcel->readString16();
             if (parcel->readInt32() != 0) {
                 // TODO: Using unsecurePointer() has some associated security
                 //       pitfalls (see declaration for details).
@@ -101,7 +100,6 @@
             (void)parcel->write(&attr, sizeof(audio_attributes_t));
             (void)parcel->write(&config, sizeof(audio_config_t));
             (void)clientInfo.writeToParcel(parcel);
-            (void)parcel->writeString16(opPackageName);
             if (sharedBuffer != 0) {
                 (void)parcel->writeInt32(1);
                 (void)parcel->writeStrongBinder(IInterface::asBinder(sharedBuffer));
@@ -125,7 +123,6 @@
         audio_attributes_t attr;
         audio_config_t config;
         AudioClient clientInfo;
-        String16 opPackageName;
         sp<IMemory> sharedBuffer;
         uint32_t notificationsPerBuffer;
         float speed;
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index ec3461e..bb1c07f 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -31,6 +31,11 @@
 #include <vector>
 
 namespace android {
+namespace media {
+// Must be pre-declared, or else there isn't a good way to generate a header
+// library.
+class ICaptureStateListener;
+}
 
 // ----------------------------------------------------------------------------
 
@@ -65,7 +70,6 @@
                                       audio_stream_type_t *stream,
                                       pid_t pid,
                                       uid_t uid,
-                                      const String16& opPackageName,
                                       const audio_config_t *config,
                                       audio_output_flags_t flags,
                                       audio_port_handle_t *selectedDeviceId,
@@ -222,6 +226,7 @@
 
     virtual status_t setAssistantUid(uid_t uid) = 0;
     virtual status_t setA11yServicesUids(const std::vector<uid_t>& uids) = 0;
+    virtual status_t setCurrentImeUid(uid_t uid) = 0;
 
     virtual bool     isHapticPlaybackSupported() = 0;
     virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) = 0;
@@ -243,6 +248,12 @@
 
     virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy,
                                                    AudioDeviceTypeAddr &device) = 0;
+
+    // The return code here is only intended to represent transport errors. The
+    // actual server implementation should always return NO_ERROR.
+    virtual status_t registerSoundTriggerCaptureStateListener(
+        const sp<media::ICaptureStateListener>& listener,
+        bool* result) = 0;
 };
 
 
diff --git a/media/libeffects/config/Android.bp b/media/libeffects/config/Android.bp
index 8476f82..8493e30 100644
--- a/media/libeffects/config/Android.bp
+++ b/media/libeffects/config/Android.bp
@@ -15,6 +15,7 @@
         "libtinyxml2",
         "libutils",
         "libmedia_helper",
+        "libcutils",
     ],
 
     header_libs: ["libaudio_system_headers"],
diff --git a/media/libeffects/config/include/media/EffectsConfig.h b/media/libeffects/config/include/media/EffectsConfig.h
index ef10e0d..57d4dd7 100644
--- a/media/libeffects/config/include/media/EffectsConfig.h
+++ b/media/libeffects/config/include/media/EffectsConfig.h
@@ -35,11 +35,6 @@
 /** Default path of effect configuration file. Relative to DEFAULT_LOCATIONS. */
 constexpr const char* DEFAULT_NAME = "audio_effects.xml";
 
-/** Default path of effect configuration file.
- * The /vendor partition is the recommended one, the others are deprecated.
- */
-constexpr const char* DEFAULT_LOCATIONS[] = {"/odm/etc", "/vendor/etc", "/system/etc"};
-
 /** Directories where the effect libraries will be search for. */
 constexpr const char* LD_EFFECT_LIBRARY_PATH[] =
 #ifdef __LP64__
diff --git a/media/libeffects/config/src/EffectsConfig.cpp b/media/libeffects/config/src/EffectsConfig.cpp
index 85fbf11..26eaaf8 100644
--- a/media/libeffects/config/src/EffectsConfig.cpp
+++ b/media/libeffects/config/src/EffectsConfig.cpp
@@ -27,6 +27,7 @@
 
 #include <media/EffectsConfig.h>
 #include <media/TypeConverter.h>
+#include <system/audio_config.h>
 
 using namespace tinyxml2;
 
@@ -338,7 +339,7 @@
         return parseWithPath(path);
     }
 
-    for (const std::string& location : DEFAULT_LOCATIONS) {
+    for (const std::string& location : audio_get_configuration_paths()) {
         std::string defaultPath = location + '/' + DEFAULT_NAME;
         if (access(defaultPath.c_str(), R_OK) != 0) {
             continue;
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 1cb81a6..39f5bb6 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1906,11 +1906,15 @@
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_GET_PARAM start");
             effect_param_t *p = (effect_param_t *)pCmdData;
+            if (pCmdData == nullptr) {
+                ALOGW("\tLVM_ERROR : pCmdData is NULL");
+                return -EINVAL;
+            }
             if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
                 android_errorWriteLog(0x534e4554, "26347509");
                 return -EINVAL;
             }
-            if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
+            if (cmdSize < sizeof(effect_param_t) ||
                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
                     pReplyData == NULL || replySize == NULL ||
                     *replySize < (sizeof(effect_param_t) + p->psize)) {
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 867187d..be3f995 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -33,6 +33,7 @@
 
 aidl_interface {
     name: "resourcemanager_aidl_interface",
+    unstable: true,
     local_include_dir: "aidl",
     srcs: [
         "aidl/android/media/IResourceManagerClient.aidl",
@@ -186,7 +187,7 @@
     srcs: ["MidiIoWrapper.cpp"],
 
     static_libs: [
-        "libsonivox",
+        "libsonivoxwithoutjet",
     ],
 
     header_libs: [
@@ -272,7 +273,6 @@
         "IRemoteDisplay.cpp",
         "IRemoteDisplayClient.cpp",
         "IStreamSource.cpp",
-        "MediaUtils.cpp",
         "Metadata.cpp",
         "mediarecorder.cpp",
         "IMediaMetadataRetriever.cpp",
@@ -295,7 +295,6 @@
     },
 
     header_libs: [
-        "bionic_libc_platform_headers",
         "libstagefright_headers",
         "media_ndk_headers",
     ],
@@ -313,7 +312,7 @@
         "libutils",
         "libbinder",
         "libbinder_ndk",
-        "libsonivox",
+        //"libsonivox",
         "libandroidicu",
         "libexpat",
         "libcamera_client",
@@ -329,12 +328,11 @@
         "libaudioclient",
         "libbinder",
         "libandroidicu",
-        "libsonivox",
+        //"libsonivox",
         "libmedia_omx",
     ],
 
     static_libs: [
-        "libc_malloc_debug_backtrace", // for memory heap analysis
         "resourcemanager_aidl_interface-ndk_platform",
     ],
 
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index b18571f..36cd73b 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -107,7 +107,7 @@
         data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
         status_t ret = remote()->transact(GETFORMAT, data, &reply);
         if (ret == NO_ERROR) {
-            AutoMutex _l(mLock);
+            AutoMutex _l(mBpLock);
             mMetaData = MetaData::createFromParcel(reply);
             return mMetaData;
         }
@@ -224,7 +224,7 @@
     // XXX: could we use this for caching, or does metadata change on the fly?
     sp<MetaData> mMetaData;
     // ensure synchronize access to mMetaData
-    Mutex mLock;
+    Mutex mBpLock;
 
     // Cache all IMemory objects received from MediaExtractor.
     // We gc IMemory objects that are no longer active (referenced by a MediaBuffer).
@@ -301,6 +301,7 @@
             CHECK_INTERFACE(IMediaSource, data, reply);
             mGroup->signalBufferReturned(nullptr);
             status_t status = stop();
+            AutoMutex _l(mBnLock);
             mIndexCache.reset();
             mBuffersSinceStop = 0;
             return status;
@@ -340,6 +341,7 @@
                     && len == sizeof(opts)
                     && data.read((void *)&opts, len) == NO_ERROR;
 
+            AutoMutex _l(mBnLock);
             mGroup->signalBufferReturned(nullptr);
             mIndexCache.gc();
             size_t inlineTransferSize = 0;
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
index 3dd0859..1b2d522 100644
--- a/media/libmedia/aidl/android/media/IResourceManagerService.aidl
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -94,4 +94,12 @@
      *        remove existing override on originalPid if newPid is -1.
      */
     void overridePid(int originalPid, int newPid);
+
+    /**
+     * Mark a client for pending removal
+     *
+     * @param pid pid from which the client's resources will be removed.
+     * @param clientId clientId within the pid that will be removed.
+     */
+    void markClientForPendingRemoval(int pid, long clientId);
 }
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index f3fa39b..84310f0 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -135,6 +135,7 @@
 
 private:
     uint32_t mBuffersSinceStop; // Buffer tracking variable
+    Mutex mBnLock; // to guard readMultiple against concurrent access to the buffer cache
 
     std::unique_ptr<MediaBufferGroup> mGroup;
 
diff --git a/media/libmedia/include/media/Modulo.h b/media/libmedia/include/media/Modulo.h
index 23280ac..c66928d 100644
--- a/media/libmedia/include/media/Modulo.h
+++ b/media/libmedia/include/media/Modulo.h
@@ -90,7 +90,7 @@
     typedef typename std::make_unsigned<T>::type unsignedT;
 
     Modulo() { } // intentionally uninitialized data
-    Modulo(const T &value) { mValue = value; }
+    Modulo(const T &value) { mValue = value; } // NOLINT
     const T & value() const { return mValue; } // not assignable
     signedT signedValue() const { return mValue; }
     unsignedT unsignedValue() const { return mValue; }
diff --git a/media/libmedia/xsd/vts/Android.bp b/media/libmedia/xsd/vts/Android.bp
index 4739504..598e41b 100644
--- a/media/libmedia/xsd/vts/Android.bp
+++ b/media/libmedia/xsd/vts/Android.bp
@@ -31,4 +31,12 @@
         "-Wall",
         "-Werror",
     ],
+    data: [
+        ":media_profiles",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts"
+    ],
+    test_config: "vts_mediaProfiles_validate_test.xml",
 }
diff --git a/media/libmedia/xsd/vts/vts_mediaProfiles_validate_test.xml b/media/libmedia/xsd/vts/vts_mediaProfiles_validate_test.xml
new file mode 100644
index 0000000..08ab8f4
--- /dev/null
+++ b/media/libmedia/xsd/vts/vts_mediaProfiles_validate_test.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs vts_mediaProfiles_validate_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="media_profiles.xsd->/data/local/tmp/media_profiles.xsd" />
+        <option name="push" value="vts_mediaProfiles_validate_test->/data/local/tmp/vts_mediaProfiles_validate_test" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="vts_mediaProfiles_validate_test" />
+    </test>
+</configuration>
diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp
index 0cd5194..03068c7 100644
--- a/media/libmediametrics/Android.bp
+++ b/media/libmediametrics/Android.bp
@@ -22,9 +22,11 @@
     export_include_dirs: ["include"],
 
     cflags: [
-        "-Werror",
-        "-Wno-error=deprecated-declarations",
         "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wthread-safety",
+        "-Wunreachable-code",
     ],
 
     sanitize: {
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index 4371668..7cdbe5f 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -25,6 +25,7 @@
 #include <set>
 
 #include <binder/Parcel.h>
+#include <cutils/properties.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/SortedVector.h>
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index eb7ac7d..ec0e133 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -37,9 +37,17 @@
 // They must be appended with another value to make a key.
 #define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."
 
+// The AudioMmap key appends the "trackId" to the prefix.
+// This is the AudioFlinger equivalent of the AAudio Stream.
+// TODO: unify with AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP  AMEDIAMETRICS_KEY_PREFIX_AUDIO "mmap."
+
 // The AudioRecord key appends the "trackId" to the prefix.
 #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."
 
+// The AudioStream key appends the "streamId" to the prefix.
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM  AMEDIAMETRICS_KEY_PREFIX_AUDIO "stream."
+
 // The AudioThread key appends the "threadId" to the prefix.
 #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread."
 
@@ -83,10 +91,24 @@
 // of suppressed in the Time Machine.
 #define AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED '#'
 
+#define AMEDIAMETRICS_PROP_ALLOWUID       "_allowUid"      // int32_t, allow client uid to post
 #define AMEDIAMETRICS_PROP_AUXEFFECTID    "auxEffectId"    // int32 (AudioTrack)
+#define AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES "bufferSizeFrames" // int32
+#define AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES "bufferCapacityFrames" // int32
+#define AMEDIAMETRICS_PROP_BURSTFRAMES    "burstFrames"    // int32
+#define AMEDIAMETRICS_PROP_CALLERNAME     "callerName"     // string, eg. "aaudio"
 #define AMEDIAMETRICS_PROP_CHANNELCOUNT   "channelCount"   // int32
 #define AMEDIAMETRICS_PROP_CHANNELMASK    "channelMask"    // int32
 #define AMEDIAMETRICS_PROP_CONTENTTYPE    "contentType"    // string attributes (AudioTrack)
+#define AMEDIAMETRICS_PROP_CUMULATIVETIMENS "cumulativeTimeNs" // int64_t playback/record time
+                                                           // since start
+// DEVICE values are averaged since starting on device
+#define AMEDIAMETRICS_PROP_DEVICELATENCYMS "deviceLatencyMs" // double - avg latency time
+#define AMEDIAMETRICS_PROP_DEVICESTARTUPMS "deviceStartupMs" // double - avg startup time
+#define AMEDIAMETRICS_PROP_DEVICETIMENS   "deviceTimeNs"   // int64_t playback/record time
+#define AMEDIAMETRICS_PROP_DEVICEVOLUME   "deviceVolume"   // double - average device volume
+
+#define AMEDIAMETRICS_PROP_DIRECTION      "direction"      // string AAudio input or output
 #define AMEDIAMETRICS_PROP_DURATIONNS     "durationNs"     // int64 duration time span
 #define AMEDIAMETRICS_PROP_ENCODING       "encoding"       // string value of format
 #define AMEDIAMETRICS_PROP_EVENT          "event#"         // string value (often func name)
@@ -96,9 +118,12 @@
 
 #define AMEDIAMETRICS_PROP_FRAMECOUNT     "frameCount"     // int32
 #define AMEDIAMETRICS_PROP_INPUTDEVICES   "inputDevices"   // string value
+#define AMEDIAMETRICS_PROP_INTERVALCOUNT  "intervalCount"  // int32
 #define AMEDIAMETRICS_PROP_LATENCYMS      "latencyMs"      // double value
+#define AMEDIAMETRICS_PROP_NAME           "name"           // string value
 #define AMEDIAMETRICS_PROP_ORIGINALFLAGS  "originalFlags"  // int32
 #define AMEDIAMETRICS_PROP_OUTPUTDEVICES  "outputDevices"  // string value
+#define AMEDIAMETRICS_PROP_PERFORMANCEMODE "performanceMode"    // string value, "none", lowLatency"
 #define AMEDIAMETRICS_PROP_PLAYBACK_PITCH "playback.pitch" // double value (AudioTrack)
 #define AMEDIAMETRICS_PROP_PLAYBACK_SPEED "playback.speed" // double value (AudioTrack)
 #define AMEDIAMETRICS_PROP_ROUTEDDEVICEID "routedDeviceId" // int32
@@ -107,6 +132,7 @@
 #define AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION "selectedMicDirection" // int32
 #define AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION "selectedMicFieldDimension" // double
 #define AMEDIAMETRICS_PROP_SESSIONID      "sessionId"      // int32
+#define AMEDIAMETRICS_PROP_SHARINGMODE    "sharingMode"    // string value, "exclusive", shared"
 #define AMEDIAMETRICS_PROP_SOURCE         "source"         // string (AudioAttributes)
 #define AMEDIAMETRICS_PROP_STARTUPMS      "startupMs"      // double value
 // State is "ACTIVE" or "STOPPED" for AudioRecord
@@ -118,6 +144,7 @@
 #define AMEDIAMETRICS_PROP_TRACKID        "trackId"        // int32 port id of track/record
 #define AMEDIAMETRICS_PROP_TYPE           "type"           // string (thread type)
 #define AMEDIAMETRICS_PROP_UNDERRUN       "underrun"       // int32
+#define AMEDIAMETRICS_PROP_UNDERRUNFRAMES "underrunFrames" // int64_t from Thread
 #define AMEDIAMETRICS_PROP_USAGE          "usage"          // string attributes (ATrack)
 #define AMEDIAMETRICS_PROP_VOLUME_LEFT    "volume.left"    // double (AudioTrack)
 #define AMEDIAMETRICS_PROP_VOLUME_RIGHT   "volume.right"   // double (AudioTrack)
@@ -129,12 +156,17 @@
 // Values are strings accepted for a given property.
 
 // An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE      "close"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE     "create"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH "createAudioPatch"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR       "ctor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT "disconnect"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR       "dtor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP "endAudioIntervalGroup"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH      "flush"  // AudioTrack
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE "invalidate" // server track, record
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN       "open"
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE      "pause"  // AudioTrack
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS "readParameters" // Thread
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_RESTORE    "restore"
@@ -144,4 +176,16 @@
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_STOP       "stop"   // AudioTrack, AudioRecord
 #define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN   "underrun" // from Thread
 
+// Possible values for AMEDIAMETRICS_PROP_CALLERNAME
+// Check within the framework for these strings as this header file may not be explicitly
+// included to avoid unnecessary cross-project dependencies.
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_AAUDIO        "aaudio"         // Native AAudio
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA          "java"           // Java API layer
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA         "media"          // libmedia
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_OPENSLES      "opensles"       // Open SLES
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_RTP           "rtp"            // RTP communication
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_SOUNDPOOL     "soundpool"      // SoundPool
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_TONEGENERATOR "tonegenerator"  // dial tones
+#define AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN       "unknown"        // callerName not set
+
 #endif // ANDROID_MEDIA_MEDIAMETRICSCONSTANTS_H
diff --git a/media/libmediametrics/include/media/MediaMetricsItem.h b/media/libmediametrics/include/media/MediaMetricsItem.h
index 08720f1..303343f 100644
--- a/media/libmediametrics/include/media/MediaMetricsItem.h
+++ b/media/libmediametrics/include/media/MediaMetricsItem.h
@@ -27,12 +27,8 @@
 #include <variant>
 
 #include <binder/Parcel.h>
-#include <cutils/properties.h>
 #include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/StrongPointer.h>
-#include <utils/Timers.h>
+#include <utils/Timers.h> // nsecs_t
 
 namespace android {
 
@@ -208,11 +204,11 @@
 
 template<size_t N>
 static inline bool startsWith(const std::string &s, const char (&comp)[N]) {
-    return !strncmp(s.c_str(), comp, N - 1);
+    return !strncmp(s.c_str(), comp, N - 1); // last char is null termination
 }
 
 static inline bool startsWith(const std::string& s, const std::string& comp) {
-    return !strncmp(s.c_str(), comp.c_str(), comp.size() - 1);
+    return !strncmp(s.c_str(), comp.c_str(), comp.size());
 }
 
 /**
@@ -223,7 +219,7 @@
 class Defer {
 public:
     template <typename U>
-    Defer(U &&f) : mThunk(std::forward<U>(f)) {}
+    explicit Defer(U &&f) : mThunk(std::forward<U>(f)) {}
     ~Defer() { mThunk(); }
 
 private:
@@ -522,7 +518,7 @@
     BufferedItem(const BufferedItem&) = delete;
     BufferedItem& operator=(const BufferedItem&) = delete;
 
-    BufferedItem(const std::string key, char *begin, char *end)
+    BufferedItem(const std::string& key, char *begin, char *end)
         : BufferedItem(key.c_str(), begin, end) { }
 
     BufferedItem(const char *key, char *begin, char *end)
@@ -687,7 +683,7 @@
 template <size_t N = 4096>
 class LogItem : public BufferedItem {
 public:
-    explicit LogItem(const std::string key) : LogItem(key.c_str()) { }
+    explicit LogItem(const std::string& key) : LogItem(key.c_str()) { }
 
     // Since this class will not be defined before the base class, we initialize variables
     // in our own order.
@@ -742,10 +738,10 @@
             mElem = other.mElem;
             return *this;
         }
-        Prop(Prop&& other) {
+        Prop(Prop&& other) noexcept {
             *this = std::move(other);
         }
-        Prop& operator=(Prop&& other) {
+        Prop& operator=(Prop&& other) noexcept {
             mName = std::move(other.mName);
             mElem = std::move(other.mElem);
             return *this;
@@ -856,7 +852,7 @@
     // Iteration of props within item
     class iterator {
     public:
-        iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
+        explicit iterator(const std::map<std::string, Prop>::const_iterator &_it) : it(_it) { }
         iterator &operator++() {
             ++it;
             return *this;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 81ffcbc..c0da0ce 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -57,7 +57,6 @@
 #include <media/MediaMetadataRetrieverInterface.h>
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/MediaCodecList.h>
@@ -68,7 +67,7 @@
 #include <media/stagefright/foundation/ALooperRoster.h>
 #include <media/stagefright/SurfaceUtils.h>
 #include <mediautils/BatteryNotifier.h>
-
+#include <mediautils/MemoryLeakTrackUtil.h>
 #include <memunreachable/memunreachable.h>
 #include <system/audio.h>
 
@@ -2207,7 +2206,9 @@
                     targetSpeed,
                     mSelectedDeviceId);
         }
-
+        // Set caller name so it can be logged in destructor.
+        // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
+        t->setCallerName("media");
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
             ALOGE("Unable to create audio track");
             delete newcbd;
diff --git a/media/libmediatranscoding/Android.bp b/media/libmediatranscoding/Android.bp
index 7468426..f948bd8 100644
--- a/media/libmediatranscoding/Android.bp
+++ b/media/libmediatranscoding/Android.bp
@@ -17,6 +17,7 @@
 // AIDL interfaces of MediaTranscoding.
 aidl_interface {
     name: "mediatranscoding_aidl_interface",
+    unstable: true,
     local_include_dir: "aidl",
     srcs: [
         "aidl/android/media/IMediaTranscodingService.aidl",
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 73d3a0b..63ab654 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2053,17 +2053,34 @@
     if (mIsVideo || mIsImage) {
         // determine need for software renderer
         bool usingSwRenderer = false;
-        if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) {
-            usingSwRenderer = true;
-            haveNativeWindow = false;
-            (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
-        } else if (haveNativeWindow && !storingMetadataInDecodedBuffers()) {
-            err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
-            if (err != OK) {
-                return err;
+        if (haveNativeWindow) {
+            bool requiresSwRenderer = false;
+            OMX_PARAM_U32TYPE param;
+            InitOMXParams(&param);
+            param.nPortIndex = kPortIndexOutput;
+
+            status_t err = mOMXNode->getParameter(
+                    (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidRequiresSwRenderer,
+                    &param, sizeof(param));
+
+            if (err == OK && param.nU32 == 1) {
+                requiresSwRenderer = true;
             }
+
+            if (mComponentName.startsWith("OMX.google.") || requiresSwRenderer) {
+                usingSwRenderer = true;
+                haveNativeWindow = false;
+                (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
+            } else if (!storingMetadataInDecodedBuffers()) {
+                err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
+                if (err != OK) {
+                    return err;
+                }
+            }
+
         }
 
+
         if (encoder) {
             err = setupVideoEncoder(mime, msg, outputFormat, inputFormat);
         } else {
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index e5115d9..fa13f32 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -134,7 +134,12 @@
     }
     ssize_t result = -1;
     ssize_t codecDataOffset = 0;
-    if (mCrypto != NULL) {
+    if (numSubSamples == 1
+            && subSamples[0].mNumBytesOfClearData == 0
+            && subSamples[0].mNumBytesOfEncryptedData == 0) {
+        // We don't need to go through crypto or descrambler if the input is empty.
+        result = 0;
+    } else if (mCrypto != NULL) {
         hardware::drm::V1_0::DestinationBuffer destination;
         if (secure) {
             destination.type = DrmBufferType::NATIVE_HANDLE;
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 00c5b40..4bc861e 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -108,6 +108,9 @@
                     selectedDeviceId,
                     selectedMicDirection,
                     selectedMicFieldDimension);
+        // Set caller name so it can be logged in destructor.
+        // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_MEDIA
+        mRecord->setCallerName("media");
         mInitCheck = mRecord->initCheck();
         if (mInitCheck != OK) {
             mRecord.clear();
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b597583..11f2f38 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -199,6 +199,7 @@
     void addResource(const MediaResourceParcel &resource);
     void removeResource(const MediaResourceParcel &resource);
     void removeClient();
+    void markClientForPendingRemoval();
     bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
 
 private:
@@ -280,6 +281,14 @@
     mService->removeClient(mPid, getId(mClient));
 }
 
+void MediaCodec::ResourceManagerServiceProxy::markClientForPendingRemoval() {
+    Mutex::Autolock _l(mLock);
+    if (mService == nullptr) {
+        return;
+    }
+    mService->markClientForPendingRemoval(mPid, getId(mClient));
+}
+
 bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
         const std::vector<MediaResourceParcel> &resources) {
     Mutex::Autolock _l(mLock);
@@ -297,6 +306,33 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+class MediaCodec::ReleaseSurface {
+public:
+    ReleaseSurface() {
+        BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mSurface = new Surface(mProducer, false /* controlledByApp */);
+        struct ConsumerListener : public BnConsumerListener {
+            void onFrameAvailable(const BufferItem&) override {}
+            void onBuffersReleased() override {}
+            void onSidebandStreamChanged() override {}
+        };
+        sp<ConsumerListener> listener{new ConsumerListener};
+        mConsumer->consumerConnect(listener, false);
+        mConsumer->setConsumerName(String8{"MediaCodec.release"});
+    }
+
+    const sp<Surface> &getSurface() {
+        return mSurface;
+    }
+
+private:
+    sp<IGraphicBufferProducer> mProducer;
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<Surface> mSurface;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
 namespace {
 
 enum {
@@ -1432,7 +1468,13 @@
 
 status_t MediaCodec::release() {
     sp<AMessage> msg = new AMessage(kWhatRelease, this);
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
 
+status_t MediaCodec::releaseAsync() {
+    sp<AMessage> msg = new AMessage(kWhatRelease, this);
+    msg->setInt32("async", 1);
     sp<AMessage> response;
     return PostAndAwaitResponse(msg, &response);
 }
@@ -2600,7 +2642,9 @@
 
                     mResourceManagerProxy->removeClient();
 
-                    (new AMessage)->postReply(mReplyID);
+                    if (mReplyID != nullptr) {
+                        (new AMessage)->postReply(mReplyID);
+                    }
                     break;
                 }
 
@@ -2987,6 +3031,26 @@
                 break;
             }
 
+            int32_t async = 0;
+            if (msg->findInt32("async", &async) && async) {
+                if ((mState ==  CONFIGURED || mState == STARTED || mState == FLUSHED)
+                       && mSurface != NULL) {
+                    if (!mReleaseSurface) {
+                        mReleaseSurface.reset(new ReleaseSurface);
+                    }
+                    status_t err = connectToSurface(mReleaseSurface->getSurface());
+                    ALOGW_IF(err != OK, "error connecting to release surface: err = %d", err);
+                    if (err == OK && !(mFlags & kFlagUsesSoftwareRenderer)) {
+                        err = mCodec->setSurface(mReleaseSurface->getSurface());
+                        ALOGW_IF(err != OK, "error setting release surface: err = %d", err);
+                    }
+                    if (err == OK) {
+                        (void)disconnectFromSurface();
+                        mSurface = mReleaseSurface->getSurface();
+                    }
+                }
+            }
+
             mReplyID = replyID;
             setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
 
@@ -2999,6 +3063,12 @@
                 pushBlankBuffersToNativeWindow(mSurface.get());
             }
 
+            if (async) {
+                mResourceManagerProxy->markClientForPendingRemoval();
+                (new AMessage)->postReply(mReplyID);
+                mReplyID = 0;
+            }
+
             break;
         }
 
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 7fec072..1395c27 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -221,6 +221,7 @@
 
 void MediaCodecSource::Puller::resume() {
     Mutexed<Queue>::Locked queue(mQueue);
+    queue->flush();
     queue->mPaused = false;
 }
 
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 94267a1..c6e753d 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -302,6 +302,12 @@
 #endif
             "/extractors", NULL, *newList);
 
+    RegisterExtractors("/system_ext/lib"
+#ifdef __LP64__
+            "64"
+#endif
+            "/extractors", NULL, *newList);
+
     newList->sort(compareFunc);
     gPlugins = newList;
 
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 986c9ac..cff14ac 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -1423,7 +1423,7 @@
     // stall since no future events are expected.
     mEndOfStream = true;
 
-    if (mExecuting && !haveAvailableBuffers_l()) {
+    if (mStopTimeUs == -1 && mExecuting && !haveAvailableBuffers_l()) {
         submitEndOfInputStream_l();
     }
 
diff --git a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
index ddc818e..c9c1cd4 100644
--- a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
+++ b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
@@ -337,7 +337,10 @@
     st = (Decoder_State *) spd_state;
 
     /* mode verification */
-
+    if (mode < 0 || mode >= NUM_OF_MODES)
+    {
+        return (-1);
+    }
     nb_bits = AMR_WB_COMPRESSED[mode];
 
     *frame_length = AMR_WB_PCM_FRAME;
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
index 679b091..a11f55e 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
@@ -409,7 +409,9 @@
         if (!BitstreamRead1Bits(stream)) return PV_FAIL;
 
         /* video_object_layer_width (13 bits) */
-        video->displayWidth = video->width = (int) BitstreamReadBits16(stream, 13);
+        tmpvar = BitstreamReadBits16(stream, 13);
+        if (!tmpvar) return PV_FAIL;
+        video->displayWidth = video->width = tmpvar;
 
         /* round up to a multiple of MB_SIZE.   08/09/2000 */
         video->width = (video->width + 15) & -16;
@@ -419,7 +421,9 @@
         if (!BitstreamRead1Bits(stream)) return PV_FAIL;
 
         /* video_object_layer_height (13 bits) */
-        video->displayHeight = video->height = (int) BitstreamReadBits16(stream, 13);
+        tmpvar = BitstreamReadBits16(stream, 13);
+        if (!tmpvar) return PV_FAIL;
+        video->displayHeight = video->height = tmpvar;
 
         /* round up to a multiple of MB_SIZE.   08/09/2000 */
         video->height = (video->height + 15) & -16;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
index df6cd03..a5c7f5e 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
@@ -659,20 +659,12 @@
     huffcodetab       *pHuff;
 
     pVars = (tmp3dec_file *)pMem;
-
-    pVars->num_channels = 0;
+    memset(pVars, 0, sizeof(*pVars));
 
     pExt->totalNumberOfBitsUsed = 0;
     pExt->inputBufferCurrentLength = 0;
     pExt->inputBufferUsedLength    = 0;
 
-    pVars->mainDataStream.offset = 0;
-
-    pv_memset((void*)pVars->mainDataBuffer,
-              0,
-              BUFSIZE*sizeof(*pVars->mainDataBuffer));
-
-
     pVars->inputStream.pBuffer = pExt->pInputBuffer;
 
     /*
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index f5687e0..784e802 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -126,12 +126,20 @@
     }
     header->num_streams = data[kOpusHeaderNumStreamsOffset];
     header->num_coupled = data[kOpusHeaderNumCoupledStreamsOffset];
-    if (header->num_streams + header->num_coupled != header->channels) {
-        ALOGV("Inconsistent channel mapping.");
+    if (header->num_coupled > header->num_streams ||
+        header->num_streams + header->num_coupled != header->channels) {
+        ALOGV("Inconsistent channel mapping, streams: %d coupled: %d channels: %d",
+        header->num_streams, header->num_coupled, header->channels);
         return false;
     }
-    for (int i = 0; i < header->channels; ++i)
-        header->stream_map[i] = data[kOpusHeaderStreamMapOffset + i];
+    for (int i = 0; i < header->channels; ++i) {
+        uint8_t value = data[kOpusHeaderStreamMapOffset + i];
+        if (value != 255 && value >= header->channels) {
+            ALOGV("Invalid channel mapping for index %i : %d", i, value);
+            return false;
+        }
+        header->stream_map[i] = value;
+    }
     return true;
 }
 
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
index c6c12ff..87cf58b 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
@@ -28,6 +28,10 @@
 #undef HIDE
 #define HIDE __attribute__((visibility("hidden")))
 
+// The internals of AUnion cause problems with CFI
+#undef  NO_CFI
+#define NO_CFI __attribute__((no_sanitize("cfi")))
+
 namespace android {
 
 /**
@@ -93,7 +97,7 @@
      * \param args      arbitrary arguments for constructor
      */
     template<typename T, typename ...Args>
-    inline static void emplace(size_t totalSize, T *addr, Args&&... args) {
+    inline static void NO_CFI emplace(size_t totalSize, T *addr, Args&&... args) {
         new(addr)T(std::forward<Args>(args)...);
         // clear slack space - this is not technically required
         constexpr size_t size = sizeof(T);
@@ -160,7 +164,7 @@
     template<
             typename T, typename ...Args,
             typename=typename std::enable_if<is_one_of<T, void, Ts...>::value>::type>
-    inline void emplace(Args&&... args) {
+    inline void NO_CFI emplace(Args&&... args) {
         _AUnion_impl::emplace(
                 sizeof(_type), reinterpret_cast<T*>(&mValue), std::forward<Args>(args)...);
     }
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 425468f..e97f6eb 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -107,20 +107,6 @@
     }
 }
 
-ID3::ID3(DataSourceBase *source, bool ignoreV1, off64_t offset)
-    : mIsValid(false),
-      mData(NULL),
-      mSize(0),
-      mFirstFrameOffset(0),
-      mVersion(ID3_UNKNOWN),
-      mRawSize(0) {
-    mIsValid = parseV2(source, offset);
-
-    if (!mIsValid && !ignoreV1) {
-        mIsValid = parseV1(source);
-    }
-}
-
 ID3::ID3(const uint8_t *data, size_t size, bool ignoreV1)
     : mIsValid(false),
       mData(NULL),
@@ -247,44 +233,14 @@
         return false;
     }
 
-    if (header.version_major == 4) {
-        void *copy = malloc(size);
-        if (copy == NULL) {
-            free(mData);
-            mData = NULL;
-            ALOGE("b/24623447, no more memory");
-            return false;
-        }
-
-        memcpy(copy, mData, size);
-
-        bool success = removeUnsynchronizationV2_4(false /* iTunesHack */);
-        if (!success) {
-            memcpy(mData, copy, size);
-            mSize = size;
-
-            success = removeUnsynchronizationV2_4(true /* iTunesHack */);
-
-            if (success) {
-                ALOGV("Had to apply the iTunes hack to parse this ID3 tag");
-            }
-        }
-
-        free(copy);
-        copy = NULL;
-
-        if (!success) {
-            free(mData);
-            mData = NULL;
-
-            return false;
-        }
-    } else if (header.flags & 0x80) {
+    // first handle global unsynchronization
+    if (header.flags & 0x80) {
         ALOGV("removing unsynchronization");
 
         removeUnsynchronization();
     }
 
+    // handle extended header, if present
     mFirstFrameOffset = 0;
     if (header.version_major == 3 && (header.flags & 0x40)) {
         // Version 2.3 has an optional extended header.
@@ -296,6 +252,7 @@
             return false;
         }
 
+        // v2.3 does not have syncsafe integers
         size_t extendedHeaderSize = U32_AT(&mData[0]);
         if (extendedHeaderSize > SIZE_MAX - 4) {
             free(mData);
@@ -367,6 +324,48 @@
         mFirstFrameOffset = ext_size;
     }
 
+    // Handle any v2.4 per-frame unsynchronization
+    // The id3 spec isn't clear about what should happen if the global
+    // unsynchronization flag is combined with per-frame unsynchronization,
+    // or whether that's even allowed, so this code assumes id3 writing
+    // tools do the right thing and not apply double-unsynchronization,
+    // but will honor the flags if they are set.
+    if (header.version_major == 4) {
+        void *copy = malloc(size);
+        if (copy == NULL) {
+            free(mData);
+            mData = NULL;
+            ALOGE("b/24623447, no more memory");
+            return false;
+        }
+
+        memcpy(copy, mData, size);
+
+        bool success = removeUnsynchronizationV2_4(false /* iTunesHack */);
+        if (!success) {
+            memcpy(mData, copy, size);
+            mSize = size;
+
+            success = removeUnsynchronizationV2_4(true /* iTunesHack */);
+
+            if (success) {
+                ALOGV("Had to apply the iTunes hack to parse this ID3 tag");
+            }
+        }
+
+        free(copy);
+        copy = NULL;
+
+        if (!success) {
+            free(mData);
+            mData = NULL;
+
+            return false;
+        }
+    }
+
+
+
     if (header.version_major == 2) {
         mVersion = ID3_V2_2;
     } else if (header.version_major == 3) {
@@ -411,7 +410,7 @@
 bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
     size_t oldSize = mSize;
 
-    size_t offset = 0;
+    size_t offset = mFirstFrameOffset;
     while (mSize >= 10 && offset <= mSize - 10) {
         if (!memcmp(&mData[offset], "\0\0\0\0", 4)) {
             break;
@@ -445,7 +444,7 @@
         }
 
         if ((flags & 2) && (dataSize >= 2)) {
-            // This file has "unsynchronization", so we have to replace occurrences
+            // This frame has "unsynchronization", so we have to replace occurrences
             // of 0xff 0x00 with just 0xff in order to get the real data.
 
             size_t readOffset = offset + 11;
diff --git a/media/libstagefright/id3/test/ID3Test.cpp b/media/libstagefright/id3/test/ID3Test.cpp
index a8f1470..cd5cd9e 100644
--- a/media/libstagefright/id3/test/ID3Test.cpp
+++ b/media/libstagefright/id3/test/ID3Test.cpp
@@ -24,6 +24,7 @@
 #include <datasource/FileSource.h>
 
 #include <media/stagefright/foundation/hexdump.h>
+#include <media/MediaExtractorPluginHelper.h>
 #include <ID3.h>
 
 #include "ID3TestEnvironment.h"
@@ -42,7 +43,8 @@
     string path = gEnv->getRes() + GetParam();
     sp<FileSource> file = new FileSource(path.c_str());
     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
-    ID3 tag(file.get());
+    DataSourceHelper helper(file->wrap());
+    ID3 tag(&helper);
     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
 
     ID3::Iterator it(tag, nullptr);
@@ -61,7 +63,8 @@
     sp<android::FileSource> file = new FileSource(path.c_str());
     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
 
-    ID3 tag(file.get());
+    DataSourceHelper helper(file->wrap());
+    ID3 tag(&helper);
     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
     ASSERT_TRUE(tag.version() >= versionNumber)
             << "Expected version: " << tag.version() << " Found version: " << versionNumber;
@@ -73,7 +76,8 @@
     sp<android::FileSource> file = new FileSource(path.c_str());
     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
 
-    ID3 tag(file.get());
+    DataSourceHelper helper(file->wrap());
+    ID3 tag(&helper);
     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
     int countTextFrames = 0;
     ID3::Iterator it(tag, nullptr);
@@ -99,7 +103,8 @@
     sp<android::FileSource> file = new FileSource(path.c_str());
     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
 
-    ID3 tag(file.get());
+    DataSourceHelper helper(file->wrap());
+    ID3 tag(&helper);
     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
     size_t dataSize;
     String8 mime;
@@ -124,7 +129,8 @@
     sp<android::FileSource> file = new FileSource(path.c_str());
     ASSERT_EQ(file->initCheck(), (status_t)OK) << "File initialization failed! \n";
 
-    ID3 tag(file.get());
+    DataSourceHelper helper(file->wrap());
+    ID3 tag(&helper);
     ASSERT_TRUE(tag.isValid()) << "No valid ID3 tag found for " << path.c_str() << "\n";
     int count = 0;
     ID3::Iterator it(tag, nullptr);
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 9984d85..5cd51cf 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -24,6 +24,7 @@
 #include <binder/ProcessState.h>
 #include <datasource/FileSource.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/MediaExtractorPluginHelper.h>
 
 #define MAXPATHLEN 256
 
@@ -72,7 +73,8 @@
     sp<FileSource> file = new FileSource(path);
     CHECK_EQ(file->initCheck(), (status_t)OK);
 
-    ID3 tag(file.get());
+    DataSourceHelper helper(file->wrap());
+    ID3 tag(&helper);
     if (!tag.isValid()) {
         printf("FAIL %s\n", path);
     } else {
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 2843a7a..0be5896 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -37,7 +37,6 @@
     };
 
     explicit ID3(DataSourceHelper *source, bool ignoreV1 = false, off64_t offset = 0);
-    explicit ID3(DataSourceBase *source, bool ignoreV1 = false, off64_t offset = 0);
     ID3(const uint8_t *data, size_t size, bool ignoreV1 = false);
     ~ID3();
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 022c48e..63a9dad 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -139,6 +139,8 @@
     // object.
     status_t release();
 
+    status_t releaseAsync();
+
     status_t flush();
 
     status_t queueInputBuffer(
@@ -509,6 +511,9 @@
                                                  // when low latency is on
     int64_t mInputBufferCounter;  // number of input buffers queued since last reset/flush
 
+    class ReleaseSurface;
+    std::unique_ptr<ReleaseSurface> mReleaseSurface;
+
     sp<BatteryChecker> mBatteryChecker;
 
     void statsBufferSent(int64_t presentationUs);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index bfdc9e7..178d334 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -790,6 +790,8 @@
 constexpr char KEY_OPERATING_RATE[] = "operating-rate";
 constexpr char KEY_OUTPUT_REORDER_DEPTH[] = "output-reorder-depth";
 constexpr char KEY_PCM_ENCODING[] = "pcm-encoding";
+constexpr char KEY_PIXEL_ASPECT_RATIO_HEIGHT[] = "sar-height";
+constexpr char KEY_PIXEL_ASPECT_RATIO_WIDTH[] = "sar-width";
 constexpr char KEY_PREPEND_HEADERS_TO_SYNC_FRAMES[] = "prepend-sps-pps-to-idr-frames";
 constexpr char KEY_PRIORITY[] = "priority";
 constexpr char KEY_PROFILE[] = "profile";
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 657144c..4bb21fa 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1153,7 +1153,7 @@
     }
 
     const RangeInfo &info = *mRangeInfos.begin();
-    if (mBuffer->size() < info.mLength) {
+    if (info.mLength == 0 || mBuffer->size() < info.mLength) {
         return NULL;
     }
 
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index a720bc9..8c186c9 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -34,12 +34,7 @@
     const char *mRole;
 
 } kComponents[] = {
-    // two choices for aac decoding.
-    // configurable in media/libstagefright/data/media_codecs_google_audio.xml
-    // default implementation
     { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
-    // alternate implementation
-    { "OMX.google.xaac.decoder", "xaacdec", "audio_decoder.aac" },
     { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },
     { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
     { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 1e434cb..7bd33c1 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -203,6 +203,14 @@
     unsigned mSerial;
 };
 
+bool AMPEG4ElementaryAssembler::initCheck() {
+    if(mSizeLength == 0 || mIndexLength == 0 || mIndexDeltaLength == 0) {
+        android_errorWriteLog(0x534e4554, "124777537");
+        return false;
+    }
+    return true;
+}
+
 ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket(
         const sp<ARTPSource> &source) {
     List<sp<ABuffer> > *queue = source->queue();
@@ -250,12 +258,16 @@
     } else {
         // hexdump(buffer->data(), buffer->size());
         if (buffer->size() < 2) {
+            android_errorWriteLog(0x534e4554, "124783982");
+            queue->erase(queue->begin());
             return MALFORMED_PACKET;
         }
 
         unsigned AU_headers_length = U16_AT(buffer->data());  // in bits
 
         if (buffer->size() < 2 + (AU_headers_length + 7) / 8) {
+            android_errorWriteLog(0x534e4554, "124783982");
+            queue->erase(queue->begin());
             return MALFORMED_PACKET;
         }
 
@@ -338,6 +350,12 @@
             ABitReader bits(buffer->data() + offset, buffer->size() - offset);
 
             unsigned auxSize = bits.getBits(mAuxiliaryDataSizeLength);
+            if (buffer->size() < auxSize) {
+                ALOGE("b/123940919 auxSize %u", auxSize);
+                android_errorWriteLog(0x534e4554, "123940919");
+                queue->erase(queue->begin());
+                return MALFORMED_PACKET;
+            }
 
             offset += (mAuxiliaryDataSizeLength + auxSize + 7) / 8;
         }
@@ -346,7 +364,15 @@
              it != headers.end(); ++it) {
             const AUHeader &header = *it;
 
+            if (buffer->size() < header.mSize) {
+                ALOGE("b/123940919 AU_size %u", header.mSize);
+                android_errorWriteLog(0x534e4554, "123940919");
+                queue->erase(queue->begin());
+                return MALFORMED_PACKET;
+            }
             if (buffer->size() < offset + header.mSize) {
+                android_errorWriteLog(0x534e4554, "124783982");
+                queue->erase(queue->begin());
                 return MALFORMED_PACKET;
             }
 
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
index 693fca5..57b7d71 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
@@ -36,6 +36,7 @@
     AMPEG4ElementaryAssembler(
             const sp<AMessage> &notify, const AString &desc,
             const AString &params);
+    virtual bool initCheck();
 
 protected:
     virtual ~AMPEG4ElementaryAssembler();
diff --git a/media/libstagefright/rtsp/ARTPAssembler.h b/media/libstagefright/rtsp/ARTPAssembler.h
index 7c147be..4082d4c 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.h
+++ b/media/libstagefright/rtsp/ARTPAssembler.h
@@ -39,6 +39,7 @@
 
     void onPacketReceived(const sp<ARTPSource> &source);
     virtual void onByeReceived() = 0;
+    virtual bool initCheck() { return true; }
 
 protected:
     virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source) = 0;
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 4afa6f4..f5f8128 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -82,6 +82,10 @@
     } else {
         TRESPASS();
     }
+
+    if (mAssembler != NULL && !mAssembler->initCheck()) {
+        mAssembler.clear();
+    }
 }
 
 static uint32_t AbsDiff(uint32_t seq1, uint32_t seq2) {
@@ -89,7 +93,7 @@
 }
 
 void ARTPSource::processRTPPacket(const sp<ABuffer> &buffer) {
-    if (queuePacket(buffer) && mAssembler != NULL) {
+    if (mAssembler != NULL && queuePacket(buffer)) {
         mAssembler->onPacketReceived(this);
     }
 }
@@ -171,7 +175,9 @@
 }
 
 void ARTPSource::byeReceived() {
-    mAssembler->onByeReceived();
+    if (mAssembler != NULL) {
+        mAssembler->onByeReceived();
+    }
 }
 
 void ARTPSource::addFIR(const sp<ABuffer> &buffer) {
diff --git a/media/libstagefright/tests/extractorFactory/Android.bp b/media/libstagefright/tests/extractorFactory/Android.bp
new file mode 100644
index 0000000..e3e61d7
--- /dev/null
+++ b/media/libstagefright/tests/extractorFactory/Android.bp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+    name: "ExtractorFactoryTest",
+    gtest: true,
+
+    srcs: [
+        "ExtractorFactoryTest.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libbase",
+        "libutils",
+        "libmedia",
+        "libbinder",
+        "libcutils",
+        "libdl_android",
+        "libdatasource",
+        "libmediametrics",
+    ],
+
+    static_libs: [
+        "libstagefright",
+        "libstagefright_foundation",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+    ],
+
+    // TODO: (b/150181583)
+    compile_multilib: "first",
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/tests/extractorFactory/AndroidTest.xml b/media/libstagefright/tests/extractorFactory/AndroidTest.xml
new file mode 100644
index 0000000..3aa6392
--- /dev/null
+++ b/media/libstagefright/tests/extractorFactory/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Test module config for extractor factory unit tests">
+    <option name="test-suite-tag" value="ExtractorFactoryTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="ExtractorFactoryTest->/data/local/tmp/ExtractorFactoryTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/extractors/tests/extractor.zip?unzip=true"
+            value="/data/local/tmp/ExtractorFactoryTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="ExtractorFactoryTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/ExtractorFactoryTestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/tests/extractorFactory/ExtractorFactoryTest.cpp b/media/libstagefright/tests/extractorFactory/ExtractorFactoryTest.cpp
new file mode 100644
index 0000000..d155caa
--- /dev/null
+++ b/media/libstagefright/tests/extractorFactory/ExtractorFactoryTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExtractorFactoryTest"
+#include <utils/Log.h>
+
+#include <binder/ProcessState.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaExtractorFactory.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+
+#include "ExtractorFactoryTestEnvironment.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/exFactoryLogs"
+
+using namespace android;
+
+static ExtractorFactoryTestEnvironment *gEnv = nullptr;
+
+class ExtractorFactoryTest : public ::testing::TestWithParam<pair<string, string>> {
+  public:
+    ExtractorFactoryTest() : mDataSource(nullptr), mExtractor(nullptr) {}
+
+    ~ExtractorFactoryTest() {
+        if (mDataSource) {
+            mDataSource.clear();
+            mDataSource = nullptr;
+        }
+        if (mExtractor) {
+            mExtractor.clear();
+            mExtractor = nullptr;
+        }
+    }
+
+    int32_t createDataSource(string inputFileName);
+    int32_t createExtractor(bool createFromService, string inputMime);
+
+    sp<DataSource> mDataSource;
+    sp<IMediaExtractor> mExtractor;
+};
+
+int32_t ExtractorFactoryTest::createDataSource(string inputFileName) {
+    FILE *mInputFp = fopen(inputFileName.c_str(), "rb");
+    if (!mInputFp) {
+        ALOGE("Unable to open input file : %s for reading", inputFileName.c_str());
+        return -1;
+    }
+    struct stat buf;
+    int32_t status = stat(inputFileName.c_str(), &buf);
+    if (status != 0) {
+        ALOGE("Failed to read file properties for input file : %s", inputFileName.c_str());
+        return -1;
+    }
+    int32_t fd = fileno(mInputFp);
+    if (fd < 0) {
+        ALOGE("Invalid file descriptor for input file : %s", inputFileName.c_str());
+        return -1;
+    }
+    mDataSource = new FileSource(dup(fd), 0, buf.st_size);
+    if (!mDataSource) return -1;
+    return 0;
+}
+
+int32_t ExtractorFactoryTest::createExtractor(bool createFromService, string inputMime) {
+    ALOGV("Creating extractor for mime : %s", inputMime.c_str());
+    if (createFromService) {
+        mExtractor = MediaExtractorFactory::CreateFromService(mDataSource, inputMime.c_str());
+    } else {
+        mExtractor = MediaExtractorFactory::Create(mDataSource);
+    }
+    if (mExtractor == nullptr) return -1;
+    return 0;
+}
+
+TEST_F(ExtractorFactoryTest, ListExtractorsTest) {
+    MediaExtractorFactory::LoadExtractors();
+    vector<std::string> supportedTypes = MediaExtractorFactory::getSupportedTypes();
+    ASSERT_GT(supportedTypes.size(), 0) << " MediaExtractorFactory doesn't suuport any extractor";
+
+    FILE *outputLog = fopen(OUTPUT_FILE_NAME, "wb");
+    ASSERT_NE(outputLog, nullptr) << "Unable to open output file - " << OUTPUT_FILE_NAME
+                                  << " for writing";
+
+    int32_t fd = fileno(outputLog);
+    ASSERT_GE(fd, 0);
+
+    Vector<String16> args;
+    int32_t status = MediaExtractorFactory::dump(fd, args);
+    ASSERT_EQ(status, OK) << "MediaExtractorFactory dump failed";
+    fclose(outputLog);
+}
+
+TEST_P(ExtractorFactoryTest, ExtractorFactoryApiTest) {
+    string inputMime = GetParam().second;
+    string inputFileName = gEnv->getRes() + GetParam().first;
+
+    MediaExtractorFactory::LoadExtractors();
+    bool createMode[] = {true, false};
+    for (bool createFromService : createMode) {
+        int32_t status = createDataSource(inputFileName);
+        ASSERT_EQ(status, 0) << "create data source failed";
+
+        status = createExtractor(createFromService, inputMime);
+        ASSERT_EQ(status, 0) << "Extractor creation failed for input: " << inputFileName;
+
+        int32_t numTracks = mExtractor->countTracks();
+        ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+        sp<MetaData> meta = mExtractor->getMetaData();
+        ASSERT_NE(meta, nullptr) << "getMetaData returned null";
+
+        const char *mime;
+        bool valueFound = meta->findCString(kKeyMIMEType, &mime);
+        ASSERT_TRUE(valueFound) << "Extractor did not provide MIME type";
+        ASSERT_EQ(mime, inputMime) << "Extractor factory returned invalid mime type";
+        mExtractor.clear();
+        mDataSource.clear();
+    }
+}
+
+// TODO: (b/150111966)
+// Replace mime strings with appropriate definitions
+INSTANTIATE_TEST_SUITE_P(
+        ExtractorFactoryTestAll, ExtractorFactoryTest,
+        ::testing::Values(make_pair("loudsoftaac.aac", MEDIA_MIMETYPE_AUDIO_AAC_ADTS),
+                          make_pair("testamr.amr", "audio/amr"),
+                          make_pair("amrwb.wav", MEDIA_MIMETYPE_AUDIO_AMR_WB),
+                          make_pair("john_cage.ogg", MEDIA_MIMETYPE_CONTAINER_OGG),
+                          make_pair("monotestgsm.wav", MEDIA_MIMETYPE_CONTAINER_WAV),
+                          make_pair("segment000001.ts", MEDIA_MIMETYPE_CONTAINER_MPEG2TS),
+                          make_pair("sinesweepflac.flac", MEDIA_MIMETYPE_AUDIO_FLAC),
+                          make_pair("testopus.opus", MEDIA_MIMETYPE_CONTAINER_OGG),
+                          make_pair("midi_a.mid", MEDIA_MIMETYPE_AUDIO_MIDI),
+                          make_pair("sinesweepvorbis.mkv", MEDIA_MIMETYPE_CONTAINER_MATROSKA),
+                          make_pair("sinesweepoggmp4.mp4", "audio/mp4"),
+                          make_pair("sinesweepmp3lame.mp3", MEDIA_MIMETYPE_AUDIO_MPEG),
+                          make_pair("swirl_144x136_vp9.webm", "video/webm"),
+                          make_pair("swirl_144x136_vp8.webm", "video/webm"),
+                          make_pair("swirl_132x130_mpeg4.mp4", MEDIA_MIMETYPE_CONTAINER_MPEG4)));
+
+int main(int argc, char **argv) {
+    ProcessState::self()->startThreadPool();
+    gEnv = new ExtractorFactoryTestEnvironment();
+    ::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/extractorFactory/ExtractorFactoryTestEnvironment.h b/media/libstagefright/tests/extractorFactory/ExtractorFactoryTestEnvironment.h
new file mode 100644
index 0000000..0fad4d3
--- /dev/null
+++ b/media/libstagefright/tests/extractorFactory/ExtractorFactoryTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EXTRACTOR_FACTORY_TEST_ENVIRONMENT_H__
+#define __EXTRACTOR_FACTORY_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class ExtractorFactoryTestEnvironment : public ::testing::Environment {
+  public:
+    ExtractorFactoryTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int ExtractorFactoryTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P':
+                setRes(optarg);
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __EXTRACTOR_FACTORY_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/tests/extractorFactory/README.md b/media/libstagefright/tests/extractorFactory/README.md
new file mode 100644
index 0000000..aaa71aa
--- /dev/null
+++ b/media/libstagefright/tests/extractorFactory/README.md
@@ -0,0 +1,37 @@
+## 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/ExtractorFactoryTest/ExtractorFactoryTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+
+adb push ${OUT}/data/nativetest/ExtractorFactoryTest/ExtractorFactoryTest /data/local/tmp/
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/extractors/tests/extractor.zip).
+Download, unzip and push these files into device for testing.
+
+```
+adb push extractor /data/local/tmp/
+```
+
+usage: ExtractorFactoryTest -P \<path_to_res_folder\>
+```
+adb shell /data/local/tmp/ExtractorFactoryTest -P /data/local/tmp/extractor/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest ExtractorFactoryTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp
index 0dc7722..2c2d11d 100644
--- a/media/libstagefright/timedtext/TextDescriptions.cpp
+++ b/media/libstagefright/timedtext/TextDescriptions.cpp
@@ -445,51 +445,75 @@
                     | *(tmpData + 10) << 8 | *(tmpData + 11);
                 parcel->writeInt32(rgba);
 
+                // tx3g box contains class FontTableBox() which extends ftab box
+                // This information is part of the 3gpp Timed Text Format
+                // Specification#: 26.245 / Section: 5.16(Sample Description Format)
+                // https://www.3gpp.org/ftp/Specs/archive/26_series/26.245/
+
                 tmpData += 12;
                 remaining -= 12;
 
-                if (remaining < 2) {
+                if (remaining < 8) {
                     return OK;
                 }
 
-                size_t dataPos = parcel->dataPosition();
-
-                parcel->writeInt32(KEY_STRUCT_FONT_LIST);
-                uint16_t count = U16_AT(tmpData);
-                parcel->writeInt32(count);
-
-                tmpData += 2;
-                remaining -= 2;
-
-                for (int i = 0; i < count; i++) {
-                    if (remaining < 3) {
-                        // roll back
-                        parcel->setDataPosition(dataPos);
-                        return OK;
-                    }
-                    // font ID
-                    parcel->writeInt32(U16_AT(tmpData));
-
-                    // font name length
-                    parcel->writeInt32(*(tmpData + 2));
-
-                    size_t len = *(tmpData + 2);
-
-                    tmpData += 3;
-                    remaining -= 3;
-
-                    if (remaining < len) {
-                        // roll back
-                        parcel->setDataPosition(dataPos);
-                        return OK;
-                    }
-
-                    parcel->write(tmpData, len);
-                    tmpData += len;
-                    remaining -= len;
+                size_t subChunkSize = U32_AT(tmpData);
+                if(remaining < subChunkSize) {
+                    return OK;
                 }
 
-                // there is a "DisparityBox" after this according to the spec, but we ignore it
+                uint32_t subChunkType = U32_AT(tmpData + 4);
+
+                if (subChunkType == FOURCC('f', 't', 'a', 'b'))
+                {
+                    tmpData += 8;
+                    size_t subChunkRemaining = subChunkSize - 8;
+
+                    if(subChunkRemaining < 2) {
+                        return OK;
+                    }
+                    size_t dataPos = parcel->dataPosition();
+
+                    parcel->writeInt32(KEY_STRUCT_FONT_LIST);
+                    uint16_t count = U16_AT(tmpData);
+                    parcel->writeInt32(count);
+
+                    tmpData += 2;
+                    subChunkRemaining -= 2;
+
+                    for (int i = 0; i < count; i++) {
+                        if (subChunkRemaining < 3) {
+                            // roll back
+                            parcel->setDataPosition(dataPos);
+                            return OK;
+                        }
+                        // font ID
+                        parcel->writeInt32(U16_AT(tmpData));
+
+                        // font name length
+                        size_t len = *(tmpData + 2);
+
+                        parcel->writeInt32(len);
+
+                        tmpData += 3;
+                        subChunkRemaining -=3;
+
+                        if (subChunkRemaining < len) {
+                            // roll back
+                            parcel->setDataPosition(dataPos);
+                            return OK;
+                        }
+
+                        parcel->writeByteArray(len, tmpData);
+                        tmpData += len;
+                        subChunkRemaining -= len;
+                    }
+                    tmpData += subChunkRemaining;
+                    remaining -= subChunkSize;
+                } else {
+                    tmpData += subChunkSize;
+                    remaining -= subChunkSize;
+                }
                 break;
             }
             default:
diff --git a/media/libstagefright/xmlparser/vts/Android.bp b/media/libstagefright/xmlparser/vts/Android.bp
index 3f93e9e..132ce82 100644
--- a/media/libstagefright/xmlparser/vts/Android.bp
+++ b/media/libstagefright/xmlparser/vts/Android.bp
@@ -30,4 +30,12 @@
         "-Wall",
         "-Werror",
     ],
+    data: [
+        ":media_codecs",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts"
+    ],
+    test_config: "vts_mediaCodecs_validate_test.xml",
 }
diff --git a/media/libstagefright/xmlparser/vts/vts_mediaCodecs_validate_test.xml b/media/libstagefright/xmlparser/vts/vts_mediaCodecs_validate_test.xml
new file mode 100644
index 0000000..fbb7cc6
--- /dev/null
+++ b/media/libstagefright/xmlparser/vts/vts_mediaCodecs_validate_test.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs vts_mediaCodecs_validate_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="media_codecs.xsd->/data/local/tmp/media_codecs.xsd" />
+        <option name="push" value="vts_mediaCodecs_validate_test->/data/local/tmp/vts_mediaCodecs_validate_test" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="vts_mediaCodecs_validate_test" />
+    </test>
+</configuration>
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
index ecb75a9..05373c9 100644
--- a/media/mediaserver/mediaserver.rc
+++ b/media/mediaserver/mediaserver.rc
@@ -6,4 +6,4 @@
     user media
     group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
     ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    task_profiles ProcessCapacityHigh HighPerformance
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index b7037e9..e3f1e44 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -19,6 +19,7 @@
         "AImageReaderUtils.cpp",
         "BatteryNotifier.cpp",
         "ISchedulingPolicyService.cpp",
+        "LimitProcessMemory.cpp",
         "MemoryLeakTrackUtil.cpp",
         "ProcessInfo.cpp",
         "SchedulingPolicyService.cpp",
diff --git a/media/libmedia/MediaUtils.cpp b/media/utils/LimitProcessMemory.cpp
similarity index 97%
rename from media/libmedia/MediaUtils.cpp
rename to media/utils/LimitProcessMemory.cpp
index 2efb30e..623138f 100644
--- a/media/libmedia/MediaUtils.cpp
+++ b/media/utils/LimitProcessMemory.cpp
@@ -23,8 +23,7 @@
 #include <unistd.h>
 
 #include <bionic/malloc.h>
-
-#include "MediaUtils.h"
+#include <mediautils/LimitProcessMemory.h>
 
 extern "C" void __scudo_set_rss_limit(size_t, int) __attribute__((weak));
 
diff --git a/media/utils/MemoryLeakTrackUtil.cpp b/media/utils/MemoryLeakTrackUtil.cpp
index 6166859..fdb8c4f 100644
--- a/media/utils/MemoryLeakTrackUtil.cpp
+++ b/media/utils/MemoryLeakTrackUtil.cpp
@@ -19,7 +19,7 @@
 #define LOG_TAG "MemoryLeackTrackUtil"
 #include <utils/Log.h>
 
-#include "media/MemoryLeakTrackUtil.h"
+#include <mediautils/MemoryLeakTrackUtil.h>
 #include <sstream>
 
 #include <bionic/malloc.h>
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 7fd4d0a..87ea084 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -223,25 +223,6 @@
     return ok;
 }
 
-bool accessCallAudioAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
-    static const String16 sAccessCallAudio("android.permission.ACCESS_CALL_AUDIO");
-    PermissionController permissionController;
-    const String16 resolvedOpPackageName = resolveCallingPackage(
-         permissionController, opPackageName, uid);
-    if (resolvedOpPackageName.size() == 0) {
-        ALOGE("accessCallAudioAllowed - FAIL - package not found.");
-        return false;
-    }
-    AppOpsManager appOps;
-    const int32_t op = appOps.permissionToOpCode(sAccessCallAudio);
-    const int32_t opResult = appOps.noteOp(op, uid, resolvedOpPackageName);
-    if (opResult == PermissionController::MODE_DEFAULT) {
-        // Only allow in case this is a system app with the proper privilege permission
-        return PermissionCache::checkPermission(sAccessCallAudio, pid, uid);
-    }
-    return opResult == PermissionController::MODE_ALLOWED;
-}
-
 // privileged behavior needed by Dialer, Settings, SetupWizard and CellBroadcastReceiver
 bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid) {
     static const String16 sWriteSecureSettings("android.permission.WRITE_SECURE_SETTINGS");
@@ -278,29 +259,28 @@
     return NO_ERROR;
 }
 
-void MediaPackageManager::loadPackageManager() {
-    if (mPackageManager != nullptr) {
-        return;
-    }
+sp<content::pm::IPackageManagerNative> MediaPackageManager::retreivePackageManager() {
     const sp<IServiceManager> sm = defaultServiceManager();
     if (sm == nullptr) {
         ALOGW("%s: failed to retrieve defaultServiceManager", __func__);
-        return;
+        return nullptr;
     }
     sp<IBinder> packageManager = sm->checkService(String16(nativePackageManagerName));
     if (packageManager == nullptr) {
         ALOGW("%s: failed to retrieve native package manager", __func__);
-        return;
+        return nullptr;
     }
-    mPackageManager = interface_cast<content::pm::IPackageManagerNative>(packageManager);
+    return interface_cast<content::pm::IPackageManagerNative>(packageManager);
 }
 
 std::optional<bool> MediaPackageManager::doIsAllowed(uid_t uid) {
-    /** Can not fetch package manager at construction it may not yet be registered. */
-    loadPackageManager();
     if (mPackageManager == nullptr) {
-        ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__);
-        return std::nullopt;
+        /** Can not fetch package manager at construction it may not yet be registered. */
+        mPackageManager = retreivePackageManager();
+        if (mPackageManager == nullptr) {
+            ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__);
+            return std::nullopt;
+        }
     }
 
     std::vector<std::string> packageNames;
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 4a3e470..59d74de 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -100,7 +100,6 @@
 bool TimeCheck::TimeCheckThread::threadLoop()
 {
     status_t status = TIMED_OUT;
-    const char *tag;
     {
         AutoMutex _l(mMutex);
 
@@ -109,6 +108,7 @@
         }
 
         nsecs_t endTimeNs = INT64_MAX;
+        const char *tag = "<unspecified>";
         // KeyedVector mMonitorRequests is ordered so take first entry as next timeout
         if (mMonitorRequests.size() != 0) {
             endTimeNs = mMonitorRequests.keyAt(0);
diff --git a/media/libmedia/MediaUtils.h b/media/utils/include/mediautils/LimitProcessMemory.h
similarity index 86%
rename from media/libmedia/MediaUtils.h
rename to media/utils/include/mediautils/LimitProcessMemory.h
index f80dd30..7f48b4f 100644
--- a/media/libmedia/MediaUtils.h
+++ b/media/utils/include/mediautils/LimitProcessMemory.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _MEDIA_UTILS_H
-#define _MEDIA_UTILS_H
+#ifndef ANDROID_MEDIAUTILS_LIMIT_PROCESS_MEMORY_H
+#define ANDROID_MEDIAUTILS_LIMIT_PROCESS_MEMORY_H
 
 namespace android {
 
@@ -32,4 +32,4 @@
 
 }   // namespace android
 
-#endif  // _MEDIA_UTILS_H
+#endif // ANDROID_MEDIAUTILS_LIMIT_PROCESS_MEMORY_H
diff --git a/media/libmedia/include/media/MemoryLeakTrackUtil.h b/media/utils/include/mediautils/MemoryLeakTrackUtil.h
similarity index 100%
rename from media/libmedia/include/media/MemoryLeakTrackUtil.h
rename to media/utils/include/mediautils/MemoryLeakTrackUtil.h
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 060e849..212599a 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -93,7 +93,6 @@
 bool dumpAllowed();
 bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
 bool bypassInterruptionPolicyAllowed(pid_t pid, uid_t uid);
-bool accessCallAudioAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
 
 status_t checkIMemory(const sp<IMemory>& iMemory);
 
@@ -111,7 +110,7 @@
 private:
     static constexpr const char* nativePackageManagerName = "package_native";
     std::optional<bool> doIsAllowed(uid_t uid);
-    void loadPackageManager();
+    sp<content::pm::IPackageManagerNative> retreivePackageManager();
     sp<content::pm::IPackageManagerNative> mPackageManager; // To check apps manifest
     uint_t mPackageManagerErrors = 0;
     struct Package {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ecda56b..de7ae40 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -67,10 +67,10 @@
 #include <powermanager/PowerManager.h>
 
 #include <media/IMediaLogService.h>
-#include <media/MemoryLeakTrackUtil.h>
 #include <media/nbaio/Pipe.h>
 #include <media/nbaio/PipeReader.h>
 #include <mediautils/BatteryNotifier.h>
+#include <mediautils/MemoryLeakTrackUtil.h>
 #include <mediautils/ServiceUtilities.h>
 #include <mediautils/TimeCheck.h>
 #include <private/android_filesystem_config.h>
@@ -135,7 +135,7 @@
 
 static sp<os::IExternalVibratorService> getExternalVibratorService() {
     if (sExternalVibratorService == 0) {
-        sp <IBinder> binder = defaultServiceManager()->getService(
+        sp<IBinder> binder = defaultServiceManager()->getService(
             String16("external_vibrator_service"));
         if (binder != 0) {
             sExternalVibratorService =
@@ -343,7 +343,7 @@
         ret = AudioSystem::getOutputForAttr(&localAttr, &io,
                                             actualSessionId,
                                             &streamType, client.clientPid, client.clientUid,
-                                            client.packageName, &fullConfig,
+                                            &fullConfig,
                                             (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ |
                                                     AUDIO_OUTPUT_FLAG_DIRECT),
                                             deviceId, &portId, &secondaryOutputs);
@@ -411,6 +411,7 @@
 
 status_t AudioFlinger::addEffectToHal(audio_port_handle_t deviceId,
         audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+    AutoMutex lock(mHardwareLock);
     AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
     if (audioHwDevice == nullptr) {
         return NO_INIT;
@@ -420,6 +421,7 @@
 
 status_t AudioFlinger::removeEffectFromHal(audio_port_handle_t deviceId,
         audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+    AutoMutex lock(mHardwareLock);
     AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
     if (audioHwDevice == nullptr) {
         return NO_INIT;
@@ -439,6 +441,7 @@
 {
     // if module is 0, the request comes from an old policy manager and we should load
     // well known modules
+    AutoMutex lock(mHardwareLock);
     if (module == 0) {
         ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
         for (size_t i = 0; i < arraysize(audio_interfaces); i++) {
@@ -783,9 +786,8 @@
     output.outputId = AUDIO_IO_HANDLE_NONE;
     output.selectedDeviceId = input.selectedDeviceId;
     lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
-                                            clientPid, clientUid, input.opPackageName,
-                                            &input.config, input.flags, &output.selectedDeviceId,
-                                            &portId, &secondaryOutputs);
+                                            clientPid, clientUid, &input.config, input.flags,
+                                            &output.selectedDeviceId, &portId, &secondaryOutputs);
 
     if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
         ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus);
@@ -1080,17 +1082,18 @@
     mMasterVolume = value;
 
     // Set master volume in the HALs which support it.
-    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+    {
         AutoMutex lock(mHardwareLock);
-        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
+        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+            AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
 
-        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        if (dev->canSetMasterVolume()) {
-            dev->hwDevice()->setMasterVolume(value);
+            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+            if (dev->canSetMasterVolume()) {
+                dev->hwDevice()->setMasterVolume(value);
+            }
+            mHardwareStatus = AUDIO_HW_IDLE;
         }
-        mHardwareStatus = AUDIO_HW_IDLE;
     }
-
     // Now set the master volume in each playback thread.  Playback threads
     // assigned to HALs which do not have master volume support will apply
     // master volume during the mix operation.  Threads with HALs which do
@@ -1157,6 +1160,9 @@
 
     { // scope for the lock
         AutoMutex lock(mHardwareLock);
+        if (mPrimaryHardwareDev == nullptr) {
+            return INVALID_OPERATION;
+        }
         sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
         mHardwareStatus = AUDIO_HW_SET_MODE;
         ret = dev->setMode(mode);
@@ -1186,15 +1192,24 @@
     }
 
     AutoMutex lock(mHardwareLock);
+    if (mPrimaryHardwareDev == nullptr) {
+        return INVALID_OPERATION;
+    }
+    sp<DeviceHalInterface> primaryDev = mPrimaryHardwareDev->hwDevice();
+    if (primaryDev == nullptr) {
+        ALOGW("%s: no primary HAL device", __func__);
+        return INVALID_OPERATION;
+    }
     mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
+    ret = primaryDev->setMicMute(state);
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
         sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
-        status_t result = dev->setMicMute(state);
-        if (result != NO_ERROR) {
-            ret = result;
+        if (dev != primaryDev) {
+            (void)dev->setMicMute(state);
         }
     }
     mHardwareStatus = AUDIO_HW_IDLE;
+    ALOGW_IF(ret != NO_ERROR, "%s: error %d setting state to HAL", __func__, ret);
     return ret;
 }
 
@@ -1204,20 +1219,21 @@
     if (ret != NO_ERROR) {
         return false;
     }
-    bool mute = true;
-    bool state = AUDIO_MODE_INVALID;
     AutoMutex lock(mHardwareLock);
-    mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
-    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
-        sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
-        status_t result = dev->getMicMute(&state);
-        if (result == NO_ERROR) {
-            mute = mute && state;
-        }
+    if (mPrimaryHardwareDev == nullptr) {
+        return false;
     }
+    sp<DeviceHalInterface> primaryDev = mPrimaryHardwareDev->hwDevice();
+    if (primaryDev == nullptr) {
+        ALOGW("%s: no primary HAL device", __func__);
+        return false;
+    }
+    bool state;
+    mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
+    ret = primaryDev->getMicMute(&state);
     mHardwareStatus = AUDIO_HW_IDLE;
-
-    return mute;
+    ALOGE_IF(ret != NO_ERROR, "%s: error %d getting state from HAL", __func__, ret);
+    return (ret == NO_ERROR) && state;
 }
 
 void AudioFlinger::setRecordSilenced(audio_port_handle_t portId, bool silenced)
@@ -1249,15 +1265,17 @@
     mMasterMute = muted;
 
     // Set master mute in the HALs which support it.
-    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+    {
         AutoMutex lock(mHardwareLock);
-        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
+        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+            AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
 
-        mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
-        if (dev->canSetMasterMute()) {
-            dev->hwDevice()->setMasterMute(muted);
+            mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
+            if (dev->canSetMasterMute()) {
+                dev->hwDevice()->setMasterMute(muted);
+            }
+            mHardwareStatus = AUDIO_HW_IDLE;
         }
-        mHardwareStatus = AUDIO_HW_IDLE;
     }
 
     // Now set the master mute in each playback thread.  Playback threads
@@ -1588,16 +1606,13 @@
     if (ioHandle == AUDIO_IO_HANDLE_NONE) {
         String8 out_s8;
 
+        AutoMutex lock(mHardwareLock);
         for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
             String8 s;
-            status_t result;
-            {
-            AutoMutex lock(mHardwareLock);
             mHardwareStatus = AUDIO_HW_GET_PARAMETER;
             sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
-            result = dev->getParameters(keys, &s);
+            status_t result = dev->getParameters(keys, &s);
             mHardwareStatus = AUDIO_HW_IDLE;
-            }
             if (result == OK) out_s8 += s;
         }
         return out_s8;
@@ -1630,6 +1645,9 @@
     }
 
     AutoMutex lock(mHardwareLock);
+    if (mPrimaryHardwareDev == nullptr) {
+        return 0;
+    }
     mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
 
     sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
@@ -1715,6 +1733,9 @@
     }
 
     AutoMutex lock(mHardwareLock);
+    if (mPrimaryHardwareDev == nullptr) {
+        return INVALID_OPERATION;
+    }
     sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
     mHardwareStatus = AUDIO_HW_SET_VOICE_VOLUME;
     ret = dev->setVoiceVolume(value);
@@ -2123,10 +2144,11 @@
         return AUDIO_MODULE_HANDLE_NONE;
     }
     Mutex::Autolock _l(mLock);
+    AutoMutex lock(mHardwareLock);
     return loadHwModule_l(name);
 }
 
-// loadHwModule_l() must be called with AudioFlinger::mLock held
+// loadHwModule_l() must be called with AudioFlinger::mLock and AudioFlinger::mHardwareLock held
 audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
 {
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
@@ -2158,44 +2180,49 @@
     // master mute and volume settings.
 
     AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
-    {  // scope for auto-lock pattern
-        AutoMutex lock(mHardwareLock);
-
-        if (0 == mAudioHwDevs.size()) {
-            mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
-            float mv;
-            if (OK == dev->getMasterVolume(&mv)) {
-                mMasterVolume = mv;
-            }
-
-            mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
-            bool mm;
-            if (OK == dev->getMasterMute(&mm)) {
-                mMasterMute = mm;
-            }
+    if (0 == mAudioHwDevs.size()) {
+        mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+        float mv;
+        if (OK == dev->getMasterVolume(&mv)) {
+            mMasterVolume = mv;
         }
 
-        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        if (OK == dev->setMasterVolume(mMasterVolume)) {
-            flags = static_cast<AudioHwDevice::Flags>(flags |
-                    AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
+        mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
+        bool mm;
+        if (OK == dev->getMasterMute(&mm)) {
+            mMasterMute = mm;
         }
-
-        mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
-        if (OK == dev->setMasterMute(mMasterMute)) {
-            flags = static_cast<AudioHwDevice::Flags>(flags |
-                    AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
-        }
-
-        mHardwareStatus = AUDIO_HW_IDLE;
     }
+
+    mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+    if (OK == dev->setMasterVolume(mMasterVolume)) {
+        flags = static_cast<AudioHwDevice::Flags>(flags |
+                AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
+    }
+
+    mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
+    if (OK == dev->setMasterMute(mMasterMute)) {
+        flags = static_cast<AudioHwDevice::Flags>(flags |
+                AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
+    }
+
+    mHardwareStatus = AUDIO_HW_IDLE;
+
     if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_MSD) == 0) {
         // An MSD module is inserted before hardware modules in order to mix encoded streams.
         flags = static_cast<AudioHwDevice::Flags>(flags | AudioHwDevice::AHWD_IS_INSERT);
     }
 
     audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
-    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
+    AudioHwDevice *audioDevice = new AudioHwDevice(handle, name, dev, flags);
+    if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
+        mPrimaryHardwareDev = audioDevice;
+        mHardwareStatus = AUDIO_HW_SET_MODE;
+        mPrimaryHardwareDev->hwDevice()->setMode(mMode);
+        mHardwareStatus = AUDIO_HW_IDLE;
+    }
+
+    mAudioHwDevs.add(handle, audioDevice);
 
     ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);
 
@@ -2281,6 +2308,7 @@
     }
 
     Mutex::Autolock _l(mLock);
+    AutoMutex lock(mHardwareLock);
     ssize_t index = mAudioHwDevs.indexOfKey(module);
     if (index < 0) {
         ALOGW("%s() bad hw module %d", __func__, module);
@@ -2302,8 +2330,15 @@
         return mHwAvSyncIds.valueAt(index);
     }
 
-    sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
-    if (dev == NULL) {
+    sp<DeviceHalInterface> dev;
+    {
+        AutoMutex lock(mHardwareLock);
+        if (mPrimaryHardwareDev == nullptr) {
+            return AUDIO_HW_SYNC_INVALID;
+        }
+        dev = mPrimaryHardwareDev->hwDevice();
+    }
+    if (dev == nullptr) {
         return AUDIO_HW_SYNC_INVALID;
     }
     String8 reply;
@@ -2371,8 +2406,21 @@
 status_t AudioFlinger::getMicrophones(std::vector<media::MicrophoneInfo> *microphones)
 {
     AutoMutex lock(mHardwareLock);
-    sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
-    status_t status = dev->getMicrophones(microphones);
+    status_t status = INVALID_OPERATION;
+
+    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+        std::vector<media::MicrophoneInfo> mics;
+        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
+        mHardwareStatus = AUDIO_HW_GET_MICROPHONES;
+        status_t devStatus = dev->hwDevice()->getMicrophones(&mics);
+        mHardwareStatus = AUDIO_HW_IDLE;
+        if (devStatus == NO_ERROR) {
+            microphones->insert(microphones->begin(), mics.begin(), mics.end());
+            // report success if at least one HW module supports the function.
+            status = NO_ERROR;
+        }
+    }
+
     return status;
 }
 
@@ -2519,12 +2567,13 @@
             // notify client processes of the new output creation
             playbackThread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
 
-            // the first primary output opened designates the primary hw device
-            if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
+            // the first primary output opened designates the primary hw device if no HW module
+            // named "primary" was already loaded.
+            AutoMutex lock(mHardwareLock);
+            if ((mPrimaryHardwareDev == nullptr) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
                 ALOGI("Using module %d as the primary audio interface", module);
                 mPrimaryHardwareDev = playbackThread->getOutput()->audioHwDev;
 
-                AutoMutex lock(mHardwareLock);
                 mHardwareStatus = AUDIO_HW_SET_MODE;
                 mPrimaryHardwareDev->hwDevice()->setMode(mMode);
                 mHardwareStatus = AUDIO_HW_IDLE;
@@ -3193,6 +3242,10 @@
 
 AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l() const
 {
+    AutoMutex lock(mHardwareLock);
+    if (mPrimaryHardwareDev == nullptr) {
+        return nullptr;
+    }
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
         if(thread->isDuplicating()) {
@@ -3203,7 +3256,7 @@
             return thread;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 DeviceTypeSet AudioFlinger::primaryOutputDevice_l() const
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 40519b0..20f561e 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -88,6 +88,8 @@
 #include "SpdifStreamOut.h"
 #include "AudioHwDevice.h"
 #include "NBAIO_Tee.h"
+#include "ThreadMetrics.h"
+#include "TrackMetrics.h"
 
 #include <powermanager/IPowerManager.h>
 
@@ -681,7 +683,8 @@
                                           struct audio_mmap_buffer_info *info);
         virtual status_t getMmapPosition(struct audio_mmap_position *position);
         virtual status_t start(const AudioClient& client,
-                                         audio_port_handle_t *handle);
+                               const audio_attributes_t *attr,
+                               audio_port_handle_t *handle);
         virtual status_t stop(audio_port_handle_t handle);
         virtual status_t standby();
 
@@ -834,10 +837,11 @@
                 // NOTE: If both mLock and mHardwareLock mutexes must be held,
                 // always take mLock before mHardwareLock
 
-                // These two fields are immutable after onFirstRef(), so no lock needed to access
-                AudioHwDevice*                      mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
+                // guarded by mHardwareLock
+                AudioHwDevice* mPrimaryHardwareDev;
                 DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>  mAudioHwDevs;
 
+                // These two fields are immutable after onFirstRef(), so no lock needed to access
                 sp<DevicesFactoryHalInterface> mDevicesFactoryHal;
                 sp<DevicesFactoryHalCallback> mDevicesFactoryHalCallback;
 
@@ -864,6 +868,7 @@
         AUDIO_HW_GET_PARAMETER,         // get_parameters
         AUDIO_HW_SET_MASTER_MUTE,       // set_master_mute
         AUDIO_HW_GET_MASTER_MUTE,       // get_master_mute
+        AUDIO_HW_GET_MICROPHONES,       // getMicrophones
     };
 
     mutable     hardware_call_state                 mHardwareStatus;    // for dump only
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 8a65122..55f2952 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -29,6 +29,7 @@
 #include <system/audio_effects/effect_visualizer.h>
 #include <audio_utils/channels.h>
 #include <audio_utils/primitives.h>
+#include <media/AudioCommonTypes.h>
 #include <media/AudioContainers.h>
 #include <media/AudioEffect.h>
 #include <media/AudioDeviceTypeAddr.h>
@@ -212,8 +213,8 @@
     bool registered = false;
     bool doEnable = false;
     bool enabled = false;
-    audio_io_handle_t io;
-    uint32_t strategy;
+    audio_io_handle_t io = AUDIO_IO_HANDLE_NONE;
+    uint32_t strategy = PRODUCT_STRATEGY_NONE;
 
     {
         Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 8b7a124..47fe0b3 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -309,7 +309,7 @@
                     // compute the delta value of clock_gettime(CLOCK_MONOTONIC)
                     uint32_t monotonicNs = nsec;
                     if (sec > 0 && sec < 4) {
-                        monotonicNs += sec * 1000000000;
+                        monotonicNs += sec * 1000000000U; // unsigned to prevent signed overflow.
                     }
                     // compute raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
                     uint32_t loadNs = 0;
@@ -325,7 +325,7 @@
                             }
                             loadNs = nsec;
                             if (sec > 0 && sec < 4) {
-                                loadNs += sec * 1000000000;
+                                loadNs += sec * 1000000000U; // unsigned to prevent signed overflow.
                             }
                         } else {
                             // first time through the loop
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1ff03c4..d8eebf3 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -171,6 +171,16 @@
 
             void    setTeePatches(TeePatches teePatches);
 
+    void tallyUnderrunFrames(size_t frames) override {
+       if (isOut()) { // we expect this from output tracks only
+           mAudioTrackServerProxy->tallyUnderrunFrames(frames);
+           // Fetch absolute numbers from AudioTrackShared as it counts
+           // contiguous underruns as a one -- we want a consistent number.
+           // TODO: isolate this counting into a class.
+           mTrackMetrics.logUnderruns(mAudioTrackServerProxy->getUnderrunCount(),
+                   mAudioTrackServerProxy->getUnderrunFrames());
+       }
+    }
 protected:
     // for numerous
     friend class PlaybackThread;
diff --git a/services/audioflinger/ThreadMetrics.h b/services/audioflinger/ThreadMetrics.h
new file mode 100644
index 0000000..7989de1
--- /dev/null
+++ b/services/audioflinger/ThreadMetrics.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_THREADMETRICS_H
+#define ANDROID_AUDIO_THREADMETRICS_H
+
+#include <mutex>
+
+namespace android {
+
+/**
+ * ThreadMetrics handles the AudioFlinger thread log statistics.
+ *
+ * We aggregate metrics for a particular device for proper analysis.
+ * This includes power, performance, and usage metrics.
+ *
+ * This class is thread-safe with a lock for safety.  There is no risk of deadlock
+ * as this class only executes external one-way calls in Mediametrics and does not
+ * call any other AudioFlinger class.
+ *
+ * Terminology:
+ * An AudioInterval is a contiguous playback segment.
+ * An AudioIntervalGroup is a group of continuous playback segments on the same device.
+ *
+ * We currently deliver metrics based on an AudioIntervalGroup.
+ */
+class ThreadMetrics final {
+public:
+    ThreadMetrics(std::string metricsId, bool isOut)
+        : mMetricsId(std::move(metricsId))
+        , mIsOut(isOut)
+        {}
+
+    ~ThreadMetrics() {
+        logEndInterval(); // close any open interval groups
+        std::lock_guard l(mLock);
+        deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+            .record();
+    }
+
+    // Called under the following circumstances
+    // 1) Upon a createPatch and we are not in standby
+    // 2) We come out of standby
+    void logBeginInterval() {
+        std::lock_guard l(mLock);
+        if (mDevices != mCreatePatchDevices) {
+            deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+            mDevices = mCreatePatchDevices; // set after endAudioIntervalGroup
+            resetIntervalGroupMetrics();
+            deliverDeviceMetrics(
+                    AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, mDevices.c_str());
+        }
+        if (mIntervalStartTimeNs == 0) {
+            ++mIntervalCount;
+            mIntervalStartTimeNs = systemTime();
+        }
+    }
+
+    void logConstructor(pid_t pid, const char *threadType, int32_t id) const {
+        mediametrics::LogItem(mMetricsId)
+            .setPid(pid)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+            .set(AMEDIAMETRICS_PROP_TYPE, threadType)
+            .set(AMEDIAMETRICS_PROP_THREADID, id)
+            .record();
+    }
+
+    void logCreatePatch(const std::string& devices) {
+        std::lock_guard l(mLock);
+        mCreatePatchDevices = devices;
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
+            .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, devices)
+            .record();
+    }
+
+    // Called when we are removed from the Thread.
+    void logEndInterval() {
+        std::lock_guard l(mLock);
+        if (mIntervalStartTimeNs != 0) {
+            const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
+            mIntervalStartTimeNs = 0;
+            mCumulativeTimeNs += elapsedTimeNs;
+            mDeviceTimeNs += elapsedTimeNs;
+        }
+    }
+
+    void logThrottleMs(double throttleMs) const {
+        mediametrics::LogItem(mMetricsId)
+            // ms units always double
+            .set(AMEDIAMETRICS_PROP_THROTTLEMS, (double)throttleMs)
+            .record();
+    }
+
+    void logLatency(double latencyMs) {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
+            .record();
+        std::lock_guard l(mLock);
+        mDeviceLatencyMs.add(latencyMs);
+    }
+
+    // TODO: further implement this.
+    void logUnderrunFrames(size_t count, size_t frames) {
+        std::lock_guard l(mLock);
+        mUnderrunCount = count;
+        mUnderrunFrames = frames;
+    }
+
+    const std::string& getMetricsId() const {
+        return mMetricsId;
+    }
+
+private:
+    // no lock required - all arguments and constants.
+    void deliverDeviceMetrics(const char *eventName, const char *devices) const {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+            .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
+                   : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
+           .record();
+    }
+
+    void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
+        if (mIntervalCount > 0) {
+            mediametrics::LogItem item(mMetricsId);
+            item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
+                .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
+                .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+                .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
+            if (mDeviceLatencyMs.getN() > 0) {
+                item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean());
+            }
+            if (mUnderrunCount > 0) {
+                item.set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t)mUnderrunCount)
+                    .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES, (int64_t)mUnderrunFrames);
+            }
+            item.record();
+        }
+    }
+
+    void resetIntervalGroupMetrics() REQUIRES(mLock) {
+        // mDevices is not reset by clear
+
+        mIntervalCount = 0;
+        mIntervalStartTimeNs = 0;
+        // mCumulativeTimeNs is not reset by clear.
+        mDeviceTimeNs = 0;
+
+        mDeviceLatencyMs.reset();
+
+        mUnderrunCount = 0;
+        mUnderrunFrames = 0;
+    }
+
+    const std::string mMetricsId;
+    const bool        mIsOut;  // if true, than a playback track, otherwise used for record.
+
+    mutable           std::mutex mLock;
+
+    // Devices in the interval group.
+    std::string       mDevices GUARDED_BY(mLock);
+    std::string       mCreatePatchDevices GUARDED_BY(mLock);
+
+    // Number of intervals and playing time
+    int32_t           mIntervalCount GUARDED_BY(mLock) = 0;
+    int64_t           mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
+    int64_t           mCumulativeTimeNs GUARDED_BY(mLock) = 0;
+    int64_t           mDeviceTimeNs GUARDED_BY(mLock) = 0;
+
+    // latency and startup for each interval.
+    audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
+
+    // underrun count and frames
+    int64_t           mUnderrunCount GUARDED_BY(mLock) = 0;
+    int64_t           mUnderrunFrames GUARDED_BY(mLock) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_THREADMETRICS_H
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 65cf96c..594baf8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -220,6 +220,9 @@
 {
     std::stringstream ss;
     for (size_t i = 0; i < patch->num_sinks; ++i) {
+        if (i > 0) {
+            ss << "|";
+        }
         ss << "(" << toString(patch->sinks[i].ext.device.type)
             << ", " << patch->sinks[i].ext.device.address << ")";
     }
@@ -230,6 +233,9 @@
 {
     std::stringstream ss;
     for (size_t i = 0; i < patch->num_sources; ++i) {
+        if (i > 0) {
+            ss << "|";
+        }
         ss << "(" << toString(patch->sources[i].ext.device.type)
             << ", " << patch->sources[i].ext.device.address << ")";
     }
@@ -486,11 +492,13 @@
 }
 
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        type_t type, bool systemReady)
+        type_t type, bool systemReady, bool isOut)
     :   Thread(false /*canCallJava*/),
         mType(type),
         mAudioFlinger(audioFlinger),
-        mMetricsId(std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(id)),
+        mThreadMetrics(std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(id),
+               isOut),
+        mIsOut(isOut),
         // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
         // are set by PlaybackThread::readOutputParameters_l() or
         // RecordThread::readInputParameters_l()
@@ -502,13 +510,7 @@
         mSystemReady(systemReady),
         mSignalPending(false)
 {
-    mediametrics::LogItem(mMetricsId)
-        .setPid(getpid())
-        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
-        .set(AMEDIAMETRICS_PROP_TYPE, threadTypeToString(type))
-        .set(AMEDIAMETRICS_PROP_THREADID, id)
-        .record();
-
+    mThreadMetrics.logConstructor(getpid(), threadTypeToString(type), id);
     memset(&mPatch, 0, sizeof(struct audio_patch));
 }
 
@@ -525,10 +527,6 @@
     }
 
     sendStatistics(true /* force */);
-
-    mediametrics::LogItem(mMetricsId)
-        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
-        .record();
 }
 
 status_t AudioFlinger::ThreadBase::readyToRun()
@@ -1686,6 +1684,7 @@
 #ifdef TEE_SINK
     track->dumpTee(-1 /* fd */, "_REMOVE");
 #endif
+    track->logEndInterval(); // log to MediaMetrics
     return index;
 }
 
@@ -1828,7 +1827,7 @@
                                              audio_io_handle_t id,
                                              type_t type,
                                              bool systemReady)
-    :   ThreadBase(audioFlinger, id, type, systemReady),
+    :   ThreadBase(audioFlinger, id, type, systemReady, true /* isOut */),
         mNormalFrameCount(0), mSinkBuffer(NULL),
         mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
         mMixerBuffer(NULL),
@@ -2553,6 +2552,7 @@
             chain->incActiveTrackCnt();
         }
 
+        track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics
         status = NO_ERROR;
     }
 
@@ -2876,7 +2876,7 @@
     }
 
     audio_output_flags_t flags = mOutput->flags;
-    mediametrics::LogItem item(mMetricsId);
+    mediametrics::LogItem item(mThreadMetrics.getMetricsId()); // TODO: method in ThreadMetrics?
     item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
         .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
         .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
@@ -3051,6 +3051,10 @@
 {
     if (!mMasterMute) {
         char value[PROPERTY_VALUE_MAX];
+        if (mOutDeviceTypeAddrs.empty()) {
+            ALOGD("ro.audio.silent is ignored since no output device is set");
+            return;
+        }
         if (isSingleDeviceType(outDeviceTypes(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
             ALOGD("ro.audio.silent will be ignored for threads on AUDIO_DEVICE_OUT_REMOTE_SUBMIX");
             return;
@@ -3130,7 +3134,10 @@
 
     mNumWrites++;
     mInWrite = false;
-    mStandby = false;
+    if (mStandby) {
+        mThreadMetrics.logBeginInterval();
+        mStandby = false;
+    }
     return bytesWritten;
 }
 
@@ -3669,8 +3676,9 @@
                     // This is where we go into standby
                     if (!mStandby) {
                         LOG_AUDIO_STATE();
+                        mThreadMetrics.logEndInterval();
+                        mStandby = true;
                     }
-                    mStandby = true;
                     sendStatistics(false /* force */);
                 }
 
@@ -3974,10 +3982,7 @@
 
                         const int32_t throttleMs = (int32_t)mHalfBufferMs - deltaMs;
                         if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
-                            mediametrics::LogItem(mMetricsId)
-                                // ms units always double
-                                .set(AMEDIAMETRICS_PROP_THROTTLEMS, (double)throttleMs)
-                                .record();
+                            mThreadMetrics.logThrottleMs((double)throttleMs);
 
                             usleep(throttleMs * 1000);
                             // notify of throttle start on verbose log
@@ -4227,6 +4232,7 @@
                          (mPatch.sinks[0].id != sinkPortId);
     mPatch = *patch;
     mOutDeviceTypeAddrs = deviceTypeAddrs;
+    checkSilentMode_l();
 
     if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -4251,10 +4257,16 @@
         status = mOutput->stream->setParameters(param.toString());
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
-    mediametrics::LogItem(mMetricsId)
-        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
-        .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, patchSinksToString(patch).c_str())
-        .record();
+    const std::string patchSinksAsString = patchSinksToString(patch);
+
+    mThreadMetrics.logEndInterval();
+    mThreadMetrics.logCreatePatch(patchSinksAsString);
+    mThreadMetrics.logBeginInterval();
+    // also dispatch to active AudioTracks for MediaMetrics
+    for (const auto &track : mActiveTracks) {
+        track->logEndInterval();
+        track->logBeginInterval(patchSinksAsString);
+    }
 
     if (configChanged) {
         sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
@@ -4797,9 +4809,8 @@
     // DeferredOperations handles statistics after setting mixerStatus.
     class DeferredOperations {
     public:
-        DeferredOperations(mixer_state *mixerStatus, const std::string &metricsId)
-            : mMixerStatus(mixerStatus)
-            , mMetricsId(metricsId) {}
+        explicit DeferredOperations(mixer_state *mixerStatus)
+            : mMixerStatus(mixerStatus) {}
 
         // when leaving scope, tally frames properly.
         ~DeferredOperations() {
@@ -4807,19 +4818,9 @@
             // because that is when the underrun occurs.
             // We do not distinguish between FastTracks and NormalTracks here.
             if (*mMixerStatus == MIXER_TRACKS_READY && mUnderrunFrames.size() > 0) {
-                mediametrics::LogItem item(mMetricsId);
-
-                item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN);
                 for (const auto &underrun : mUnderrunFrames) {
-                    underrun.first->mAudioTrackServerProxy->tallyUnderrunFrames(
-                            underrun.second);
-
-                    item.set(std::string("[" AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
-                            + std::to_string(underrun.first->portId())
-                            + "]" AMEDIAMETRICS_PROP_UNDERRUN,
-                            (int32_t)underrun.second);
+                    underrun.first->tallyUnderrunFrames(underrun.second);
                 }
-                item.record();
             }
         }
 
@@ -4832,9 +4833,8 @@
 
     private:
         const mixer_state * const mMixerStatus;
-        const std::string& mMetricsId;
         std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
-    } deferredOperations(&mixerStatus, mMetricsId);
+    } deferredOperations(&mixerStatus);
     // implicit nested scope for variable capture
 
     bool noFastHapticTrack = true;
@@ -5573,7 +5573,10 @@
         status = mOutput->stream->setParameters(keyValuePair);
         if (!mStandby && status == INVALID_OPERATION) {
             mOutput->standby();
-            mStandby = true;
+            if (!mStandby) {
+                mThreadMetrics.logEndInterval();
+                mStandby = true;
+            }
             mBytesWritten = 0;
             status = mOutput->stream->setParameters(keyValuePair);
         }
@@ -6086,7 +6089,10 @@
         status = mOutput->stream->setParameters(keyValuePair);
         if (!mStandby && status == INVALID_OPERATION) {
             mOutput->standby();
-            mStandby = true;
+            if (!mStandby) {
+                mThreadMetrics.logEndInterval();
+                mStandby = true;
+            }
             mBytesWritten = 0;
             status = mOutput->stream->setParameters(keyValuePair);
         }
@@ -6681,7 +6687,10 @@
 
         // TODO: Report correction for the other output tracks and show in the dump.
     }
-    mStandby = false;
+    if (mStandby) {
+        mThreadMetrics.logBeginInterval();
+        mStandby = false;
+    }
     return (ssize_t)mSinkBufferSize;
 }
 
@@ -6843,7 +6852,7 @@
                                          audio_io_handle_t id,
                                          bool systemReady
                                          ) :
-    ThreadBase(audioFlinger, id, RECORD, systemReady),
+    ThreadBase(audioFlinger, id, RECORD, systemReady, false /* isOut */),
     mInput(input),
     mSource(mInput),
     mActiveTracks(&this->mLocalLog),
@@ -7131,7 +7140,10 @@
 
                 case TrackBase::STARTING_2:
                     doBroadcast = true;
-                    mStandby = false;
+                    if (mStandby) {
+                        mThreadMetrics.logBeginInterval();
+                        mStandby = false;
+                    }
                     activeTrack->mState = TrackBase::ACTIVE;
                     allStopped = false;
                     break;
@@ -7572,6 +7584,7 @@
 {
     if (!mStandby) {
         inputStandBy();
+        mThreadMetrics.logEndInterval();
         mStandby = true;
     }
 }
@@ -7876,6 +7889,9 @@
             sendIoConfigEvent_l(
                 AUDIO_CLIENT_STARTED, recordTrack->creatorPid(), recordTrack->portId());
         }
+
+        recordTrack->logBeginInterval(patchSourcesToString(&mPatch)); // log to MediaMetrics
+
         // Catch up with current buffer indices if thread is already running.
         // This is what makes a new client discard all buffered data.  If the track's mRsmpInFront
         // was initialized to some value closer to the thread's mRsmpInFront, then the track could
@@ -8540,12 +8556,15 @@
         mPatch = *patch;
     }
 
-    mediametrics::LogItem(mMetricsId)
-        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
-        .set(AMEDIAMETRICS_PROP_INPUTDEVICES, patchSourcesToString(patch).c_str())
-        .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAudioSource).c_str())
-        .record();
-
+    const std::string pathSourcesAsString = patchSourcesToString(patch);
+    mThreadMetrics.logEndInterval();
+    mThreadMetrics.logCreatePatch(pathSourcesAsString);
+    mThreadMetrics.logBeginInterval();
+    // also dispatch to active AudioRecords
+    for (const auto &track : mActiveTracks) {
+        track->logEndInterval();
+        track->logBeginInterval(pathSourcesAsString);
+    }
     return status;
 }
 
@@ -8633,10 +8652,10 @@
 }
 
 status_t AudioFlinger::MmapThreadHandle::start(const AudioClient& client,
-        audio_port_handle_t *handle)
+        const audio_attributes_t *attr, audio_port_handle_t *handle)
 
 {
-    return mThread->start(client, handle);
+    return mThread->start(client, attr, handle);
 }
 
 status_t AudioFlinger::MmapThreadHandle::stop(audio_port_handle_t handle)
@@ -8652,8 +8671,8 @@
 
 AudioFlinger::MmapThread::MmapThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady)
-    : ThreadBase(audioFlinger, id, MMAP, systemReady),
+        AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady, bool isOut)
+    : ThreadBase(audioFlinger, id, MMAP, systemReady, isOut),
       mSessionId(AUDIO_SESSION_NONE),
       mPortId(AUDIO_PORT_HANDLE_NONE),
       mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
@@ -8736,11 +8755,15 @@
         ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret);
         return ret;
     }
-    mStandby = false;
+    if (mStandby) {
+        mThreadMetrics.logBeginInterval();
+        mStandby = false;
+    }
     return NO_ERROR;
 }
 
 status_t AudioFlinger::MmapThread::start(const AudioClient& client,
+                                         const audio_attributes_t *attr,
                                          audio_port_handle_t *handle)
 {
     ALOGV("%s clientUid %d mStandby %d mPortId %d *handle %d", __FUNCTION__,
@@ -8774,7 +8797,6 @@
                                             &stream,
                                             client.clientPid,
                                             client.clientUid,
-                                            client.packageName,
                                             &config,
                                             flags,
                                             &deviceId,
@@ -8832,9 +8854,10 @@
     }
 
     // Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
-    sp<MmapTrack> track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId,
-                                        isOutput(), client.clientUid, client.clientPid,
-                                        IPCThreadState::self()->getCallingPid(), portId);
+    sp<MmapTrack> track = new MmapTrack(this, attr == nullptr ? mAttr : *attr, mSampleRate, mFormat,
+                                        mChannelMask, mSessionId, isOutput(), client.clientUid,
+                                        client.clientPid, IPCThreadState::self()->getCallingPid(),
+                                        portId);
 
     if (isOutput()) {
         // force volume update when a new track is added
@@ -8855,6 +8878,7 @@
         chain->incActiveTrackCnt();
     }
 
+    track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics
     *handle = portId;
     broadcast_l();
 
@@ -8923,7 +8947,10 @@
         return INVALID_OPERATION;
     }
     mHalStream->standby();
-    mStandby = true;
+    if (!mStandby) {
+        mThreadMetrics.logEndInterval();
+        mStandby = true;
+    }
     releaseWakeLock();
     return NO_ERROR;
 }
@@ -8940,6 +8967,27 @@
     result = mHalStream->getBufferSize(&mBufferSize);
     LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
     mFrameCount = mBufferSize / mFrameSize;
+
+    // TODO: make a readHalParameters call?
+    mediametrics::LogItem item(mThreadMetrics.getMetricsId());
+    item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
+        .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+        .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+        .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
+        .set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)mChannelCount)
+        .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
+        /*
+        .set(AMEDIAMETRICS_PROP_FLAGS, toString(flags).c_str())
+        .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELMASK,
+                (int32_t)mHapticChannelMask)
+        .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELCOUNT,
+                (int32_t)mHapticChannelCount)
+        */
+        .set(AMEDIAMETRICS_PROP_PREFIX_HAL    AMEDIAMETRICS_PROP_ENCODING,
+                formatToString(mHALFormat).c_str())
+        .set(AMEDIAMETRICS_PROP_PREFIX_HAL    AMEDIAMETRICS_PROP_FRAMECOUNT,
+                (int32_t)mFrameCount) // sic - added HAL
+        .record();
 }
 
 bool AudioFlinger::MmapThread::threadLoop()
@@ -9152,6 +9200,7 @@
         if (isOutput()) {
             sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
             mOutDeviceTypeAddrs = sinkDeviceTypeAddrs;
+            checkSilentMode_l();
         } else {
             sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
             mInDeviceTypeAddr = sourceDeviceTypeAddr;
@@ -9350,7 +9399,7 @@
 AudioFlinger::MmapPlaybackThread::MmapPlaybackThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
         AudioHwDevice *hwDev,  AudioStreamOut *output, bool systemReady)
-    : MmapThread(audioFlinger, id, hwDev, output->stream, systemReady),
+    : MmapThread(audioFlinger, id, hwDev, output->stream, systemReady, true /* isOut */),
       mStreamType(AUDIO_STREAM_MUSIC),
       mStreamVolume(1.0),
       mStreamMute(false),
@@ -9561,7 +9610,7 @@
 AudioFlinger::MmapCaptureThread::MmapCaptureThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
         AudioHwDevice *hwDev,  AudioStreamIn *input, bool systemReady)
-    : MmapThread(audioFlinger, id, hwDev, input->stream, systemReady),
+    : MmapThread(audioFlinger, id, hwDev, input->stream, systemReady, false /* isOut */),
       mInput(input)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8149e95..5b8c081 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -37,7 +37,7 @@
     static const char *threadTypeToString(type_t type);
 
     ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-               type_t type, bool systemReady);
+               type_t type, bool systemReady, bool isOut);
     virtual             ~ThreadBase();
 
     virtual status_t    readyToRun();
@@ -330,7 +330,7 @@
                     return mInDeviceTypeAddr;
                 }
 
-    virtual     bool        isOutput() const = 0;
+                bool        isOutput() const { return mIsOut; }
 
     virtual     sp<StreamHalInterface> stream() const = 0;
 
@@ -524,7 +524,8 @@
                 Condition               mWaitWorkCV;
 
                 const sp<AudioFlinger>  mAudioFlinger;
-                const std::string       mMetricsId;
+                ThreadMetrics           mThreadMetrics;
+                const bool              mIsOut;
 
                 // updated by PlaybackThread::readOutputParameters_l() or
                 // RecordThread::readInputParameters_l()
@@ -911,9 +912,6 @@
 
                 // Return the asynchronous signal wait time.
     virtual     int64_t     computeWaitTimeNs_l() const { return INT64_MAX; }
-
-    virtual     bool        isOutput() const override { return true; }
-
                 // returns true if the track is allowed to be added to the thread.
     virtual     bool        isTrackAllowed_l(
                                     audio_channel_mask_t channelMask __unused,
@@ -1651,7 +1649,6 @@
                             ThreadBase::acquireWakeLock_l();
                             mActiveTracks.updatePowerState(this, true /* force */);
                         }
-    virtual bool        isOutput() const override { return false; }
 
             void        checkBtNrec();
 
@@ -1760,7 +1757,8 @@
 #include "MmapTracks.h"
 
     MmapThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-               AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady);
+               AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady,
+               bool isOut);
     virtual     ~MmapThread();
 
     virtual     void        configure(const audio_attributes_t *attr,
@@ -1776,7 +1774,9 @@
     status_t createMmapBuffer(int32_t minSizeFrames,
                                       struct audio_mmap_buffer_info *info);
     status_t getMmapPosition(struct audio_mmap_position *position);
-    status_t start(const AudioClient& client, audio_port_handle_t *handle);
+    status_t start(const AudioClient& client,
+                   const audio_attributes_t *attr,
+                   audio_port_handle_t *handle);
     status_t stop(audio_port_handle_t handle);
     status_t standby();
 
@@ -1886,8 +1886,6 @@
     virtual     void        checkSilentMode_l();
                 void        processVolume_l() override;
 
-    virtual     bool        isOutput() const override { return true; }
-
                 void        updateMetadata_l() override;
 
     virtual     void        toAudioPortConfig(struct audio_port_config *config);
@@ -1914,7 +1912,6 @@
                 AudioStreamIn* clearInput();
 
                 status_t       exitStandby() override;
-    virtual     bool           isOutput() const override { return false; }
 
                 void           updateMetadata_l() override;
                 void           processVolume_l() override;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index e39b944..15c66fb 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -97,10 +97,7 @@
 
     virtual void        invalidate() {
                             if (mIsInvalid) return;
-                            mediametrics::LogItem(mMetricsId)
-                                .set(AMEDIAMETRICS_PROP_EVENT,
-                                     AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
-                                .record();
+                            mTrackMetrics.logInvalidate();
                             mIsInvalid = true;
                         }
             bool        isInvalid() const { return mIsInvalid; }
@@ -242,6 +239,20 @@
         }
     }
 
+    // Called by the PlaybackThread to indicate that the track is becoming active
+    // and a new interval should start with a given device list.
+    void logBeginInterval(const std::string& devices) {
+        mTrackMetrics.logBeginInterval(devices);
+    }
+
+    // Called by the PlaybackThread to indicate the track is no longer active.
+    void logEndInterval() {
+        mTrackMetrics.logEndInterval();
+    }
+
+    // Called to tally underrun frames in playback.
+    virtual void tallyUnderrunFrames(size_t /* frames */) {}
+
 protected:
     DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
@@ -367,7 +378,7 @@
     int64_t             mLogStartTimeNs = 0;
     int64_t             mLogStartFrames = 0;
 
-    const std::string   mMetricsId;
+    TrackMetrics        mTrackMetrics;
 
     bool                mServerLatencySupported = false;
     std::atomic<bool>   mServerLatencyFromTrack{}; // latency from track or server timestamp.
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
new file mode 100644
index 0000000..399c788
--- /dev/null
+++ b/services/audioflinger/TrackMetrics.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIO_TRACKMETRICS_H
+#define ANDROID_AUDIO_TRACKMETRICS_H
+
+#include <mutex>
+
+namespace android {
+
+/**
+ * TrackMetrics handles the AudioFlinger track metrics.
+ *
+ * We aggregate metrics for a particular device for proper analysis.
+ * This includes power, performance, and usage metrics.
+ *
+ * This class is thread-safe with a lock for safety.  There is no risk of deadlock
+ * as this class only executes external one-way calls in Mediametrics and does not
+ * call any other AudioFlinger class.
+ *
+ * Terminology:
+ * An AudioInterval is a contiguous playback segment.
+ * An AudioIntervalGroup is a group of continuous playback segments on the same device.
+ *
+ * We currently deliver metrics based on an AudioIntervalGroup.
+ */
+class TrackMetrics final {
+public:
+    TrackMetrics(std::string metricsId, bool isOut)
+        : mMetricsId(std::move(metricsId))
+        , mIsOut(isOut)
+        {}  // we don't log a constructor item, we wait for more info in logConstructor().
+
+    ~TrackMetrics() {
+        logEndInterval();
+        std::lock_guard l(mLock);
+        deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+        // we don't log a destructor item here.
+    }
+
+    // Called under the following circumstances
+    // 1) when we are added to the Thread
+    // 2) when we have a createPatch in the Thread.
+    void logBeginInterval(const std::string& devices) {
+        std::lock_guard l(mLock);
+        if (mDevices != devices) {
+            deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+            mDevices = devices;
+            resetIntervalGroupMetrics();
+            deliverDeviceMetrics(
+                    AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, devices.c_str());
+        }
+        ++mIntervalCount;
+        mIntervalStartTimeNs = systemTime();
+    }
+
+    void logConstructor(pid_t creatorPid, uid_t creatorUid) const {
+        // Once this item is logged by the server, the client can add properties.
+        // no lock required, all local or const variables.
+        mediametrics::LogItem(mMetricsId)
+            .setPid(creatorPid)
+            .setUid(creatorUid)
+            .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)creatorUid)
+            .set(AMEDIAMETRICS_PROP_EVENT,
+                    AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+            .record();
+    }
+
+    // Called when we are removed from the Thread.
+    void logEndInterval() {
+        std::lock_guard l(mLock);
+        if (mIntervalStartTimeNs != 0) {
+            const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
+            mIntervalStartTimeNs = 0;
+            mCumulativeTimeNs += elapsedTimeNs;
+            mDeviceTimeNs += elapsedTimeNs;
+        }
+    }
+
+    void logInvalidate() const {
+        // no lock required, all local or const variables.
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT,
+                 AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
+            .record();
+    }
+
+    void logLatencyAndStartup(double latencyMs, double startupMs) {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
+            .set(AMEDIAMETRICS_PROP_STARTUPMS, startupMs)
+            .record();
+        std::lock_guard l(mLock);
+        mDeviceLatencyMs.add(latencyMs);
+        mDeviceStartupMs.add(startupMs);
+    }
+
+    // may be called multiple times during an interval
+    void logVolume(float volume) {
+        const int64_t timeNs = systemTime();
+        std::lock_guard l(mLock);
+        if (mStartVolumeTimeNs == 0) {
+            mDeviceVolume = mVolume = volume;
+            mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
+            return;
+        }
+        mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
+            mVolume * (timeNs - mLastVolumeChangeTimeNs)) / (timeNs - mStartVolumeTimeNs);
+        mVolume = volume;
+        mLastVolumeChangeTimeNs = timeNs;
+    }
+
+    // Use absolute numbers returned by AudioTrackShared.
+    void logUnderruns(size_t count, size_t frames) {
+        std::lock_guard l(mLock);
+        mUnderrunCount = count;
+        mUnderrunFrames = frames;
+        // Consider delivering a message here (also be aware of excessive spam).
+    }
+
+private:
+    // no lock required - all arguments and constants.
+    void deliverDeviceMetrics(const char *eventName, const char *devices) const {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+            .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
+                   : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
+           .record();
+    }
+
+    void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
+        if (mIntervalCount > 0) {
+            mediametrics::LogItem item(mMetricsId);
+            item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
+                .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
+                .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+                .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
+            if (mIsOut) {
+                item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume);
+            }
+            if (mDeviceLatencyMs.getN() > 0) {
+                item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
+                    .set(AMEDIAMETRICS_PROP_DEVICESTARTUPMS, mDeviceStartupMs.getMean());
+            }
+            if (mUnderrunCount > 0) {
+                item.set(AMEDIAMETRICS_PROP_UNDERRUN,
+                        (int32_t)(mUnderrunCount - mUnderrunCountSinceIntervalGroup))
+                    .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES,
+                        (int64_t)(mUnderrunFrames - mUnderrunFramesSinceIntervalGroup));
+            }
+            item.record();
+        }
+    }
+
+    void resetIntervalGroupMetrics() REQUIRES(mLock) {
+        // mDevices is not reset by resetIntervalGroupMetrics.
+
+        mIntervalCount = 0;
+        mIntervalStartTimeNs = 0;
+        // mCumulativeTimeNs is not reset by resetIntervalGroupMetrics.
+        mDeviceTimeNs = 0;
+
+        mVolume = 0.f;
+        mDeviceVolume = 0.f;
+        mStartVolumeTimeNs = 0;
+        mLastVolumeChangeTimeNs = 0;
+
+        mDeviceLatencyMs.reset();
+        mDeviceStartupMs.reset();
+
+        mUnderrunCountSinceIntervalGroup = mUnderrunCount;
+        mUnderrunFramesSinceIntervalGroup = mUnderrunFrames;
+        // do not reset mUnderrunCount - it keeps continuously running for tracks.
+    }
+
+    const std::string mMetricsId;
+    const bool        mIsOut;  // if true, than a playback track, otherwise used for record.
+
+    mutable           std::mutex mLock;
+
+    // Devices in the interval group.
+    std::string       mDevices GUARDED_BY(mLock);
+
+    // Number of intervals and playing time
+    int32_t           mIntervalCount GUARDED_BY(mLock) = 0;
+    int64_t           mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
+    int64_t           mCumulativeTimeNs GUARDED_BY(mLock) = 0;
+    int64_t           mDeviceTimeNs GUARDED_BY(mLock) = 0;
+
+    // Average volume
+    double            mVolume GUARDED_BY(mLock) = 0.f;
+    double            mDeviceVolume GUARDED_BY(mLock) = 0.f;
+    int64_t           mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
+    int64_t           mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
+
+    // latency and startup for each interval.
+    audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
+    audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
+
+    // underrun count and frames
+    int64_t           mUnderrunCount GUARDED_BY(mLock) = 0;
+    int64_t           mUnderrunFrames GUARDED_BY(mLock) = 0;
+    int64_t           mUnderrunCountSinceIntervalGroup GUARDED_BY(mLock) = 0;
+    int64_t           mUnderrunFramesSinceIntervalGroup GUARDED_BY(mLock) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_TRACKMETRICS_H
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 23d8329..58c61c9 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -106,7 +106,7 @@
         mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
         mPortId(portId),
         mIsInvalid(false),
-        mMetricsId(std::move(metricsId)),
+        mTrackMetrics(std::move(metricsId), isOut),
         mCreatorPid(creatorPid)
 {
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -602,12 +602,7 @@
     }
 
     // Once this item is logged by the server, the client can add properties.
-    mediametrics::LogItem(mMetricsId)
-        .setPid(creatorPid)
-        .setUid(uid)
-        .set(AMEDIAMETRICS_PROP_EVENT,
-                AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
-        .record();
+    mTrackMetrics.logConstructor(creatorPid, uid);
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
@@ -1248,6 +1243,7 @@
     if (mFinalVolume != volume) { // Compare to an epsilon if too many meaningless updates
         mFinalVolume = volume;
         setMetadataHasChanged();
+        mTrackMetrics.logVolume(volume);
     }
 }
 
@@ -1533,10 +1529,7 @@
                     (long long)mLogStartTimeNs,
                     (long long)local.mPosition[ExtendedTimestamp::LOCATION_SERVER],
                     (long long)mLogStartFrames);
-            mediametrics::LogItem(mMetricsId)
-                .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
-                .set(AMEDIAMETRICS_PROP_STARTUPMS, startUpMs)
-                .record();
+            mTrackMetrics.logLatencyAndStartup(latencyMs, startUpMs);
         }
     }
 }
@@ -2162,11 +2155,7 @@
 #endif
 
     // Once this item is logged by the server, the client can add properties.
-    mediametrics::LogItem(mMetricsId)
-        .setPid(creatorPid)
-        .setUid(uid)
-        .set(AMEDIAMETRICS_PROP_EVENT, "server." AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
-        .record();
+    mTrackMetrics.logConstructor(creatorPid, uid);
 }
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
@@ -2723,9 +2712,12 @@
                   nullptr /* buffer */, (size_t)0 /* bufferSize */,
                   sessionId, creatorPid, uid, isOut,
                   ALLOC_NONE,
-                  TYPE_DEFAULT, portId),
+                  TYPE_DEFAULT, portId,
+                  std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
         mPid(pid), mSilenced(false), mSilencedNotified(false)
 {
+    // Once this item is logged by the server, the client can add properties.
+    mTrackMetrics.logConstructor(creatorPid, uid);
 }
 
 AudioFlinger::MmapThread::MmapTrack::~MmapTrack()
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
index 6e29632..6167f95 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioIODescriptorInterface.h
@@ -34,6 +34,8 @@
     virtual audio_patch_handle_t getPatchHandle() const = 0;
 
     virtual void setPatchHandle(audio_patch_handle_t handle) = 0;
+
+    virtual bool isMmap() = 0;
 };
 
 template <class IoDescriptor, class Filter>
@@ -41,11 +43,24 @@
         IoDescriptor& desc, Filter filter, bool& active, const DeviceVector& devices)
 {
     auto activeClients = desc->clientsList(true /*activeOnly*/);
-    auto activeClientsWithRoute =
-        desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
     active = activeClients.size() > 0;
-    if (active && activeClients.size() == activeClientsWithRoute.size()) {
-        return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
+
+    if (active) {
+        // On MMAP IOs, the preferred device is selected by the first client (virtual client
+        // created when the mmap stream is opened). This client is never active.
+        // On non MMAP IOs, the preferred device is honored only if all active clients have
+        // a preferred device in which case the first client drives the selection.
+        if (desc->isMmap()) {
+            // The client list is never empty on a MMAP IO
+            return devices.getDeviceFromId(
+                    desc->clientsList(false /*activeOnly*/)[0]->preferredDeviceId());
+        } else {
+            auto activeClientsWithRoute =
+                desc->clientsList(true /*activeOnly*/, filter, true /*preferredDevice*/);
+            if (activeClients.size() == activeClientsWithRoute.size()) {
+                return devices.getDeviceFromId(activeClientsWithRoute[0]->preferredDeviceId());
+            }
+        }
     }
     return nullptr;
 }
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index c67a006..6f47abc 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -92,6 +92,12 @@
     audio_config_base_t getConfig() const override;
     audio_patch_handle_t getPatchHandle() const override;
     void setPatchHandle(audio_patch_handle_t handle) override;
+    bool isMmap() override {
+        if (getPolicyAudioPort() != nullptr) {
+            return getPolicyAudioPort()->isMmap();
+        }
+        return false;
+    }
 
     status_t open(const audio_config_t *config,
                   const sp<DeviceDescriptor> &device,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 41f7dfc..39d1140 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -268,6 +268,12 @@
     audio_config_base_t getConfig() const override;
     audio_patch_handle_t getPatchHandle() const override;
     void setPatchHandle(audio_patch_handle_t handle) override;
+    bool isMmap() override {
+        if (getPolicyAudioPort() != nullptr) {
+            return getPolicyAudioPort()->isMmap();
+        }
+        return false;
+    }
 
     TrackClientVector clientsList(bool activeOnly = false,
                                   product_strategy_t strategy = PRODUCT_STRATEGY_NONE,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index a757551..b82305d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -72,8 +72,8 @@
      */
     status_t getOutputForAttr(const audio_attributes_t& attributes, uid_t uid,
                               audio_output_flags_t flags,
-                              sp<SwAudioOutputDescriptor> &primaryDesc,
-                              std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
+                              sp<AudioPolicyMix> &primaryMix,
+                              std::vector<sp<AudioPolicyMix>> *secondaryMixes);
 
     sp<DeviceDescriptor> getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                        const DeviceVector &availableDeviceTypes,
diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
index 99df3c0..d2f6297 100644
--- a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
@@ -107,6 +107,15 @@
                 (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
     }
 
+    inline bool isMmap() const
+    {
+        return (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX)
+                && (((asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE) &&
+                        ((mFlags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0))
+                    || ((asAudioPort()->getRole() == AUDIO_PORT_ROLE_SINK) &&
+                        ((mFlags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)));
+    }
+
     void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
     const AudioRouteVector &getRoutes() const { return mRoutes; }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index aaa28bc..d5272bc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -152,10 +152,16 @@
 bool AudioOutputDescriptor::setVolume(float volumeDb,
                                       VolumeSource volumeSource,
                                       const StreamTypeVector &/*streams*/,
-                                      const DeviceTypeSet& /*deviceTypes*/,
+                                      const DeviceTypeSet& deviceTypes,
                                       uint32_t delayMs,
                                       bool force)
 {
+
+    if (!supportedDevices().containsDeviceAmongTypes(deviceTypes)) {
+        ALOGV("%s output ID %d unsupported device %s",
+                __func__, getId(), toString(deviceTypes).c_str());
+        return false;
+    }
     // We actually change the volume if:
     // - the float value returned by computeVolume() changed
     // - the force flag is set
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index ed51389..fc1a59f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -150,11 +150,11 @@
 status_t AudioPolicyMixCollection::getOutputForAttr(
         const audio_attributes_t& attributes, uid_t uid,
         audio_output_flags_t flags,
-        sp<SwAudioOutputDescriptor> &primaryDesc,
-        std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
+        sp<AudioPolicyMix> &primaryMix,
+        std::vector<sp<AudioPolicyMix>> *secondaryMixes)
 {
     ALOGV("getOutputForAttr() querying %zu mixes:", size());
-    primaryDesc = 0;
+    primaryMix.clear();
     for (size_t i = 0; i < size(); i++) {
         sp<AudioPolicyMix> policyMix = itemAt(i);
         const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
@@ -169,13 +169,7 @@
             return INVALID_OPERATION;
         }
 
-        sp<SwAudioOutputDescriptor> policyDesc = policyMix->getOutput();
-        if (!policyDesc) {
-            ALOGV("%s: Skiping %zu: Mix has no output", __func__, i);
-            continue;
-        }
-
-        if (primaryOutputMix && primaryDesc != 0) {
+        if (primaryOutputMix && primaryMix != nullptr) {
             ALOGV("%s: Skiping %zu: Primary output already found", __func__, i);
             continue; // Primary output already found
         }
@@ -191,18 +185,13 @@
             case MixMatchStatus::MATCH:;
         }
 
-        policyDesc->mPolicyMix = policyMix;
         if (primaryOutputMix) {
-            primaryDesc = policyDesc;
+            primaryMix = policyMix;
             ALOGV("%s: Mix %zu: set primary desc", __func__, i);
         } else {
-            if (policyDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) {
-                ALOGV("%s: Mix %zu ignored as secondaryOutput because not opened yet", __func__, i);
-            } else {
-                ALOGV("%s: Add a secondary desc %zu", __func__, i);
-                if (secondaryDescs != nullptr) {
-                    secondaryDescs->push_back(policyDesc);
-                }
+            ALOGV("%s: Add a secondary desc %zu", __func__, i);
+            if (secondaryMixes != nullptr) {
+                secondaryMixes->push_back(policyMix);
             }
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 886e4c9..d31e443 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -320,7 +320,7 @@
 {
     String8 devAddress = (address == nullptr || !matchAddress) ? String8("") : String8(address);
     // handle legacy remote submix case where the address was not always specified
-    if (device_distinguishes_on_address(deviceType) && (devAddress.length() == 0)) {
+    if (audio_is_remote_submix_device(deviceType) && (devAddress.length() == 0)) {
         devAddress = String8("0");
     }
 
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index fe15ff6..151c7bb 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -73,10 +73,18 @@
 audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(
         const audio_attributes_t &attr) const
 {
-    const auto iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
+    const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
                                    [&attr](const auto &supportedAttr) {
         return AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr); });
-    return iter != end(mAttributesVector) ? iter->mStream : AUDIO_STREAM_DEFAULT;
+    if (iter == end(mAttributesVector)) {
+        return AUDIO_STREAM_DEFAULT;
+    }
+    audio_stream_type_t streamType = iter->mStream;
+    ALOGW_IF(streamType == AUDIO_STREAM_DEFAULT,
+             "%s: Strategy %s supporting attributes %s has not stream type associated"
+             "fallback on MUSIC. Do not use stream volume API", __func__, mName.c_str(),
+             toString(attr).c_str());
+    return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
 }
 
 audio_attributes_t ProductStrategy::getAttributesForStreamType(audio_stream_type_t streamType) const
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index 7f5ed5e..5d22c24 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -31,9 +31,6 @@
 /** Default path of audio policy usages configuration file. */
 constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_policy_engine_configuration.xml";
 
-/** Directories where the effect libraries will be search for. */
-constexpr const char* POLICY_USAGE_LIBRARY_PATH[] = {"/odm/etc/", "/vendor/etc/", "/system/etc/"};
-
 using AttributesVector = std::vector<audio_attributes_t>;
 using StreamVector = std::vector<audio_stream_type_t>;
 
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 7f8cdd9..4842cb2 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -21,6 +21,7 @@
 #include <cutils/properties.h>
 #include <media/TypeConverter.h>
 #include <media/convert.h>
+#include <system/audio_config.h>
 #include <utils/Log.h>
 #include <libxml/parser.h>
 #include <libxml/xinclude.h>
@@ -693,9 +694,6 @@
     return deserializeLegacyVolumeCollection(doc, cur, volumeGroups, nbSkippedElements);
 }
 
-static const char *kConfigLocationList[] = {"/odm/etc", "/vendor/etc", "/system/etc"};
-static const int kConfigLocationListSize =
-        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
 static const int gApmXmlConfigFilePathMaxLength = 128;
 
 static constexpr const char *apmXmlConfigFileName = "audio_policy_configuration.xml";
@@ -715,9 +713,9 @@
     fileNames.push_back(apmXmlConfigFileName);
 
     for (const char* fileName : fileNames) {
-        for (int i = 0; i < kConfigLocationListSize; i++) {
+        for (const auto& path : audio_get_configuration_paths()) {
             snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
-                     "%s/%s", kConfigLocationList[i], fileName);
+                     "%s/%s", path.c_str(), fileName);
             ret = parseLegacyVolumeFile(audioPolicyXmlConfigFile, volumeGroups);
             if (ret == NO_ERROR) {
                 return ret;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ffc3a0f..bcf6f38 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -47,6 +47,7 @@
 #include <media/AudioParameter.h>
 #include <private/android_filesystem_config.h>
 #include <system/audio.h>
+#include <system/audio_config.h>
 #include "AudioPolicyManager.h"
 #include <Serializer.h>
 #include "TypeConverter.h"
@@ -133,12 +134,14 @@
     sp<DeviceDescriptor> device =
             mHwModules.getDeviceDescriptor(deviceType, device_address, device_name, encodedFormat,
                                            state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
-    if (device == 0) {
-        return INVALID_OPERATION;
-    }
+    return device ? setDeviceConnectionStateInt(device, state) : INVALID_OPERATION;
+}
 
+status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescriptor> &device,
+                                                         audio_policy_dev_state_t state)
+{
     // handle output devices
-    if (audio_is_output_device(deviceType)) {
+    if (audio_is_output_device(device->type())) {
         SortedVector <audio_io_handle_t> outputs;
 
         ssize_t index = mAvailableOutputDevices.indexOf(device);
@@ -155,7 +158,7 @@
                 return INVALID_OPERATION;
             }
             ALOGV("%s() connecting device %s format %x",
-                    __func__, device->toString().c_str(), encodedFormat);
+                    __func__, device->toString().c_str(), device->getEncodedFormat());
 
             // register new device as available
             if (mAvailableOutputDevices.add(device) < 0) {
@@ -217,16 +220,13 @@
         // output device used by a dynamic policy of type recorder as no
         // playback use case is affected.
         bool doCheckForDeviceAndOutputChanges = true;
-        if (device->type() == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
-                && strncmp(device_address, "0", AUDIO_DEVICE_MAX_ADDRESS_LEN) != 0) {
+        if (device->type() == AUDIO_DEVICE_OUT_REMOTE_SUBMIX && device->address() != "0") {
             for (audio_io_handle_t output : outputs) {
                 sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
                 sp<AudioPolicyMix> policyMix = desc->mPolicyMix.promote();
                 if (policyMix != nullptr
                         && policyMix->mMixType == MIX_TYPE_RECORDERS
-                        && strncmp(device_address,
-                                   policyMix->mDeviceAddress.string(),
-                                   AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0) {
+                        && device->address() == policyMix->mDeviceAddress.string()) {
                     doCheckForDeviceAndOutputChanges = false;
                     break;
                 }
@@ -272,7 +272,7 @@
                 // a valid device selection on those outputs.
                 bool force = (msdOutDevices.isEmpty() || msdOutDevices != desc->devices())
                         && !desc->isDuplicated()
-                        && (!device_distinguishes_on_address(deviceType)
+                        && (!device_distinguishes_on_address(device->type())
                                 // always force when disconnecting (a non-duplicated device)
                                 || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
                 setOutputDevices(desc, newDevices, force, 0);
@@ -288,7 +288,7 @@
     }  // end if is output device
 
     // handle input devices
-    if (audio_is_input_device(deviceType)) {
+    if (audio_is_input_device(device->type())) {
         ssize_t index = mAvailableInputDevices.indexOf(device);
         switch (state)
         {
@@ -907,7 +907,7 @@
         audio_output_flags_t *flags,
         audio_port_handle_t *selectedDeviceId,
         bool *isRequestedDeviceForExclusiveUse,
-        std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+        std::vector<sp<AudioPolicyMix>> *secondaryMixes,
         output_type_t *outputType)
 {
     DeviceVector outputDevices;
@@ -932,29 +932,45 @@
     // The primary output is the explicit routing (eg. setPreferredDevice) if specified,
     //       otherwise, fallback to the dynamic policies, if none match, query the engine.
     // Secondary outputs are always found by dynamic policies as the engine do not support them
-    sp<SwAudioOutputDescriptor> policyDesc;
-    status = mPolicyMixes.getOutputForAttr(*resultAttr, uid, *flags, policyDesc, secondaryDescs);
+    sp<AudioPolicyMix> primaryMix;
+    status = mPolicyMixes.getOutputForAttr(*resultAttr, uid, *flags, primaryMix, secondaryMixes);
     if (status != OK) {
         return status;
     }
 
     // Explicit routing is higher priority then any dynamic policy primary output
-    bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && policyDesc != nullptr;
+    bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && primaryMix != nullptr;
 
     // FIXME: in case of RENDER policy, the output capabilities should be checked
-    if ((usePrimaryOutputFromPolicyMixes || !secondaryDescs->empty())
+    if ((usePrimaryOutputFromPolicyMixes
+            || (secondaryMixes != nullptr && !secondaryMixes->empty()))
         && !audio_is_linear_pcm(config->format)) {
         ALOGD("%s: rejecting request as dynamic audio policy only support pcm", __func__);
         return BAD_VALUE;
     }
     if (usePrimaryOutputFromPolicyMixes) {
-        *output = policyDesc->mIoHandle;
-        sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
-        if (mix != nullptr) {
-            sp<DeviceDescriptor> deviceDesc =
-                    mAvailableOutputDevices.getDevice(mix->mDeviceType,
-                                                      mix->mDeviceAddress,
-                                                      AUDIO_FORMAT_DEFAULT);
+        sp<DeviceDescriptor> deviceDesc =
+                mAvailableOutputDevices.getDevice(primaryMix->mDeviceType,
+                                                  primaryMix->mDeviceAddress,
+                                                  AUDIO_FORMAT_DEFAULT);
+        sp<SwAudioOutputDescriptor> policyDesc = primaryMix->getOutput();
+        if (deviceDesc != nullptr
+                && (policyDesc == nullptr || (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT))) {
+            audio_io_handle_t newOutput;
+            status = openDirectOutput(
+                    *stream, session, config,
+                    (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT),
+                    DeviceVector(deviceDesc), &newOutput);
+            if (status != NO_ERROR) {
+                policyDesc = nullptr;
+            } else {
+                policyDesc = mOutputs.valueFor(newOutput);
+                primaryMix->setOutput(policyDesc);
+            }
+        }
+        if (policyDesc != nullptr) {
+            policyDesc->mPolicyMix = primaryMix;
+            *output = policyDesc->mIoHandle;
             *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
 
             ALOGV("getOutputForAttr() returns output %d", *output);
@@ -1050,7 +1066,7 @@
     const audio_port_handle_t requestedPortId = *selectedDeviceId;
     audio_attributes_t resultAttr;
     bool isRequestedDeviceForExclusiveUse = false;
-    std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputDescs;
+    std::vector<sp<AudioPolicyMix>> secondaryMixes;
     const sp<DeviceDescriptor> requestedDevice =
       mAvailableOutputDevices.getDeviceFromId(requestedPortId);
 
@@ -1061,14 +1077,20 @@
 
     status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
             config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
-            &secondaryOutputDescs, outputType);
+            secondaryOutputs != nullptr ? &secondaryMixes : nullptr, outputType);
     if (status != NO_ERROR) {
         return status;
     }
     std::vector<wp<SwAudioOutputDescriptor>> weakSecondaryOutputDescs;
-    for (auto& secondaryDesc : secondaryOutputDescs) {
-        secondaryOutputs->push_back(secondaryDesc->mIoHandle);
-        weakSecondaryOutputDescs.push_back(secondaryDesc);
+    if (secondaryOutputs != nullptr) {
+        for (auto &secondaryMix : secondaryMixes) {
+            sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
+            if (outputDesc != nullptr &&
+                outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+                secondaryOutputs->push_back(outputDesc->mIoHandle);
+                weakSecondaryOutputDescs.push_back(outputDesc);
+            }
+        }
     }
 
     audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
@@ -1093,6 +1115,118 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyManager::openDirectOutput(audio_stream_type_t stream,
+                                              audio_session_t session,
+                                              const audio_config_t *config,
+                                              audio_output_flags_t flags,
+                                              const DeviceVector &devices,
+                                              audio_io_handle_t *output) {
+
+    *output = AUDIO_IO_HANDLE_NONE;
+
+    // skip direct output selection if the request can obviously be attached to a mixed output
+    // and not explicitly requested
+    if (((flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
+            audio_is_linear_pcm(config->format) && config->sample_rate <= SAMPLE_RATE_HZ_MAX &&
+            audio_channel_count_from_out_mask(config->channel_mask) <= 2) {
+        return NAME_NOT_FOUND;
+    }
+
+    // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
+    // This prevents creating an offloaded track and tearing it down immediately after start
+    // when audioflinger detects there is an active non offloadable effect.
+    // FIXME: We should check the audio session here but we do not have it in this context.
+    // This may prevent offloading in rare situations where effects are left active by apps
+    // in the background.
+    sp<IOProfile> profile;
+    if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
+            !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
+        profile = getProfileForOutput(
+                devices, config->sample_rate, config->format, config->channel_mask,
+                flags, true /* directOnly */);
+    }
+
+    if (profile == nullptr) {
+        return NAME_NOT_FOUND;
+    }
+
+    // exclusive outputs for MMAP and Offload are enforced by different session ids.
+    for (size_t i = 0; i < mOutputs.size(); i++) {
+        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+        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->getSamplingRate()) &&
+                (config->format == desc->getFormat()) &&
+                (config->channel_mask == desc->getChannelMask()) &&
+                (session == desc->mDirectClientSession)) {
+                desc->mDirectOpenCount++;
+                ALOGI("%s reusing direct output %d for session %d", __func__,
+                    mOutputs.keyAt(i), session);
+                *output = mOutputs.keyAt(i);
+                return NO_ERROR;
+            }
+        }
+    }
+
+    if (!profile->canOpenNewIo()) {
+        return NAME_NOT_FOUND;
+    }
+
+    sp<SwAudioOutputDescriptor> outputDesc =
+            new SwAudioOutputDescriptor(profile, mpClientInterface);
+
+    String8 address = getFirstDeviceAddress(devices);
+
+    // MSD patch may be using the only output stream that can service this request. Release
+    // MSD patch to prioritize this request over any active output on MSD.
+    AudioPatchCollection msdPatches = getMsdPatches();
+    for (size_t i = 0; i < msdPatches.size(); i++) {
+        const auto& patch = msdPatches[i];
+        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 &&
+                    devices.containsDeviceWithType(sink->ext.device.type) &&
+                    (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
+                            AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+                releaseAudioPatch(patch->getHandle(), mUidCached);
+                break;
+            }
+        }
+    }
+
+    status_t status = outputDesc->open(config, devices, stream, flags, output);
+
+    // only accept an output with the requested parameters
+    if (status != NO_ERROR ||
+        (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+        (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+        (config->channel_mask != 0 && config->channel_mask != 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->getSamplingRate(), config->format, outputDesc->getFormat(),
+                config->channel_mask, outputDesc->getChannelMask());
+        if (*output != AUDIO_IO_HANDLE_NONE) {
+            outputDesc->close();
+        }
+        // fall back to mixer output if possible when the direct output could not be open
+        if (audio_is_linear_pcm(config->format) &&
+                config->sample_rate  <= SAMPLE_RATE_HZ_MAX) {
+            return NAME_NOT_FOUND;
+        }
+        *output = AUDIO_IO_HANDLE_NONE;
+        return BAD_VALUE;
+    }
+    outputDesc->mDirectOpenCount = 1;
+    outputDesc->mDirectClientSession = session;
+
+    addOutput(*output, outputDesc);
+    mPreviousOutputs = mOutputs;
+    ALOGV("%s returns new direct output %d", __func__, *output);
+    mpClientInterface->onAudioPortListUpdate();
+    return NO_ERROR;
+}
+
 audio_io_handle_t AudioPolicyManager::getOutputForDevices(
         const DeviceVector &devices,
         audio_session_t session,
@@ -1102,7 +1236,6 @@
         bool forceMutingHaptic)
 {
     audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-    status_t status;
 
     // Discard haptic channel mask when forcing muting haptic channels.
     audio_channel_mask_t channelMask = forceMutingHaptic
@@ -1137,112 +1270,13 @@
         ALOGV("Set VoIP and Direct output flags for PCM format");
     }
 
-
-    sp<IOProfile> profile;
-
-    // skip direct output selection if the request can obviously be attached to a mixed output
-    // and not explicitly requested
-    if (((*flags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) &&
-            audio_is_linear_pcm(config->format) && config->sample_rate <= SAMPLE_RATE_HZ_MAX &&
-            audio_channel_count_from_out_mask(channelMask) <= 2) {
-        goto non_direct_output;
-    }
-
-    // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
-    // This prevents creating an offloaded track and tearing it down immediately after start
-    // when audioflinger detects there is an active non offloadable effect.
-    // FIXME: We should check the audio session here but we do not have it in this context.
-    // This may prevent offloading in rare situations where effects are left active by apps
-    // in the background.
-
-    if (((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
-            !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
-        profile = getProfileForOutput(devices,
-                                   config->sample_rate,
-                                   config->format,
-                                   channelMask,
-                                   (audio_output_flags_t)*flags,
-                                   true /* directOnly */);
-    }
-
-    if (profile != 0) {
-        // exclusive outputs for MMAP and Offload are enforced by different session ids.
-        for (size_t i = 0; i < mOutputs.size(); i++) {
-            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-            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->getSamplingRate()) &&
-                    (config->format == desc->getFormat()) &&
-                    (channelMask == desc->getChannelMask()) &&
-                    (session == desc->mDirectClientSession)) {
-                    desc->mDirectOpenCount++;
-                    ALOGI("%s reusing direct output %d for session %d", __func__, 
-                        mOutputs.keyAt(i), session);
-                    return mOutputs.keyAt(i);
-                }
-            }
-        }
-
-        if (!profile->canOpenNewIo()) {
-            goto non_direct_output;
-        }
-
-        sp<SwAudioOutputDescriptor> outputDesc =
-                new SwAudioOutputDescriptor(profile, mpClientInterface);
-
-        String8 address = getFirstDeviceAddress(devices);
-
-        // MSD patch may be using the only output stream that can service this request. Release
-        // MSD patch to prioritize this request over any active output on MSD.
-        AudioPatchCollection msdPatches = getMsdPatches();
-        for (size_t i = 0; i < msdPatches.size(); i++) {
-            const auto& patch = msdPatches[i];
-            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 &&
-                        devices.containsDeviceWithType(sink->ext.device.type) &&
-                        (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
-                                AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
-                    releaseAudioPatch(patch->getHandle(), mUidCached);
-                    break;
-                }
-            }
-        }
-
-        status = outputDesc->open(config, devices, stream, *flags, &output);
-
-        // only accept an output with the requested parameters
-        if (status != NO_ERROR ||
-            (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->getSamplingRate(), config->format, outputDesc->getFormat(),
-                    channelMask, outputDesc->getChannelMask());
-            if (output != AUDIO_IO_HANDLE_NONE) {
-                outputDesc->close();
-            }
-            // fall back to mixer output if possible when the direct output could not be open
-            if (audio_is_linear_pcm(config->format) &&
-                    config->sample_rate  <= SAMPLE_RATE_HZ_MAX) {
-                goto non_direct_output;
-            }
-            return AUDIO_IO_HANDLE_NONE;
-        }
-        outputDesc->mDirectOpenCount = 1;
-        outputDesc->mDirectClientSession = session;
-
-        addOutput(output, outputDesc);
-        mPreviousOutputs = mOutputs;
-        ALOGV("%s returns new direct output %d", __func__, output);
-        mpClientInterface->onAudioPortListUpdate();
+    audio_config_t directConfig = *config;
+    directConfig.channel_mask = channelMask;
+    status_t status = openDirectOutput(stream, session, &directConfig, *flags, devices, &output);
+    if (status != NAME_NOT_FOUND) {
         return output;
     }
 
-non_direct_output:
-
     // A request for HW A/V sync cannot fallback to a mixed output because time
     // stamps are embedded in audio data
     if ((*flags & (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) != 0) {
@@ -2146,7 +2180,7 @@
 
     if (!profile->canOpenNewIo()) {
         for (size_t i = 0; i < mInputs.size(); ) {
-            sp <AudioInputDescriptor> desc = mInputs.valueAt(i);
+            sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
             if (desc->mProfile != profile) {
                 i++;
                 continue;
@@ -2406,9 +2440,7 @@
     for (size_t i = 0; i < mInputs.size(); i++) {
         const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
         if (input->clientsList().size() == 0
-                || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())
-                || (input->getPolicyAudioPort()->getFlags()
-                        & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
+                || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())) {
             inputsToClose.push_back(mInputs.keyAt(i));
         } else {
             bool close = false;
@@ -2457,6 +2489,10 @@
                                                   audio_devices_t device)
 {
     auto attributes = mEngine->getAttributesForStreamType(stream);
+    if (attributes == AUDIO_ATTRIBUTES_INITIALIZER) {
+        ALOGW("%s: no group for stream %s, bailing out", __func__, toString(stream).c_str());
+        return NO_ERROR;
+    }
     ALOGV("%s: stream %s attributes=%s", __func__,
           toString(stream).c_str(), toString(attributes).c_str());
     return setVolumeIndexForAttributes(attributes, index, device);
@@ -2884,8 +2920,8 @@
             }
             audio_config_t outputConfig = mix.mFormat;
             audio_config_t inputConfig = mix.mFormat;
-            // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL in
-            // stereo and let audio flinger do the channel conversion if needed.
+            // NOTE: audio flinger mixer does not support mono output: configure remote submix HAL
+            // in 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.c_str(), &outputConfig,
@@ -2915,10 +2951,11 @@
             }
 
             bool foundOutput = false;
-            for (size_t j = 0 ; j < mOutputs.size() ; j++) {
+            // First try to find an already opened output supporting the device
+            for (size_t j = 0 ; j < mOutputs.size() && !foundOutput && res == NO_ERROR; j++) {
                 sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(j);
 
-                if (desc->supportedDevices().contains(device)) {
+                if (!desc->isDuplicated() && desc->supportedDevices().contains(device)) {
                     if (mPolicyMixes.registerMix(mix, desc) != NO_ERROR) {
                         ALOGE("Could not register mix RENDER,  dev=0x%X addr=%s", type,
                               address.string());
@@ -2926,10 +2963,26 @@
                     } else {
                         foundOutput = true;
                     }
-                    break;
                 }
             }
-
+            // If no output found, try to find a direct output profile supporting the device
+            for (size_t i = 0; i < mHwModules.size() && !foundOutput && res == NO_ERROR; i++) {
+                sp<HwModule> module = mHwModules[i];
+                for (size_t j = 0;
+                        j < module->getOutputProfiles().size() && !foundOutput && res == NO_ERROR;
+                        j++) {
+                    sp<IOProfile> profile = module->getOutputProfiles()[j];
+                    if (profile->isDirectOutput() && profile->supportsDevice(device)) {
+                        if (mPolicyMixes.registerMix(mix, nullptr) != NO_ERROR) {
+                            ALOGE("Could not register mix RENDER,  dev=0x%X addr=%s", type,
+                                  address.string());
+                            res = INVALID_OPERATION;
+                        } else {
+                            foundOutput = true;
+                        }
+                    }
+                }
+            }
             if (res != NO_ERROR) {
                 ALOGE(" Error registering mix %zu for device 0x%X addr %s",
                         i, type, address.string());
@@ -3012,58 +3065,67 @@
     }
 }
 
+// Returns true if all devices types match the predicate and are supported by one HW module
+bool  AudioPolicyManager::areAllDevicesSupported(
+        const Vector<AudioDeviceTypeAddr>& devices,
+        std::function<bool(audio_devices_t)> predicate,
+        const char *context) {
+    for (size_t i = 0; i < devices.size(); i++) {
+        sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
+                devices[i].mType, devices[i].mAddress.c_str(), String8(),
+                AUDIO_FORMAT_DEFAULT, false /*allowToCreate*/, true /*matchAddress*/);
+        if (devDesc == nullptr || (predicate != nullptr && !predicate(devices[i].mType))) {
+            ALOGE("%s: device type %#x address %s not supported or not an output device",
+                    context, devices[i].mType, devices[i].mAddress.c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
 status_t AudioPolicyManager::setUidDeviceAffinities(uid_t uid,
         const Vector<AudioDeviceTypeAddr>& devices) {
     ALOGV("%s() uid=%d num devices %zu", __FUNCTION__, uid, devices.size());
-    // uid/device affinity is only for output devices
-    for (size_t i = 0; i < devices.size(); i++) {
-        if (!audio_is_output_device(devices[i].mType)) {
-            ALOGE("setUidDeviceAffinities() device=%08x is NOT an output device",
-                    devices[i].mType);
-            return BAD_VALUE;
-        }
+    if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
+        return BAD_VALUE;
     }
     status_t res =  mPolicyMixes.setUidDeviceAffinities(uid, devices);
-    if (res == NO_ERROR) {
-        // 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.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.c_str());
-                return INVALID_OPERATION;
-            }
-        }
+    if (res != NO_ERROR) {
+        ALOGE("%s() Could not set all device affinities for uid = %d", __FUNCTION__, uid);
+        return res;
     }
-    return res;
+
+    checkForDeviceAndOutputChanges();
+    updateCallAndOutputRouting();
+
+    return NO_ERROR;
 }
 
 status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) {
     ALOGV("%s() uid=%d", __FUNCTION__, uid);
     status_t res = mPolicyMixes.removeUidDeviceAffinities(uid);
     if (res != NO_ERROR) {
-        ALOGE("%s() Could not remove all device affinities fo uid = %d",
+        ALOGE("%s() Could not remove all device affinities for uid = %d",
             __FUNCTION__, uid);
         return INVALID_OPERATION;
     }
 
+    checkForDeviceAndOutputChanges();
+    updateCallAndOutputRouting();
+
     return res;
 }
 
 status_t AudioPolicyManager::setPreferredDeviceForStrategy(product_strategy_t strategy,
                                                    const AudioDeviceTypeAddr &device) {
-    ALOGI("%s() strategy=%d device=%08x addr=%s", __FUNCTION__,
+    ALOGV("%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);
+
+    Vector<AudioDeviceTypeAddr> devices;
+    devices.add(device);
+    if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
         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",
@@ -3122,17 +3184,10 @@
 
 status_t AudioPolicyManager::setUserIdDeviceAffinities(int userId,
         const Vector<AudioDeviceTypeAddr>& devices) {
-    ALOGI("%s() userId=%d num devices %zu", __FUNCTION__, userId, devices.size());
-    // userId/device affinity is only for output devices
-    for (size_t i = 0; i < devices.size(); i++) {
-        if (!audio_is_output_device(devices[i].mType)) {
-            ALOGE("%s() device=%08x is NOT an output device",
-                    __FUNCTION__,
-                    devices[i].mType);
-            return BAD_VALUE;
-        }
+    ALOGI("%s() userId=%d num devices %zu", __FUNCTION__, userId, devices.size());\
+    if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
+        return BAD_VALUE;
     }
-
     status_t status =  mPolicyMixes.setUserIdDeviceAffinities(userId, devices);
     if (status != NO_ERROR) {
         ALOGE("%s() could not set device affinity for userId %d",
@@ -3639,12 +3694,11 @@
                         audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
                         audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
                         bool isRequestedDeviceForExclusiveUse = false;
-                        std::vector<sp<SwAudioOutputDescriptor>> secondaryOutputs;
                         output_type_t outputType;
                         getOutputForAttrInt(&resultAttr, &output, AUDIO_SESSION_NONE, &attributes,
                                             &stream, sourceDesc->uid(), &config, &flags,
                                             &selectedDeviceId, &isRequestedDeviceForExclusiveUse,
-                                            &secondaryOutputs, &outputType);
+                                            nullptr, &outputType);
                         if (output == AUDIO_IO_HANDLE_NONE) {
                             ALOGV("%s no output for device %s",
                                   __FUNCTION__, sinkDevice->toString().c_str());
@@ -3755,6 +3809,22 @@
             removeAudioPatch(patchDesc->getHandle());
             nextAudioPortGeneration();
             mpClientInterface->onAudioPatchListUpdate();
+            // SW Bridge
+            if (patch->num_sources > 1 && patch->sources[1].type == AUDIO_PORT_TYPE_MIX) {
+                sp<SwAudioOutputDescriptor> outputDesc =
+                        mOutputs.getOutputFromId(patch->sources[1].id);
+                if (outputDesc == NULL) {
+                    ALOGE("%s output not found for id %d", __func__, patch->sources[0].id);
+                    return BAD_VALUE;
+                }
+                // Reset handle so that setOutputDevice will force new AF patch to reach the sink
+                outputDesc->setPatchHandle(AUDIO_PATCH_HANDLE_NONE);
+                setOutputDevices(outputDesc,
+                                 getNewOutputDevices(outputDesc, true /*fromCache*/),
+                                 true, /*force*/
+                                 0,
+                                 NULL);
+            }
         } else {
             return BAD_VALUE;
         }
@@ -4350,12 +4420,6 @@
     return mAudioPortGeneration++;
 }
 
-// Treblized audio policy xml config will be located in /odm/etc or /vendor/etc.
-static const char *kConfigLocationList[] =
-        {"/odm/etc", "/vendor/etc", "/system/etc"};
-static const int kConfigLocationListSize =
-        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
-
 static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
     char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
     std::vector<const char*> fileNames;
@@ -4377,9 +4441,9 @@
     fileNames.push_back(AUDIO_POLICY_XML_CONFIG_FILE_NAME);
 
     for (const char* fileName : fileNames) {
-        for (int i = 0; i < kConfigLocationListSize; i++) {
+        for (const auto& path : audio_get_configuration_paths()) {
             snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
-                     "%s/%s", kConfigLocationList[i], fileName);
+                     "%s/%s", path.c_str(), fileName);
             ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile, &config);
             if (ret == NO_ERROR) {
                 config.setSource(audioPolicyXmlConfigFile);
@@ -4444,7 +4508,7 @@
 
     // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
     // open all output streams needed to access attached devices
-    onNewAudioModulesAvailable();
+    onNewAudioModulesAvailableInt(nullptr /*newDevices*/);
 
     // make sure default device is reachable
     if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
@@ -4501,6 +4565,16 @@
 
 void AudioPolicyManager::onNewAudioModulesAvailable()
 {
+    DeviceVector newDevices;
+    onNewAudioModulesAvailableInt(&newDevices);
+    if (!newDevices.empty()) {
+        nextAudioPortGeneration();
+        mpClientInterface->onAudioPortListUpdate();
+    }
+}
+
+void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
+{
     for (const auto& hwModule : mHwModulesAll) {
         if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
             continue;
@@ -4529,9 +4603,6 @@
                 mTtsOutputAvailable = true;
             }
 
-            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
-                continue;
-            }
             const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
             DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
             sp<DeviceDescriptor> supportedDevice = 0;
@@ -4564,6 +4635,7 @@
                 if (!device->isAttached()) {
                     device->attach(hwModule);
                     mAvailableOutputDevices.add(device);
+                    if (newDevices) newDevices->add(device);
                     setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
                 }
             }
@@ -4571,12 +4643,16 @@
                     outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                 mPrimaryOutput = outputDesc;
             }
-            addOutput(output, outputDesc);
-            setOutputDevices(outputDesc,
-                             DeviceVector(supportedDevice),
-                             true,
-                             0,
-                             NULL);
+            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+                outputDesc->close();
+            } else {
+                addOutput(output, outputDesc);
+                setOutputDevices(outputDesc,
+                                 DeviceVector(supportedDevice),
+                                 true,
+                                 0,
+                                 NULL);
+            }
         }
         // open input streams needed to access attached devices to validate
         // mAvailableInputDevices list
@@ -4619,6 +4695,7 @@
                     device->attach(hwModule);
                     device->importAudioPortAndPickAudioProfile(inProfile, true);
                     mAvailableInputDevices.add(device);
+                    if (newDevices) newDevices->add(device);
                     setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
                 }
             }
@@ -4761,7 +4838,7 @@
 
                 if (output != AUDIO_IO_HANDLE_NONE) {
                     addOutput(output, desc);
-                    if (device_distinguishes_on_address(deviceType) && address != "0") {
+                    if (audio_is_remote_submix_device(deviceType) && address != "0") {
                         sp<AudioPolicyMix> policyMix;
                         if (mPolicyMixes.getAudioPolicyMix(deviceType, address, policyMix)
                                 == NO_ERROR) {
@@ -5251,10 +5328,19 @@
     for (size_t i = 0; i < mOutputs.size(); i++) {
         const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
         for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
-            sp<SwAudioOutputDescriptor> desc;
-            std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
+            sp<AudioPolicyMix> primaryMix;
+            std::vector<sp<AudioPolicyMix>> secondaryMixes;
             status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->uid(),
-                                                            client->flags(), desc, &secondaryDescs);
+                    client->flags(), primaryMix, &secondaryMixes);
+            std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
+            for (auto &secondaryMix : secondaryMixes) {
+                sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
+                if (outputDesc != nullptr &&
+                    outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
+                    secondaryDescs.push_back(outputDesc);
+                }
+            }
+
             if (status != OK ||
                 !std::equal(client->getSecondaryOutputs().begin(),
                             client->getSecondaryOutputs().end(),
@@ -5458,21 +5544,17 @@
     }
     // check dynamic policies but only for primary descriptors (secondary not used for audible
     // audio routing, only used for duplication for playback capture)
-    sp<SwAudioOutputDescriptor> policyDesc;
+    sp<AudioPolicyMix> policyMix;
     status_t status = mPolicyMixes.getOutputForAttr(attr, 0 /*uid unknown here*/,
-            AUDIO_OUTPUT_FLAG_NONE, policyDesc, nullptr);
+            AUDIO_OUTPUT_FLAG_NONE, policyMix, nullptr);
     if (status != OK) {
         return status;
     }
-    if (policyDesc != nullptr) {
-        sp<AudioPolicyMix> mix = policyDesc->mPolicyMix.promote();
-        if (mix != nullptr) {
-            AudioDeviceTypeAddr device(mix->mDeviceType, mix->mDeviceAddress.c_str());
-            devices->push_back(device);
-            return NO_ERROR;
-        }
+    if (policyMix != nullptr && policyMix->getOutput() != nullptr) {
+        AudioDeviceTypeAddr device(policyMix->mDeviceType, policyMix->mDeviceAddress.c_str());
+        devices->push_back(device);
+        return NO_ERROR;
     }
-
     DeviceVector curDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false);
     for (const auto& device : curDevices) {
         devices->push_back(device->getDeviceTypeAddr());
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 8121f86..b588f89 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -788,6 +788,8 @@
 
         std::unordered_map<uid_t, audio_flags_mask_t> mAllowedCapturePolicies;
 private:
+        void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
+
         // Add or remove AC3 DTS encodings based on user preferences.
         void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
         void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr);
@@ -835,7 +837,7 @@
                 audio_output_flags_t *flags,
                 audio_port_handle_t *selectedDeviceId,
                 bool *isRequestedDeviceForExclusiveUse,
-                std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+                std::vector<sp<AudioPolicyMix>> *secondaryMixes,
                 output_type_t *outputType);
         // internal method to return the output handle for the given device and format
         audio_io_handle_t getOutputForDevices(
@@ -846,6 +848,16 @@
                 audio_output_flags_t *flags,
                 bool forceMutingHaptic = false);
 
+        // Internal method checking if a direct output can be opened matching the requested
+        // attributes, flags, config and devices.
+        // If NAME_NOT_FOUND is returned, an attempt can be made to open a mixed output.
+        status_t openDirectOutput(
+                audio_stream_type_t stream,
+                audio_session_t session,
+                const audio_config_t *config,
+                audio_output_flags_t flags,
+                const DeviceVector &devices,
+                audio_io_handle_t *output);
         /**
          * @brief getInputForDevice selects an input handle for a given input device and
          * requester context
@@ -878,6 +890,8 @@
                                              const char *device_address,
                                              const char *device_name,
                                              audio_format_t encodedFormat);
+        status_t setDeviceConnectionStateInt(const sp<DeviceDescriptor> &device,
+                                             audio_policy_dev_state_t state);
 
         void setEngineDeviceConnectionState(const sp<DeviceDescriptor> device,
                                       audio_policy_dev_state_t state);
@@ -922,6 +936,12 @@
                 int delayMs,
                 uid_t uid,
                 sp<AudioPatch> *patchDescPtr);
+
+        bool areAllDevicesSupported(
+                const Vector<AudioDeviceTypeAddr>& devices,
+                std::function<bool(audio_devices_t)> predicate,
+                const char* context);
+
 };
 
 };
diff --git a/services/audiopolicy/service/Android.mk b/services/audiopolicy/service/Android.mk
index 80f4eab..680b077 100644
--- a/services/audiopolicy/service/Android.mk
+++ b/services/audiopolicy/service/Android.mk
@@ -6,7 +6,8 @@
     AudioPolicyService.cpp \
     AudioPolicyEffects.cpp \
     AudioPolicyInterfaceImpl.cpp \
-    AudioPolicyClientImpl.cpp
+    AudioPolicyClientImpl.cpp \
+    CaptureStateNotifier.cpp
 
 LOCAL_C_INCLUDES := \
     frameworks/av/services/audioflinger \
@@ -32,7 +33,7 @@
     libmediautils \
     libeffectsconfig \
     libsensorprivacy \
-    soundtrigger_middleware-aidl-cpp
+    capture_state_listener-aidl-cpp
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
     libsensorprivacy
@@ -43,7 +44,7 @@
 LOCAL_MODULE:= libaudiopolicyservice
 
 LOCAL_CFLAGS += -fvisibility=hidden
-LOCAL_CFLAGS += -Wall -Werror
+LOCAL_CFLAGS += -Wall -Werror -Wthread-safety
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 5b81b9d..9fa7a53 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -19,7 +19,6 @@
 
 #include "AudioPolicyService.h"
 
-#include <android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.h>
 #include <utils/Log.h>
 
 #include "BinderProxy.h"
@@ -242,12 +241,9 @@
     return AudioSystem::newAudioUniqueId(use);
 }
 
-void AudioPolicyService::AudioPolicyClient::setSoundTriggerCaptureState(bool active) {
-    using media::soundtrigger_middleware::ISoundTriggerMiddlewareService;
-
-    static BinderProxy<ISoundTriggerMiddlewareService>
-        proxy("soundtrigger_middleware");
-    proxy.waitServiceOrDie()->setExternalCaptureState(active);
+void AudioPolicyService::AudioPolicyClient::setSoundTriggerCaptureState(bool active)
+{
+    mAudioPolicyService->mCaptureStateNotifier.setCaptureState(active);
 }
 
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 738a279..1ec0c5e 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -928,7 +928,10 @@
 
     loadProcessingChain(result.parsedConfig->preprocess, mInputSources);
     loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams);
-    loadDeviceProcessingChain(result.parsedConfig->deviceprocess, mDeviceEffects);
+    {
+        Mutex::Autolock _l(mLock);
+        loadDeviceProcessingChain(result.parsedConfig->deviceprocess, mDeviceEffects);
+    }
     // Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors
     return result.nbSkippedElement;
 }
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 0da3b9c..9577160 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -219,7 +219,6 @@
                                               audio_stream_type_t *stream,
                                               pid_t pid,
                                               uid_t uid,
-                                              const String16& opPackageName,
                                               const audio_config_t *config,
                                               audio_output_flags_t flags,
                                               audio_port_handle_t *selectedDeviceId,
@@ -266,8 +265,7 @@
         case AudioPolicyInterface::API_OUTPUT_LEGACY:
             break;
         case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
-          if (!modifyPhoneStateAllowed(pid, uid) &&
-              !accessCallAudioAllowed(opPackageName, pid, uid)) {
+            if (!modifyPhoneStateAllowed(pid, uid)) {
                 ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
                     __func__, uid);
                 result = PERMISSION_DENIED;
@@ -464,22 +462,15 @@
     }
 
     bool canCaptureOutput = captureAudioOutputAllowed(pid, uid);
-    bool canCaptureTelephonyOutput = canCaptureOutput
-        || accessCallAudioAllowed(opPackageName, pid, uid);
-
-    if ((attr->source == AUDIO_SOURCE_ECHO_REFERENCE ||
-         attr->source == AUDIO_SOURCE_FM_TUNER) &&
+    if ((inputSource == AUDIO_SOURCE_VOICE_UPLINK ||
+        inputSource == AUDIO_SOURCE_VOICE_DOWNLINK ||
+        inputSource == AUDIO_SOURCE_VOICE_CALL ||
+        inputSource == AUDIO_SOURCE_ECHO_REFERENCE||
+        inputSource == AUDIO_SOURCE_FM_TUNER) &&
         !canCaptureOutput) {
         return PERMISSION_DENIED;
     }
 
-    if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
-        attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
-        attr->source == AUDIO_SOURCE_VOICE_CALL) &&
-        !canCaptureTelephonyOutput) {
-        return PERMISSION_DENIED;
-    }
-
     bool canCaptureHotword = captureHotwordAllowed(opPackageName, pid, uid);
     if ((inputSource == AUDIO_SOURCE_HOTWORD) && !canCaptureHotword) {
         return BAD_VALUE;
@@ -511,11 +502,6 @@
                 break;
             case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
                 // FIXME: use the same permission as for remote submix for now.
-                if (!canCaptureTelephonyOutput) {
-                    ALOGE("getInputForAttr() permission denied: call capture not allowed");
-                    status = PERMISSION_DENIED;
-                }
-                break;
             case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
                 if (!canCaptureOutput) {
                     ALOGE("getInputForAttr() permission denied: capture not allowed");
@@ -543,13 +529,9 @@
             return status;
         }
 
-        bool allowAudioCapture = canCaptureOutput ||
-            (inputType == AudioPolicyInterface::API_INPUT_TELEPHONY_RX &&
-             canCaptureTelephonyOutput);
-
         sp<AudioRecordClient> client = new AudioRecordClient(*attr, *input, uid, pid, session, *portId,
                                                              *selectedDeviceId, opPackageName,
-                                                             allowAudioCapture, canCaptureHotword);
+                                                             canCaptureOutput, canCaptureHotword);
         mAudioRecordClients.add(*portId, client);
     }
 
@@ -1438,6 +1420,13 @@
     return NO_ERROR;
 }
 
+status_t AudioPolicyService::setCurrentImeUid(uid_t uid)
+{
+    Mutex::Autolock _l(mLock);
+    mUidPolicy->setCurrentImeUid(uid);
+    return NO_ERROR;
+}
+
 bool AudioPolicyService::isHapticPlaybackSupported()
 {
     if (mAudioPolicyManager == NULL) {
@@ -1534,4 +1523,12 @@
     return mAudioPolicyManager->getPreferredDeviceForStrategy(strategy, device);
 }
 
+status_t AudioPolicyService::registerSoundTriggerCaptureStateListener(
+    const sp<media::ICaptureStateListener>& listener,
+    bool* result)
+{
+    *result = mCaptureStateNotifier.RegisterListener(listener);
+    return NO_ERROR;
+}
+
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index bf38477..9b61e74 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -57,9 +57,11 @@
 // ----------------------------------------------------------------------------
 
 AudioPolicyService::AudioPolicyService()
-    : BnAudioPolicyService(), mpAudioPolicyDev(NULL), mpAudioPolicy(NULL),
-      mAudioPolicyManager(NULL), mAudioPolicyClient(NULL), mPhoneState(AUDIO_MODE_INVALID)
-{
+    : BnAudioPolicyService(),
+      mAudioPolicyManager(NULL),
+      mAudioPolicyClient(NULL),
+      mPhoneState(AUDIO_MODE_INVALID),
+      mCaptureStateNotifier(false) {
 }
 
 void AudioPolicyService::onFirstRef()
@@ -74,21 +76,19 @@
 
         mAudioPolicyClient = new AudioPolicyClient(this);
         mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
-
-        mSupportedSystemUsages = std::vector<audio_usage_t> {};
     }
     // load audio processing modules
-    sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
+    sp<AudioPolicyEffects> audioPolicyEffects = new AudioPolicyEffects();
+    sp<UidPolicy> uidPolicy = new UidPolicy(this);
+    sp<SensorPrivacyPolicy> sensorPrivacyPolicy = new SensorPrivacyPolicy(this);
     {
         Mutex::Autolock _l(mLock);
         mAudioPolicyEffects = audioPolicyEffects;
+        mUidPolicy = uidPolicy;
+        mSensorPrivacyPolicy = sensorPrivacyPolicy;
     }
-
-    mUidPolicy = new UidPolicy(this);
-    mUidPolicy->registerSelf();
-
-    mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
-    mSensorPrivacyPolicy->registerSelf();
+    uidPolicy->registerSelf();
+    sensorPrivacyPolicy->registerSelf();
 }
 
 AudioPolicyService::~AudioPolicyService()
@@ -103,9 +103,9 @@
     mAudioPolicyEffects.clear();
 
     mUidPolicy->unregisterSelf();
-    mUidPolicy.clear();
-
     mSensorPrivacyPolicy->unregisterSelf();
+
+    mUidPolicy.clear();
     mSensorPrivacyPolicy.clear();
 }
 
@@ -168,20 +168,20 @@
 // removeNotificationClient() is called when the client process dies.
 void AudioPolicyService::removeNotificationClient(uid_t uid, pid_t pid)
 {
+    bool hasSameUid = false;
     {
         Mutex::Autolock _l(mNotificationClientsLock);
         int64_t token = ((int64_t)uid<<32) | pid;
         mNotificationClients.removeItem(token);
-    }
-    {
-        Mutex::Autolock _l(mLock);
-        bool hasSameUid = false;
         for (size_t i = 0; i < mNotificationClients.size(); i++) {
             if (mNotificationClients.valueAt(i)->uid() == uid) {
                 hasSameUid = true;
                 break;
             }
         }
+    }
+    {
+        Mutex::Autolock _l(mLock);
         if (mAudioPolicyManager && !hasSameUid) {
             // called from binder death notification: no need to clear caller identity
             mAudioPolicyManager->releaseResourcesForUid(uid);
@@ -377,10 +377,14 @@
             IPCThreadState::self()->getCallingPid());
 }
 
-static bool dumpTryLock(Mutex& mutex)
+static bool dumpTryLock(Mutex& mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
 {
-    status_t err = mutex.timedLock(kDumpLockTimeoutNs);
-    return err == NO_ERROR;
+    return mutex.timedLock(kDumpLockTimeoutNs) == NO_ERROR;
+}
+
+static void dumpReleaseLock(Mutex& mutex, bool locked) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
+{
+    if (locked) mutex.unlock();
 }
 
 status_t AudioPolicyService::dumpInternals(int fd)
@@ -437,6 +441,8 @@
 //            OR all active clients are using HOTWORD source
 //        AND no call is active
 //            OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+//    OR the client is the current InputMethodService
+//        AND a RTT call is active AND the source is VOICE_RECOGNITION
 //    OR Any client
 //        AND The assistant is not on TOP
 //        AND is on TOP or latest started
@@ -543,7 +549,7 @@
     //  else
     //    favor the privacy sensitive case
     if (topActive != nullptr && topSensitiveActive != nullptr
-            && !topActive->canCaptureCallOrOutput) {
+            && !topActive->canCaptureOutput) {
         topActive = nullptr;
     }
 
@@ -558,9 +564,9 @@
         bool isTopOrLatestSensitive = topSensitiveActive == nullptr ?
                                  false : current->uid == topSensitiveActive->uid;
 
-        auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) {
-            bool canCaptureCall = recordClient->canCaptureCallOrOutput;
-            bool canCaptureCommunication = recordClient->canCaptureCallOrOutput
+        auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) REQUIRES(mLock) {
+            bool canCaptureCall = recordClient->canCaptureOutput;
+            bool canCaptureCommunication = recordClient->canCaptureOutput
                 || recordClient->uid == mPhoneStateOwnerUid
                 || isServiceUid(mPhoneStateOwnerUid);
             return !(isInCall && !canCaptureCall)
@@ -575,7 +581,7 @@
         bool allowCapture = !isAssistantOnTop
                 && (isTopOrLatestActive || isTopOrLatestSensitive)
                 && !(isSensitiveActive
-                    && !(isTopOrLatestSensitive || current->canCaptureCallOrOutput))
+                    && !(isTopOrLatestSensitive || current->canCaptureOutput))
                 && canCaptureIfInCallOrCommunication(current);
 
         if (isVirtualSource(source)) {
@@ -596,7 +602,7 @@
             } else {
                 if (((isAssistantOnTop && source == AUDIO_SOURCE_VOICE_RECOGNITION) ||
                         source == AUDIO_SOURCE_HOTWORD)
-                        && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+                        && !(isSensitiveActive && !current->canCaptureOutput)
                         && canCaptureIfInCallOrCommunication(current)) {
                     allowCapture = true;
                 }
@@ -609,7 +615,7 @@
             //     OR
             //         Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
             if (!isAssistantOnTop
-                    && !(isSensitiveActive && !current->canCaptureCallOrOutput)
+                    && !(isSensitiveActive && !current->canCaptureOutput)
                     && canCaptureIfInCallOrCommunication(current)) {
                 allowCapture = true;
             }
@@ -627,6 +633,12 @@
                     && canCaptureIfInCallOrCommunication(current)) {
                 allowCapture = true;
             }
+        } else if (mUidPolicy->isCurrentImeUid(current->uid)) {
+            // For current InputMethodService allow capture if:
+            //     A RTT call is active AND the source is VOICE_RECOGNITION
+            if (rttCallActive && source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+                allowCapture = true;
+            }
         }
         setAppState_l(current->portId,
                       allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
@@ -664,6 +676,7 @@
         case AUDIO_SOURCE_VOICE_CALL:
         case AUDIO_SOURCE_REMOTE_SUBMIX:
         case AUDIO_SOURCE_FM_TUNER:
+        case AUDIO_SOURCE_ECHO_REFERENCE:
             return true;
         default:
             break;
@@ -690,7 +703,7 @@
     if (!dumpAllowed()) {
         dumpPermissionDenial(fd);
     } else {
-        bool locked = dumpTryLock(mLock);
+        const bool locked = dumpTryLock(mLock);
         if (!locked) {
             String8 result(kDeadlockedString);
             write(fd, result.string(), result.size());
@@ -707,7 +720,7 @@
 
         mPackageManager.dump(fd);
 
-        if (locked) mLock.unlock();
+        dumpReleaseLock(mLock, locked);
     }
     return NO_ERROR;
 }
@@ -826,8 +839,16 @@
         return BAD_VALUE;
     }
 
-    mUidPolicy->addOverrideUid(uid, active);
-    return NO_ERROR;
+    sp<UidPolicy> uidPolicy;
+    {
+        Mutex::Autolock _l(mLock);
+        uidPolicy = mUidPolicy;
+    }
+    if (uidPolicy) {
+        uidPolicy->addOverrideUid(uid, active);
+        return NO_ERROR;
+    }
+    return NO_INIT;
 }
 
 status_t AudioPolicyService::handleResetUidState(Vector<String16>& args, int err) {
@@ -847,8 +868,16 @@
         return BAD_VALUE;
     }
 
-    mUidPolicy->removeOverrideUid(uid);
-    return NO_ERROR;
+    sp<UidPolicy> uidPolicy;
+    {
+        Mutex::Autolock _l(mLock);
+        uidPolicy = mUidPolicy;
+    }
+    if (uidPolicy) {
+        uidPolicy->removeOverrideUid(uid);
+        return NO_ERROR;
+    }
+    return NO_INIT;
 }
 
 status_t AudioPolicyService::handleGetUidState(Vector<String16>& args, int out, int err) {
@@ -868,11 +897,15 @@
         return BAD_VALUE;
     }
 
-    if (mUidPolicy->isUidActive(uid)) {
-        return dprintf(out, "active\n");
-    } else {
-        return dprintf(out, "idle\n");
+    sp<UidPolicy> uidPolicy;
+    {
+        Mutex::Autolock _l(mLock);
+        uidPolicy = mUidPolicy;
     }
+    if (uidPolicy) {
+        return dprintf(out, uidPolicy->isUidActive(uid) ? "active\n" : "idle\n");
+    }
+    return NO_INIT;
 }
 
 status_t AudioPolicyService::printHelp(int out) {
@@ -1389,7 +1422,7 @@
     result.append(buffer);
     write(fd, result.string(), result.size());
 
-    bool locked = dumpTryLock(mLock);
+    const bool locked = dumpTryLock(mLock);
     if (!locked) {
         String8 result2(kCmdDeadlockedString);
         write(fd, result2.string(), result2.size());
@@ -1412,7 +1445,7 @@
 
     write(fd, result.string(), result.size());
 
-    if (locked) mLock.unlock();
+    dumpReleaseLock(mLock, locked);
 
     return NO_ERROR;
 }
@@ -1876,7 +1909,7 @@
 
 void AudioPolicyService::onNewAudioModulesAvailable()
 {
-    mAudioCommandThread->audioModulesUpdateCommand();
+    mOutputCommandThread->audioModulesUpdateCommand();
 }
 
 
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index ff99124..869a963 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_AUDIOPOLICYSERVICE_H
 #define ANDROID_AUDIOPOLICYSERVICE_H
 
+#include <android-base/thread_annotations.h>
 #include <cutils/misc.h>
 #include <cutils/config_utils.h>
 #include <cutils/compiler.h>
@@ -34,6 +35,7 @@
 #include <media/AudioPolicy.h>
 #include <mediautils/ServiceUtilities.h>
 #include "AudioPolicyEffects.h"
+#include "CaptureStateNotifier.h"
 #include <AudioPolicyInterface.h>
 #include <android/hardware/BnSensorPrivacyListener.h>
 
@@ -83,7 +85,6 @@
                               audio_stream_type_t *stream,
                               pid_t pid,
                               uid_t uid,
-                              const String16& opPackageName,
                               const audio_config_t *config,
                               audio_output_flags_t flags,
                               audio_port_handle_t *selectedDeviceId,
@@ -262,6 +263,7 @@
 
     virtual status_t setAssistantUid(uid_t uid);
     virtual status_t setA11yServicesUids(const std::vector<uid_t>& uids);
+    virtual status_t setCurrentImeUid(uid_t uid);
 
     virtual bool     isHapticPlaybackSupported();
 
@@ -274,6 +276,10 @@
     virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
                                                        volume_group_t &volumeGroup);
 
+    status_t registerSoundTriggerCaptureStateListener(
+        const sp<media::ICaptureStateListener>& listener,
+        bool* result) override;
+
     virtual status_t setRttEnabled(bool enabled);
 
             bool isCallScreenModeSupported() override;
@@ -325,13 +331,13 @@
                         AudioPolicyService() ANDROID_API;
     virtual             ~AudioPolicyService();
 
-            status_t dumpInternals(int fd);
+            status_t dumpInternals(int fd) REQUIRES(mLock);
 
     // Handles binder shell commands
     virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
 
     // Sets whether the given UID records only silence
-    virtual void setAppState_l(audio_port_handle_t portId, app_state_t state);
+    virtual void setAppState_l(audio_port_handle_t portId, app_state_t state) REQUIRES(mLock);
 
     // Overrides the UID state as if it is idle
     status_t handleSetUidState(Vector<String16>& args, int err);
@@ -356,9 +362,9 @@
     status_t validateUsage(audio_usage_t usage, pid_t pid, uid_t uid);
 
     void updateUidStates();
-    void updateUidStates_l();
+    void updateUidStates_l() REQUIRES(mLock);
 
-    void silenceAllRecordings_l();
+    void silenceAllRecordings_l() REQUIRES(mLock);
 
     static bool isVirtualSource(audio_source_t source);
 
@@ -372,7 +378,7 @@
     public:
         explicit UidPolicy(wp<AudioPolicyService> service)
                 : mService(service), mObserverRegistered(false),
-                  mAssistantUid(0), mRttEnabled(false) {}
+                  mAssistantUid(0), mCurrentImeUid(0), mRttEnabled(false) {}
 
         void registerSelf();
         void unregisterSelf();
@@ -387,6 +393,8 @@
         void setA11yUids(const std::vector<uid_t>& uids) { mA11yUids.clear(); mA11yUids = uids; }
         bool isA11yUid(uid_t uid);
         bool isA11yOnTop();
+        void setCurrentImeUid(uid_t uid) { mCurrentImeUid = uid; }
+        bool isCurrentImeUid(uid_t uid) { return uid == mCurrentImeUid; }
         void setRttEnabled(bool enabled) { mRttEnabled = enabled; }
         bool isRttEnabled() { return mRttEnabled; }
 
@@ -413,12 +421,13 @@
         wp<AudioPolicyService> mService;
         Mutex mLock;
         ActivityManager mAm;
-        bool mObserverRegistered;
+        bool mObserverRegistered = false;
         std::unordered_map<uid_t, std::pair<bool, int>> mOverrideUids;
         std::unordered_map<uid_t, std::pair<bool, int>> mCachedUids;
-        uid_t mAssistantUid;
+        uid_t mAssistantUid = -1;
         std::vector<uid_t> mA11yUids;
-        bool mRttEnabled;
+        uid_t mCurrentImeUid = -1;
+        bool mRttEnabled = false;
     };
 
     // If sensor privacy is enabled then all apps, including those that are active, should be
@@ -439,7 +448,7 @@
 
         private:
             wp<AudioPolicyService> mService;
-            std::atomic_bool mSensorPrivacyEnabled;
+            std::atomic_bool mSensorPrivacyEnabled = false;
     };
 
     // Thread used to send audio config commands to audio flinger
@@ -812,16 +821,15 @@
                           const audio_io_handle_t io, uid_t uid, pid_t pid,
                           const audio_session_t session, audio_port_handle_t portId,
                           const audio_port_handle_t deviceId, const String16& opPackageName,
-                          bool canCaptureCallOrOutput, bool canCaptureHotword) :
+                          bool canCaptureOutput, bool canCaptureHotword) :
                     AudioClient(attributes, io, uid, pid, session, portId, deviceId),
                     opPackageName(opPackageName), startTimeNs(0),
-                    canCaptureCallOrOutput(canCaptureCallOrOutput),
-                    canCaptureHotword(canCaptureHotword) {}
+                    canCaptureOutput(canCaptureOutput), canCaptureHotword(canCaptureHotword) {}
                 ~AudioRecordClient() override = default;
 
         const String16 opPackageName;        // client package name
         nsecs_t startTimeNs;
-        const bool canCaptureCallOrOutput;
+        const bool canCaptureOutput;
         const bool canCaptureHotword;
     };
 
@@ -873,28 +881,31 @@
     // and possibly back in to audio policy service and acquire mEffectsLock.
     sp<AudioCommandThread> mAudioCommandThread;     // audio commands thread
     sp<AudioCommandThread> mOutputCommandThread;    // process stop and release output
-    struct audio_policy_device *mpAudioPolicyDev;
-    struct audio_policy *mpAudioPolicy;
     AudioPolicyInterface *mAudioPolicyManager;
     AudioPolicyClient *mAudioPolicyClient;
     std::vector<audio_usage_t> mSupportedSystemUsages;
 
-    DefaultKeyedVector< int64_t, sp<NotificationClient> >    mNotificationClients;
-    Mutex mNotificationClientsLock;  // protects mNotificationClients
+    Mutex mNotificationClientsLock;
+    DefaultKeyedVector<int64_t, sp<NotificationClient>> mNotificationClients
+        GUARDED_BY(mNotificationClientsLock);
     // Manage all effects configured in audio_effects.conf
     // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
     // those can call back into AudioPolicyService methods and try to acquire the mutex
-    sp<AudioPolicyEffects> mAudioPolicyEffects;
-    audio_mode_t mPhoneState;
-    uid_t mPhoneStateOwnerUid;
+    sp<AudioPolicyEffects> mAudioPolicyEffects GUARDED_BY(mLock);
+    audio_mode_t mPhoneState GUARDED_BY(mLock);
+    uid_t mPhoneStateOwnerUid GUARDED_BY(mLock);
 
-    sp<UidPolicy> mUidPolicy;
-    sp<SensorPrivacyPolicy> mSensorPrivacyPolicy;
+    sp<UidPolicy> mUidPolicy GUARDED_BY(mLock);
+    sp<SensorPrivacyPolicy> mSensorPrivacyPolicy GUARDED_BY(mLock);
 
-    DefaultKeyedVector< audio_port_handle_t, sp<AudioRecordClient> >   mAudioRecordClients;
-    DefaultKeyedVector< audio_port_handle_t, sp<AudioPlaybackClient> >   mAudioPlaybackClients;
+    DefaultKeyedVector<audio_port_handle_t, sp<AudioRecordClient>> mAudioRecordClients
+        GUARDED_BY(mLock);
+    DefaultKeyedVector<audio_port_handle_t, sp<AudioPlaybackClient>> mAudioPlaybackClients
+        GUARDED_BY(mLock);
 
     MediaPackageManager mPackageManager; // To check allowPlaybackCapture
+
+    CaptureStateNotifier mCaptureStateNotifier;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/service/CaptureStateNotifier.cpp b/services/audiopolicy/service/CaptureStateNotifier.cpp
new file mode 100644
index 0000000..135e0a2
--- /dev/null
+++ b/services/audiopolicy/service/CaptureStateNotifier.cpp
@@ -0,0 +1,67 @@
+#define LOG_TAG "CaptureStateNotifier"
+
+#include "CaptureStateNotifier.h"
+
+#include <android/media/ICaptureStateListener.h>
+#include <binder/IBinder.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using media::ICaptureStateListener;
+
+class CaptureStateNotifier::DeathRecipient : public IBinder::DeathRecipient {
+public:
+    DeathRecipient(CaptureStateNotifier* notifier) : mNotifier(notifier) {}
+
+    void binderDied(const wp<IBinder>&) override {
+        mNotifier->binderDied();
+    }
+
+private:
+    CaptureStateNotifier* const mNotifier;
+};
+
+CaptureStateNotifier::CaptureStateNotifier(bool initialActive)
+    : mDeathRecipient(new DeathRecipient(this)), mActive(
+    initialActive) {}
+
+CaptureStateNotifier::~CaptureStateNotifier() {
+    LOG_ALWAYS_FATAL_IF(mListener != nullptr);
+}
+
+bool CaptureStateNotifier::RegisterListener(const sp<ICaptureStateListener>& listener) {
+    std::lock_guard<std::mutex> _l(mMutex);
+    LOG_ALWAYS_FATAL_IF(mListener != nullptr);
+    LOG_ALWAYS_FATAL_IF(listener == nullptr);
+
+    ALOGI("Registering a listener");
+    sp<IBinder> binder = IInterface::asBinder(listener);
+    if (binder != nullptr) {
+        status_t status = binder->linkToDeath(mDeathRecipient);
+        if (status == NO_ERROR) {
+            mListener = listener;
+        } else {
+            ALOGE("Failed to register death listener: %u", status);
+        }
+    } else {
+        ALOGE("Listener failed to cast to a binder.");
+    }
+    return mActive;
+}
+
+void CaptureStateNotifier::setCaptureState(bool active) {
+    std::lock_guard<std::mutex> _l(mMutex);
+    mActive = active;
+    if (mListener) {
+        mListener->setCaptureState(active);
+    }
+}
+
+void CaptureStateNotifier::binderDied() {
+    std::lock_guard<std::mutex> _l(mMutex);
+    mListener.clear();
+    ALOGI("Listener binder died");
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/services/audiopolicy/service/CaptureStateNotifier.h b/services/audiopolicy/service/CaptureStateNotifier.h
new file mode 100644
index 0000000..166de2a
--- /dev/null
+++ b/services/audiopolicy/service/CaptureStateNotifier.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <binder/IBinder.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace media {
+// Must be pre-declared, or else there isn't a good way to generate a header
+// library.
+class ICaptureStateListener;
+}
+
+// A utility for managing capture state change notifications.
+//
+// We are making some strong assumptions, for the sake of simplicity:
+// - There is no way to explicitly unregister listeners. The only way for a
+//   listener to unregister is by dying.
+// - There's only at most one listener at a given time. Attempting to register
+//   a second listener will cause a crash.
+// - This class isn't really meant to ever be destroyed. We expose a destructor
+//   because it is convenient to use this class as a global instance or a member
+//   of another class, but it will crash if destroyed while a listener is
+//   registered.
+//
+// All of these assumptions can be lifted if there is ever a need.
+//
+// This class is thread-safe.
+class CaptureStateNotifier {
+public:
+    // Ctor.
+    // Accepts the initial active state.
+    explicit CaptureStateNotifier(bool initialActive);
+
+    // Register a listener to be notified of state changes.
+    // The current state is returned and from that point on any change will be
+    // notified of.
+    bool RegisterListener(const sp<media::ICaptureStateListener>& listener);
+
+    // Change the current capture state.
+    // Active means "actively capturing".
+    void setCaptureState(bool active);
+
+    // Dtor. Do not actually call at runtime. Will cause a crash if a listener
+    // is registered.
+    ~CaptureStateNotifier();
+
+private:
+    std::mutex mMutex;
+    sp<media::ICaptureStateListener> mListener;
+    sp<IBinder::DeathRecipient> mDeathRecipient;
+    bool mActive;
+
+    class DeathRecipient;
+
+    void binderDied();
+};
+
+}  // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index af69466..e1721ea 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -94,6 +94,10 @@
         return NO_ERROR;
     }
 
+    void onAudioPortListUpdate() override {
+        ++mAudioPortListUpdateCount;
+    }
+
     // Helper methods for tests
     size_t getActivePatchesCount() const { return mActivePatches.size(); }
 
@@ -111,12 +115,15 @@
         mAllowedModuleNames.swap(names);
     }
 
+    size_t getAudioPortListUpdateCount() const { return mAudioPortListUpdateCount; }
+
 private:
     audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
     audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
     audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
     std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
     std::set<std::string> mAllowedModuleNames;
+    size_t mAudioPortListUpdateCount = 0;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 922a538..8bab020 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -29,6 +29,7 @@
     using AudioPolicyManager::getOutputs;
     using AudioPolicyManager::getAvailableOutputDevices;
     using AudioPolicyManager::getAvailableInputDevices;
+    uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
 };
 
 }  // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 7d92f34..a0074bc 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -104,8 +104,10 @@
             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);
+    // Tries to find a device port. If 'foundPort' isn't nullptr,
+    // will generate a failure if the port hasn't been found.
+    bool 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;
@@ -211,30 +213,36 @@
     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) {
+bool 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);
+    EXPECT_EQ(NO_ERROR, ret) << "mManager->listAudioPorts returned error";
+    if (HasFailure()) return false;
 
     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);
+    EXPECT_EQ(NO_ERROR, ret) << "mManager->listAudioPorts returned error";
+    EXPECT_EQ(generation1, generation2) << "Generations changed during ports retrieval";
+    if (HasFailure()) return false;
 
     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;
+            if (foundPort) *foundPort = port;
+            return true;
         }
     }
-    GTEST_FAIL() << "Device port with role " << role << " and address " << address << "not found";
+    if (foundPort) {
+        ADD_FAILURE() << "Device port with role " << role << " and address "
+                      << address << " not found";
+    }
+    return false;
 }
 
 audio_port_handle_t AudioPolicyManagerTest::getDeviceIdFromPatch(
@@ -694,8 +702,8 @@
     ASSERT_EQ(NO_ERROR, ret);
 
     struct audio_port extractionPort;
-    findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
-            mMixAddress, extractionPort);
+    ASSERT_TRUE(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;
@@ -707,8 +715,8 @@
     ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
     ASSERT_EQ(extractionPort.id, selectedDeviceId);
 
-    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-            mMixAddress, mInjectionPort);
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+                    mMixAddress, &mInjectionPort));
 }
 
 void AudioPolicyManagerTestDPPlaybackReRouting::TearDown() {
@@ -879,8 +887,8 @@
     ASSERT_EQ(NO_ERROR, ret);
 
     struct audio_port injectionPort;
-    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-            mMixAddress, injectionPort);
+    ASSERT_TRUE(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;
@@ -892,8 +900,8 @@
     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);
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+                    mMixAddress, &mExtractionPort));
 }
 
 void AudioPolicyManagerTestDPMixRecordInjection::TearDown() {
@@ -1028,7 +1036,7 @@
     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);
+    ASSERT_TRUE(findDevicePort(role, type, address, &devicePort));
 
     audio_port_handle_t routedPortId = devicePort.id;
     // Try start input or output according to the device type
@@ -1162,3 +1170,21 @@
     ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, mManager->getDeviceConnectionState(
                     AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0"));
 }
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, ListAddedAudioPorts) {
+    ASSERT_FALSE(
+            findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", nullptr));
+    mClient->swapAllowedModuleNames({"primary", "r_submix"});
+    mManager->onNewAudioModulesAvailable();
+    struct audio_port port;
+    ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", &port));
+}
+
+TEST_F(AudioPolicyManagerDynamicHwModulesTest, ClientIsUpdated) {
+    const size_t prevAudioPortListUpdateCount = mClient->getAudioPortListUpdateCount();
+    const uint32_t prevAudioPortGeneration = mManager->getAudioPortGeneration();
+    mClient->swapAllowedModuleNames({"primary", "r_submix"});
+    mManager->onNewAudioModulesAvailable();
+    EXPECT_GT(mClient->getAudioPortListUpdateCount(), prevAudioPortListUpdateCount);
+    EXPECT_GT(mManager->getAudioPortGeneration(), prevAudioPortGeneration);
+}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 9bc79e0..c9d2c68 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2742,7 +2742,7 @@
         mClientPackageName(clientPackageName),
         mClientPid(clientPid), mClientUid(clientUid),
         mServicePid(servicePid),
-        mDisconnected(false),
+        mDisconnected(false), mUidIsTrusted(false),
         mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE),
         mRemoteBinder(remoteCallback)
 {
@@ -2791,6 +2791,8 @@
     if (getCurrentServingCall() != BinderCallType::HWBINDER) {
         mAppOpsManager = std::make_unique<AppOpsManager>();
     }
+
+    mUidIsTrusted = isTrustedCallingUid(mClientUid);
 }
 
 CameraService::BasicClient::~BasicClient() {
@@ -2905,7 +2907,9 @@
             return PERMISSION_DENIED;
         }
 
-        if (res == AppOpsManager::MODE_IGNORED) {
+        // If the calling Uid is trusted (a native service), the AppOpsManager could
+        // return MODE_IGNORED. Do not treat such case as error.
+        if (!mUidIsTrusted && res == AppOpsManager::MODE_IGNORED) {
             ALOGI("Camera %s: Access for \"%s\" has been restricted",
                     mCameraIdStr.string(), String8(mClientPackageName).string());
             // Return the same error as for device policy manager rejection
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 1adf15a..18cf77a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -323,6 +323,7 @@
         const uid_t                     mClientUid;
         const pid_t                     mServicePid;
         bool                            mDisconnected;
+        bool                            mUidIsTrusted;
 
         mutable Mutex                   mAudioRestrictionLock;
         int32_t                         mAudioRestriction;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 1d62a74..ebb0555 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -733,6 +733,10 @@
 
     ALOGV("%s: state == %d, restart = %d", __FUNCTION__, params.state, restart);
 
+    if (params.state == Parameters::DISCONNECTED) {
+        ALOGE("%s: Camera %d has been disconnected.", __FUNCTION__, mCameraId);
+        return INVALID_OPERATION;
+    }
     if ( (params.state == Parameters::PREVIEW ||
                     params.state == Parameters::RECORD ||
                     params.state == Parameters::VIDEO_SNAPSHOT)
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 8f20685..237c24b 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -197,7 +197,9 @@
             return PERMISSION_DENIED;
         }
 
-        if (res == AppOpsManager::MODE_IGNORED) {
+        // If the calling Uid is trusted (a native service), the AppOpsManager could
+        // return MODE_IGNORED. Do not treat such case as error.
+        if (!mUidIsTrusted && res == AppOpsManager::MODE_IGNORED) {
             ALOGI("Offline Camera %s: Access for \"%s\" has been restricted",
                     mCameraIdStr.string(), String8(mClientPackageName).string());
             // Return the same error as for device policy manager rejection
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index cc369fa..32d118d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -841,13 +841,6 @@
         itDuration++; itSize++;
     }
 
-    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
-            dynamicDepthEntries.data(), dynamicDepthEntries.size());
-    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS,
-            dynamicDepthMinDurationEntries.data(), dynamicDepthMinDurationEntries.size());
-    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS,
-            dynamicDepthStallDurationEntries.data(), dynamicDepthStallDurationEntries.size());
-
     std::vector<int32_t> supportedChTags;
     supportedChTags.reserve(chTags.count + 3);
     supportedChTags.insert(supportedChTags.end(), chTags.data.i32,
@@ -855,6 +848,12 @@
     supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
     supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
     supportedChTags.push_back(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
+    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS,
+            dynamicDepthEntries.data(), dynamicDepthEntries.size());
+    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS,
+            dynamicDepthMinDurationEntries.data(), dynamicDepthMinDurationEntries.size());
+    c.update(ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS,
+            dynamicDepthStallDurationEntries.data(), dynamicDepthStallDurationEntries.size());
     c.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, supportedChTags.data(),
             supportedChTags.size());
 
@@ -950,6 +949,51 @@
     return res;
 }
 
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addPreCorrectionActiveArraySize() {
+    status_t res = OK;
+    auto& c = mCameraCharacteristics;
+
+    auto activeArraySize = c.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+    auto preCorrectionActiveArraySize = c.find(
+            ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+    if (activeArraySize.count == 4 && preCorrectionActiveArraySize.count == 0) {
+        std::vector<int32_t> preCorrectionArray(
+                activeArraySize.data.i32, activeArraySize.data.i32+4);
+        res = c.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+                preCorrectionArray.data(), 4);
+        if (res != OK) {
+            ALOGE("%s: Failed to add ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s(%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+    } else {
+        return res;
+    }
+
+    auto charTags = c.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+    bool hasPreCorrectionActiveArraySize = std::find(charTags.data.i32,
+            charTags.data.i32 + charTags.count,
+            ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE) !=
+            (charTags.data.i32 + charTags.count);
+    if (!hasPreCorrectionActiveArraySize) {
+        std::vector<int32_t> supportedCharTags;
+        supportedCharTags.reserve(charTags.count + 1);
+        supportedCharTags.insert(supportedCharTags.end(), charTags.data.i32,
+                charTags.data.i32 + charTags.count);
+        supportedCharTags.push_back(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+
+        res = c.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, supportedCharTags.data(),
+                supportedCharTags.size());
+        if (res != OK) {
+            ALOGE("%s: Failed to update ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS: %s(%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return res;
+        }
+    }
+
+    return res;
+}
+
 status_t CameraProviderManager::ProviderInfo::DeviceInfo3::removeAvailableKeys(
         CameraMetadata& c, const std::vector<uint32_t>& keys, uint32_t keyTag) {
     status_t res = OK;
@@ -2255,7 +2299,11 @@
         ALOGE("%s: Unable to add default SCALER_ROTATE_AND_CROP tags: %s (%d)", __FUNCTION__,
                 strerror(-res), res);
     }
-
+    res = addPreCorrectionActiveArraySize();
+    if (OK != res) {
+        ALOGE("%s: Unable to add PRE_CORRECTION_ACTIVE_ARRAY_SIZE: %s (%d)", __FUNCTION__,
+                strerror(-res), res);
+    }
     res = camera3::ZoomRatioMapper::overrideZoomRatioTags(
             &mCameraCharacteristics, &mSupportNativeZoomRatio);
     if (OK != res) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 50044d8..25d3639 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -566,6 +566,7 @@
             status_t addDynamicDepthTags();
             status_t deriveHeicTags();
             status_t addRotateCropTags();
+            status_t addPreCorrectionActiveArraySize();
 
             static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag,
                     android_pixel_format_t format,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 87bdef6..b00a2d9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -1722,6 +1722,13 @@
             return res;
         }
 
+        // Fill in JPEG_QUALITY if not available
+        if (!mRequestTemplateCache[templateId].exists(ANDROID_JPEG_QUALITY)) {
+            static const uint8_t kDefaultJpegQuality = 95;
+            mRequestTemplateCache[templateId].update(ANDROID_JPEG_QUALITY,
+                    &kDefaultJpegQuality, 1);
+        }
+
         *request = mRequestTemplateCache[templateId];
         mLastTemplateId = templateId;
     }
@@ -2337,6 +2344,21 @@
     }
 }
 
+bool Camera3Device::checkAbandonedStreamsLocked() {
+    if ((mInputStream.get() != nullptr) && (mInputStream->isAbandoned())) {
+        return true;
+    }
+
+    for (size_t i = 0; i < mOutputStreams.size(); i++) {
+        auto stream = mOutputStreams[i];
+        if ((stream.get() != nullptr) && (stream->isAbandoned())) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 bool Camera3Device::reconfigureCamera(const CameraMetadata& sessionParams) {
     ATRACE_CALL();
     bool ret = false;
@@ -2345,6 +2367,12 @@
     nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
 
     Mutex::Autolock l(mLock);
+    if (checkAbandonedStreamsLocked()) {
+        ALOGW("%s: Abandoned stream detected, session parameters can't be applied correctly!",
+                __FUNCTION__);
+        return true;
+    }
+
     auto rc = internalPauseAndWaitLocked(maxExpectedDuration);
     if (rc == NO_ERROR) {
         mNeedConfig = true;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index b373a64..19ecf4b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -648,6 +648,12 @@
     bool reconfigureCamera(const CameraMetadata& sessionParams);
 
     /**
+     * Return true in case of any output or input abandoned streams,
+     * otherwise return false.
+     */
+    bool checkAbandonedStreamsLocked();
+
+    /**
      * Filter stream session parameters and configure camera HAL.
      */
     status_t filterParamsAndConfigureLocked(const CameraMetadata& sessionParams,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 238356e..603f516 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -246,6 +246,8 @@
                 frameNumber);
         return;
     }
+    nsecs_t sensorTimestamp = timestamp.data.i64[0];
+
     for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
         camera_metadata_entry timestamp =
                 physicalMetadata.mPhysicalCameraMetadata.find(ANDROID_SENSOR_TIMESTAMP);
@@ -257,13 +259,15 @@
     }
 
     // Fix up some result metadata to account for HAL-level distortion correction
-    status_t res =
-            states.distortionMappers[states.cameraId.c_str()].correctCaptureResult(
-                    &captureResult.mMetadata);
-    if (res != OK) {
-        SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
-                frameNumber, strerror(-res), res);
-        return;
+    status_t res = OK;
+    auto iter = states.distortionMappers.find(states.cameraId.c_str());
+    if (iter != states.distortionMappers.end()) {
+        res = iter->second.correctCaptureResult(&captureResult.mMetadata);
+        if (res != OK) {
+            SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
+                    frameNumber, strerror(-res), res);
+            return;
+        }
     }
 
     // Fix up result metadata to account for zoom ratio availabilities between
@@ -337,7 +341,7 @@
                 CameraMetadata(m.mPhysicalCameraMetadata));
     }
     states.tagMonitor.monitorMetadata(TagMonitor::RESULT,
-            frameNumber, timestamp.data.i64[0], captureResult.mMetadata,
+            frameNumber, sensorTimestamp, captureResult.mMetadata,
             monitoredPhysicalMetadata);
 
     insertResultLocked(states, &captureResult, frameNumber);
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 84da45a..a87de77 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -243,10 +243,15 @@
             if (weight == 0) {
                 continue;
             }
-            // Top-left is inclusively clamped
-            scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, ClampInclusive);
-            // Bottom-right is exclusively clamped
-            scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, ClampExclusive);
+            // Top left (inclusive)
+            scaleCoordinates(entry.data.i32 + j, 1, zoomRatio, true /*clamp*/);
+            // Bottom right (exclusive): Use adjacent inclusive pixel to
+            // calculate.
+            entry.data.i32[j+2] -= 1;
+            entry.data.i32[j+3] -= 1;
+            scaleCoordinates(entry.data.i32 + j + 2, 1, zoomRatio, true /*clamp*/);
+            entry.data.i32[j+2] += 1;
+            entry.data.i32[j+3] += 1;
         }
     }
 
@@ -258,7 +263,7 @@
     if (isResult) {
         for (auto pts : kResultPointsToCorrectNoClamp) {
             entry = metadata->find(pts);
-            scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, ClampOff);
+            scaleCoordinates(entry.data.i32, entry.count / 2, zoomRatio, false /*clamp*/);
         }
     }
 
@@ -282,10 +287,15 @@
             if (weight == 0) {
                 continue;
             }
-            // Top-left is inclusively clamped
-            scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, ClampInclusive);
-            // Bottom-right is exclusively clamped
-            scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, ClampExclusive);
+            // Top-left (inclusive)
+            scaleCoordinates(entry.data.i32 + j, 1, 1.0 / zoomRatio, true /*clamp*/);
+            // Bottom-right (exclusive): Use adjacent inclusive pixel to
+            // calculate.
+            entry.data.i32[j+2] -= 1;
+            entry.data.i32[j+3] -= 1;
+            scaleCoordinates(entry.data.i32 + j + 2, 1, 1.0 / zoomRatio, true /*clamp*/);
+            entry.data.i32[j+2] += 1;
+            entry.data.i32[j+3] += 1;
         }
     }
     for (auto rect : kRectsToCorrect) {
@@ -295,7 +305,7 @@
     if (isResult) {
         for (auto pts : kResultPointsToCorrectNoClamp) {
             entry = metadata->find(pts);
-            scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, ClampOff);
+            scaleCoordinates(entry.data.i32, entry.count / 2, 1.0 / zoomRatio, false /*clamp*/);
         }
     }
 
@@ -309,28 +319,31 @@
 }
 
 void ZoomRatioMapper::scaleCoordinates(int32_t* coordPairs, int coordCount,
-        float scaleRatio, ClampMode clamp) {
+        float scaleRatio, bool clamp) {
+    // A pixel's coordinate is represented by the position of its top-left corner.
+    // To avoid the rounding error, we use the coordinate for the center of the
+    // pixel instead:
+    // 1. First shift the coordinate system half pixel both horizontally and
+    // vertically, so that [x, y] is the center of the pixel, not the top-left corner.
+    // 2. Do zoom operation to scale the coordinate relative to the center of
+    // the active array (shifted by 0.5 pixel as well).
+    // 3. Shift the coordinate system back by directly using the pixel center
+    // coordinate.
     for (int i = 0; i < coordCount * 2; i += 2) {
         float x = coordPairs[i];
         float y = coordPairs[i + 1];
-        float xCentered = x - mArrayWidth / 2;
-        float yCentered = y - mArrayHeight / 2;
+        float xCentered = x - (mArrayWidth - 2) / 2;
+        float yCentered = y - (mArrayHeight - 2) / 2;
         float scaledX = xCentered * scaleRatio;
         float scaledY = yCentered * scaleRatio;
-        scaledX += mArrayWidth / 2;
-        scaledY += mArrayHeight / 2;
+        scaledX += (mArrayWidth - 2) / 2;
+        scaledY += (mArrayHeight - 2) / 2;
+        coordPairs[i] = static_cast<int32_t>(std::round(scaledX));
+        coordPairs[i+1] = static_cast<int32_t>(std::round(scaledY));
         // Clamp to within activeArray/preCorrectionActiveArray
-        coordPairs[i] = static_cast<int32_t>(scaledX);
-        coordPairs[i+1] = static_cast<int32_t>(scaledY);
-        if (clamp != ClampOff) {
-            int32_t right, bottom;
-            if (clamp == ClampInclusive) {
-                right = mArrayWidth - 1;
-                bottom = mArrayHeight - 1;
-            } else {
-                right = mArrayWidth;
-                bottom = mArrayHeight;
-            }
+        if (clamp) {
+            int32_t right = mArrayWidth - 1;
+            int32_t bottom = mArrayHeight - 1;
             coordPairs[i] =
                     std::min(right, std::max(0, coordPairs[i]));
             coordPairs[i+1] =
@@ -343,25 +356,25 @@
 void ZoomRatioMapper::scaleRects(int32_t* rects, int rectCount,
         float scaleRatio) {
     for (int i = 0; i < rectCount * 4; i += 4) {
-        // Map from (l, t, width, height) to (l, t, r, b).
-        // [l, t] is inclusive, and [r, b] is exclusive.
+        // Map from (l, t, width, height) to (l, t, l+width-1, t+height-1),
+        // where both top-left and bottom-right are inclusive.
         int32_t coords[4] = {
             rects[i],
             rects[i + 1],
-            rects[i] + rects[i + 2],
-            rects[i + 1] + rects[i + 3]
+            rects[i] + rects[i + 2] - 1,
+            rects[i + 1] + rects[i + 3] - 1
         };
 
         // top-left
-        scaleCoordinates(coords, 1, scaleRatio, ClampInclusive);
+        scaleCoordinates(coords, 1, scaleRatio, true /*clamp*/);
         // bottom-right
-        scaleCoordinates(coords+2, 1, scaleRatio, ClampExclusive);
+        scaleCoordinates(coords+2, 1, scaleRatio, true /*clamp*/);
 
         // Map back to (l, t, width, height)
         rects[i] = coords[0];
         rects[i + 1] = coords[1];
-        rects[i + 2] = coords[2] - coords[0];
-        rects[i + 3] = coords[3] - coords[1];
+        rects[i + 2] = coords[2] - coords[0] + 1;
+        rects[i + 3] = coords[3] - coords[1] + 1;
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.h b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
index aa3d913..698f87f 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.h
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.h
@@ -65,14 +65,8 @@
     status_t updateCaptureResult(CameraMetadata *request, bool requestedZoomRatioIs1);
 
   public: // Visible for testing. Do not use concurently.
-    enum ClampMode {
-        ClampOff,
-        ClampInclusive,
-        ClampExclusive,
-    };
-
     void scaleCoordinates(int32_t* coordPairs, int coordCount,
-            float scaleRatio, ClampMode clamp);
+            float scaleRatio, bool clamp);
 
     bool isValid() { return mIsValid; }
   private:
diff --git a/services/camera/libcameraservice/tests/Android.mk b/services/camera/libcameraservice/tests/Android.mk
index fa5d69e..3ead715 100644
--- a/services/camera/libcameraservice/tests/Android.mk
+++ b/services/camera/libcameraservice/tests/Android.mk
@@ -48,6 +48,8 @@
 
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
+LOCAL_SANITIZE := address
+
 LOCAL_MODULE:= cameraservice_test
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_MODULE_TAGS := tests
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index a8f6889..855b5ab 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -40,8 +40,15 @@
  */
 struct TestDeviceInterface : public device::V3_2::ICameraDevice {
     std::vector<hardware::hidl_string> mDeviceNames;
+    android::hardware::hidl_vec<uint8_t> mCharacteristics;
+
+    TestDeviceInterface(std::vector<hardware::hidl_string> deviceNames,
+            android::hardware::hidl_vec<uint8_t> chars) :
+        mDeviceNames(deviceNames), mCharacteristics(chars) {}
+
     TestDeviceInterface(std::vector<hardware::hidl_string> deviceNames) :
         mDeviceNames(deviceNames) {}
+
     using getResourceCost_cb = std::function<void(
             hardware::camera::common::V1_0::Status status,
             const hardware::camera::common::V1_0::CameraResourceCost& resourceCost)>;
@@ -58,8 +65,7 @@
             const hardware::hidl_vec<uint8_t>& cameraCharacteristics)>;
     hardware::Return<void> getCameraCharacteristics(
             getCameraCharacteristics_cb _hidl_cb) override {
-        hardware::hidl_vec<uint8_t> cameraCharacteristics;
-        _hidl_cb(Status::OK, cameraCharacteristics);
+        _hidl_cb(Status::OK, mCharacteristics);
         return hardware::Void();
     }
 
@@ -100,6 +106,13 @@
         mDeviceInterface(new TestDeviceInterface(devices)),
         mVendorTagSections (vendorSection) {}
 
+    TestICameraProvider(const std::vector<hardware::hidl_string> &devices,
+            const hardware::hidl_vec<common::V1_0::VendorTagSection> &vendorSection,
+            android::hardware::hidl_vec<uint8_t> chars) :
+        mDeviceNames(devices),
+        mDeviceInterface(new TestDeviceInterface(devices, chars)),
+        mVendorTagSections (vendorSection) {}
+
     virtual hardware::Return<Status> setCallback(
             const sp<provider::V2_4::ICameraProviderCallback>& callbacks) override {
         mCalledCounter[SET_CALLBACK]++;
@@ -243,6 +256,52 @@
     void onNewProviderRegistered() override {}
 };
 
+TEST(CameraProviderManagerTest, InitializeDynamicDepthTest) {
+    std::vector<hardware::hidl_string> deviceNames;
+    deviceNames.push_back("device@3.2/test/0");
+    hardware::hidl_vec<common::V1_0::VendorTagSection> vendorSection;
+    status_t res;
+    sp<CameraProviderManager> providerManager = new CameraProviderManager();
+    sp<TestStatusListener> statusListener = new TestStatusListener();
+    TestInteractionProxy serviceProxy;
+
+    android::hardware::hidl_vec<uint8_t> chars;
+    CameraMetadata meta;
+    int32_t charKeys[] = { ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE,
+            ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS };
+    meta.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, charKeys,
+            sizeof(charKeys) / sizeof(charKeys[0]));
+    uint8_t depthIsExclusive = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE;
+    meta.update(ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE, &depthIsExclusive, 1);
+    int32_t sizes[] = { HAL_PIXEL_FORMAT_BLOB,
+            640, 480, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT };
+    meta.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, sizes,
+            sizeof(sizes) / sizeof(sizes[0]));
+    sizes[0] = HAL_PIXEL_FORMAT_Y16;
+    meta.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, sizes,
+            sizeof(sizes) / sizeof(sizes[0]));
+    int64_t durations[] = { HAL_PIXEL_FORMAT_BLOB, 640, 480, 0 };
+    meta.update(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, durations,
+            sizeof(durations) / sizeof(durations[0]));
+    meta.update(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, durations,
+            sizeof(durations) / sizeof(durations[0]));
+    durations[0]= HAL_PIXEL_FORMAT_Y16;
+    meta.update(ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS, durations,
+            sizeof(durations) / sizeof(durations[0]));
+    meta.update(ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS, durations,
+            sizeof(durations) / sizeof(durations[0]));
+    camera_metadata_t* metaBuffer = const_cast<camera_metadata_t*>(meta.getAndLock());
+    chars.setToExternal(reinterpret_cast<uint8_t*>(metaBuffer),
+            get_camera_metadata_size(metaBuffer));
+
+    sp<TestICameraProvider> provider =  new TestICameraProvider(deviceNames,
+            vendorSection, chars);
+    serviceProxy.setProvider(provider);
+
+    res = providerManager->initialize(statusListener, &serviceProxy);
+    ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+}
+
 TEST(CameraProviderManagerTest, InitializeTest) {
     std::vector<hardware::hidl_string> deviceNames;
     deviceNames.push_back("device@3.2/test/0");
diff --git a/services/camera/libcameraservice/tests/RotateAndCropMapperTest.cpp b/services/camera/libcameraservice/tests/RotateAndCropMapperTest.cpp
index c638d40..3c187cd 100644
--- a/services/camera/libcameraservice/tests/RotateAndCropMapperTest.cpp
+++ b/services/camera/libcameraservice/tests/RotateAndCropMapperTest.cpp
@@ -38,10 +38,9 @@
 
 #define EXPECT_EQUAL_WITHIN_N(vec, array, N, msg)   \
 { \
-    std::vector<int32_t> vec_diff; \
-    std::transform(vec.begin(), vec.end(), array, \
-            std::back_inserter(vec_diff), std::minus()); \
-    EXPECT_THAT(vec_diff, Each(AllOf(Ge(-N), Le(N)))) << msg; \
+    for (size_t i = 0; i < vec.size(); i++) { \
+        EXPECT_THAT(vec[i] - array[i], AllOf(Ge(-N), Le(N))) << msg " failed at index:" << i; \
+    } \
 }
 
 int32_t testActiveArray[] = {100, 100, 4000, 3000};
diff --git a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
index 300da09..4e94991 100644
--- a/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
+++ b/services/camera/libcameraservice/tests/ZoomRatioTest.cpp
@@ -171,35 +171,35 @@
 
     std::array<int32_t, 16> originalCoords = {
             0, 0, // top-left
-            width, 0, // top-right
-            0, height, // bottom-left
-            width, height, // bottom-right
-            width / 2, height / 2, // center
-            width / 4, height / 4, // top-left after 2x
-            width / 3, height * 2 / 3, // bottom-left after 3x zoom
-            width * 7 / 8, height / 2, // middle-right after 1.33x zoom
+            width - 1, 0, // top-right
+            0, height - 1, // bottom-left
+            width - 1, height - 1, // bottom-right
+            (width - 1) / 2, (height - 1) / 2, // center
+            (width - 1) / 4, (height - 1) / 4, // top-left after 2x
+            (width - 1) / 3, (height - 1) * 2 / 3, // bottom-left after 3x zoom
+            (width - 1) * 7 / 8, (height - 1) / 2, // middle-right after 1.33x zoom
     };
 
     // Verify 1.0x zoom doesn't change the coordinates
     auto coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f, ZoomRatioMapper::ClampOff);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f, false /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_EQ(coords[i], originalCoords[i]);
     }
 
     // Verify 2.0x zoom work as expected (no clamping)
     std::array<float, 16> expected2xCoords = {
-            - width / 2.0f, - height / 2.0f,// top-left
-            width * 3 / 2.0f, - height / 2.0f, // top-right
-            - width / 2.0f, height * 3 / 2.0f, // bottom-left
-            width * 3 / 2.0f, height * 3 / 2.0f, // bottom-right
-            width / 2.0f, height / 2.0f, // center
+            - (width - 1) / 2.0f, - (height - 1) / 2.0f,// top-left
+            (width - 1) * 3 / 2.0f, - (height - 1) / 2.0f, // top-right
+            - (width - 1) / 2.0f, (height - 1) * 3 / 2.0f, // bottom-left
+            (width - 1) * 3 / 2.0f, (height - 1) * 3 / 2.0f, // bottom-right
+            (width - 1) / 2.0f, (height - 1) / 2.0f, // center
             0, 0, // top-left after 2x
-            width / 6.0f, height - height / 6.0f, // bottom-left after 3x zoom
-            width + width / 4.0f, height / 2.0f, // middle-right after 1.33x zoom
+            (width - 1) / 6.0f, (height - 1) * 5.0f / 6.0f, // bottom-left after 3x zoom
+            (width - 1) * 5.0f / 4.0f, (height - 1) / 2.0f, // middle-right after 1.33x zoom
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampOff);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, false /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expected2xCoords[i]), kMaxAllowedPixelError);
     }
@@ -207,16 +207,16 @@
     // Verify 2.0x zoom work as expected (with inclusive clamping)
     std::array<float, 16> expected2xCoordsClampedInc = {
             0, 0, // top-left
-            static_cast<float>(width) - 1, 0, // top-right
-            0, static_cast<float>(height) - 1, // bottom-left
-            static_cast<float>(width) - 1, static_cast<float>(height) - 1, // bottom-right
-            width / 2.0f, height / 2.0f, // center
+            width - 1.0f, 0, // top-right
+            0, height - 1.0f, // bottom-left
+            width - 1.0f, height - 1.0f, // bottom-right
+            (width - 1) / 2.0f, (height - 1) / 2.0f, // center
             0, 0, // top-left after 2x
-            width / 6.0f, height - height / 6.0f , // bottom-left after 3x zoom
-            static_cast<float>(width) - 1,  height / 2.0f, // middle-right after 1.33x zoom
+            (width - 1) / 6.0f, (height - 1) * 5.0f / 6.0f , // bottom-left after 3x zoom
+            width - 1.0f,  (height - 1) / 2.0f, // middle-right after 1.33x zoom
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampInclusive);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedInc[i]), kMaxAllowedPixelError);
     }
@@ -224,33 +224,33 @@
     // Verify 2.0x zoom work as expected (with exclusive clamping)
     std::array<float, 16> expected2xCoordsClampedExc = {
             0, 0, // top-left
-            static_cast<float>(width), 0, // top-right
-            0, static_cast<float>(height), // bottom-left
-            static_cast<float>(width), static_cast<float>(height), // bottom-right
+            width - 1.0f, 0, // top-right
+            0, height - 1.0f, // bottom-left
+            width - 1.0f, height - 1.0f, // bottom-right
             width / 2.0f, height / 2.0f, // center
             0, 0, // top-left after 2x
-            width / 6.0f, height - height / 6.0f , // bottom-left after 3x zoom
-            static_cast<float>(width),  height / 2.0f, // middle-right after 1.33x zoom
+            (width - 1) / 6.0f, (height - 1) * 5.0f / 6.0f , // bottom-left after 3x zoom
+            width - 1.0f,  height / 2.0f, // middle-right after 1.33x zoom
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, ZoomRatioMapper::ClampExclusive);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 2.0f, true /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expected2xCoordsClampedExc[i]), kMaxAllowedPixelError);
     }
 
     // Verify 0.33x zoom work as expected
     std::array<float, 16> expectedZoomOutCoords = {
-            width / 3.0f, height / 3.0f, // top-left
-            width * 2 / 3.0f, height / 3.0f, // top-right
-            width / 3.0f, height * 2 / 3.0f, // bottom-left
-            width * 2 / 3.0f, height * 2 / 3.0f, // bottom-right
-            width / 2.0f, height / 2.0f, // center
-            width * 5 / 12.0f, height * 5 / 12.0f, // top-left after 2x
-            width * 4 / 9.0f, height * 5 / 9.0f, // bottom-left after 3x zoom-in
-            width * 5 / 8.0f, height / 2.0f, // middle-right after 1.33x zoom-in
+            (width - 1) / 3.0f, (height - 1) / 3.0f, // top-left
+            (width - 1) * 2 / 3.0f, (height - 1) / 3.0f, // top-right
+            (width - 1) / 3.0f, (height - 1) * 2 / 3.0f, // bottom-left
+            (width - 1) * 2 / 3.0f, (height - 1) * 2 / 3.0f, // bottom-right
+            (width - 1) / 2.0f, (height - 1) / 2.0f, // center
+            (width - 1) * 5 / 12.0f, (height - 1) * 5 / 12.0f, // top-left after 2x
+            (width - 1) * 4 / 9.0f, (height - 1) * 5 / 9.0f, // bottom-left after 3x zoom-in
+            (width - 1) * 5 / 8.0f, (height - 1) / 2.0f, // middle-right after 1.33x zoom-in
     };
     coords = originalCoords;
-    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f/3, ZoomRatioMapper::ClampOff);
+    mapper.scaleCoordinates(coords.data(), coords.size()/2, 1.0f/3, false /*clamp*/);
     for (size_t i = 0; i < coords.size(); i++) {
         EXPECT_LE(std::abs(coords[i] - expectedZoomOutCoords[i]), kMaxAllowedPixelError);
     }
@@ -323,7 +323,8 @@
     entry = metadata.find(ANDROID_SCALER_CROP_REGION);
     ASSERT_EQ(entry.count, 4U);
     for (int i = 0; i < 4; i++) {
-        EXPECT_EQ(entry.data.i32[i], testDefaultCropSize[index][i]);
+        EXPECT_LE(std::abs(entry.data.i32[i] - testDefaultCropSize[index][i]),
+                kMaxAllowedPixelError);
     }
     entry = metadata.find(ANDROID_CONTROL_ZOOM_RATIO);
     EXPECT_NEAR(entry.data.f[0], 2.0f, kMaxAllowedRatioError);
@@ -335,7 +336,7 @@
     entry = metadata.find(ANDROID_SCALER_CROP_REGION);
     ASSERT_EQ(entry.count, 4U);
     for (int i = 0; i < 4; i++) {
-        EXPECT_EQ(entry.data.i32[i], test2xCropRegion[index][i]);
+        EXPECT_LE(std::abs(entry.data.i32[i] - test2xCropRegion[index][i]), kMaxAllowedPixelError);
     }
 
     // Letter boxing crop region, zoomRatio is 1.0
diff --git a/services/mediacodec/registrant/CodecServiceRegistrant.cpp b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
index 83d233e..184251a 100644
--- a/services/mediacodec/registrant/CodecServiceRegistrant.cpp
+++ b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
@@ -17,11 +17,13 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "CodecServiceRegistrant"
 
+#include <android-base/properties.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 
 #include <C2Component.h>
 #include <C2PlatformSupport.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
 #include <codec2/hidl/1.1/ComponentStore.h>
 #include <codec2/hidl/1.1/Configurable.h>
 #include <codec2/hidl/1.1/types.h>
@@ -43,6 +45,10 @@
 // Converter from IComponentStore to C2ComponentStore.
 class H2C2ComponentStore : public C2ComponentStore {
 protected:
+    using IComponentStore =
+        ::android::hardware::media::c2::V1_0::IComponentStore;
+    using IConfigurable =
+        ::android::hardware::media::c2::V1_0::IConfigurable;
     sp<IComponentStore> mStore;
     sp<IConfigurable> mConfigurable;
 public:
@@ -399,36 +405,67 @@
 } // unnamed namespace
 
 extern "C" void RegisterCodecServices() {
-    using namespace ::android::hardware::media::c2::V1_1;
     LOG(INFO) << "Creating software Codec2 service...";
-    sp<ComponentStore> store =
-        new ComponentStore(::android::GetCodec2PlatformComponentStore());
-    if (store == nullptr) {
-        LOG(ERROR) <<
-                "Cannot create software Codec2 service.";
-    } else {
-        if (!ionPropertiesDefined()) {
-            std::string preferredStoreName = "default";
-            sp<IComponentStore> preferredStore =
-                IComponentStore::getService(preferredStoreName.c_str());
-            if (preferredStore) {
-                ::android::SetPreferredCodec2ComponentStore(
-                        std::make_shared<H2C2ComponentStore>(preferredStore));
-                LOG(INFO) <<
-                        "Preferred Codec2 store is set to \"" <<
-                        preferredStoreName << "\".";
-            } else {
-                LOG(INFO) <<
-                        "Preferred Codec2 store is defaulted to \"software\".";
+    std::shared_ptr<C2ComponentStore> store =
+        android::GetCodec2PlatformComponentStore();
+    if (!store) {
+        LOG(ERROR) << "Failed to create Codec2 service.";
+        return;
+    }
+
+    using namespace ::android::hardware::media::c2;
+
+    int platformVersion =
+        android::base::GetIntProperty("ro.build.version.sdk", int32_t(29));
+    // STOPSHIP: Remove code name checking once platform version bumps up to 30.
+    std::string codeName =
+        android::base::GetProperty("ro.build.version.codename", "");
+    if (codeName == "R") {
+        platformVersion = 30;
+    }
+
+    switch (platformVersion) {
+        case 30: {
+            android::sp<V1_1::IComponentStore> storeV1_1 =
+                new V1_1::utils::ComponentStore(store);
+            if (storeV1_1->registerAsService("software") != android::OK) {
+                LOG(ERROR) << "Cannot register software Codec2 v1.1 service.";
+                return;
             }
+            break;
         }
-        if (store->registerAsService("software") != android::OK) {
-            LOG(ERROR) <<
-                    "Cannot register software Codec2 service.";
-        } else {
-            LOG(INFO) <<
-                    "Software Codec2 service created.";
+        case 29: {
+            android::sp<V1_0::IComponentStore> storeV1_0 =
+                new V1_0::utils::ComponentStore(store);
+            if (storeV1_0->registerAsService("software") != android::OK) {
+                LOG(ERROR) << "Cannot register software Codec2 v1.0 service.";
+                return;
+            }
+            break;
+        }
+        default: {
+            LOG(ERROR) << "The platform version " << platformVersion <<
+                          " is not supported.";
+            return;
         }
     }
+    if (!ionPropertiesDefined()) {
+        using IComponentStore =
+            ::android::hardware::media::c2::V1_0::IComponentStore;
+        std::string const preferredStoreName = "default";
+        sp<IComponentStore> preferredStore =
+            IComponentStore::getService(preferredStoreName.c_str());
+        if (preferredStore) {
+            ::android::SetPreferredCodec2ComponentStore(
+                    std::make_shared<H2C2ComponentStore>(preferredStore));
+            LOG(INFO) <<
+                    "Preferred Codec2 store is set to \"" <<
+                    preferredStoreName << "\".";
+        } else {
+            LOG(INFO) <<
+                    "Preferred Codec2 store is defaulted to \"software\".";
+        }
+    }
+    LOG(INFO) << "Software Codec2 service created and registered.";
 }
 
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 548b7f6..0b25d62 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -29,6 +29,7 @@
     shared_libs: [
         "libmedia",
         "libmediaextractorservice",
+        "libmediautils",
         "libbinder",
         "libutils",
         "liblog",
@@ -50,8 +51,6 @@
     },
     init_rc: ["mediaextractor.rc"],
 
-    include_dirs: ["frameworks/av/media/libmedia"],
-
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index afb7692..f21574f 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -21,7 +21,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
-
+#include <mediautils/LimitProcessMemory.h>
 #include <string>
 
 #include <android-base/logging.h>
@@ -32,7 +32,6 @@
 
 // from LOCAL_C_INCLUDES
 #include "MediaExtractorService.h"
-#include "MediaUtils.h"
 #include "minijail.h"
 
 using namespace android;
diff --git a/services/mediametrics/AnalyticsActions.h b/services/mediametrics/AnalyticsActions.h
index 5568c91..897e567 100644
--- a/services/mediametrics/AnalyticsActions.h
+++ b/services/mediametrics/AnalyticsActions.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <android-base/thread_annotations.h>
 #include <media/MediaMetricsItem.h>
 #include <mutex>
 
@@ -77,8 +78,8 @@
     template <typename T, typename U, typename A>
     void addAction(T&& url, U&& value, A&& action) {
         std::lock_guard l(mLock);
-        mFilters[ { std::forward<T>(url), std::forward<U>(value) } ]
-                = std::forward<A>(action);
+        mFilters.emplace(Trigger{ std::forward<T>(url), std::forward<U>(value) },
+                std::forward<A>(action));
     }
 
     // TODO: remove an action.
@@ -93,36 +94,15 @@
         std::vector<Action> actions;
         std::lock_guard l(mLock);
 
-        // Essentially the code looks like this:
-        /*
-        for (auto &[trigger, action] : mFilters) {
-            if (isMatch(trigger, item)) {
-                actions.push_back(action);
-            }
-        }
-        */
-
-        // Optimization: there should only be one match for a non-wildcard url.
-        auto it = mFilters.upper_bound( {item->getKey(), std::monostate{} });
-        if (it != mFilters.end()) {
-            const auto &[trigger, action] = *it;
-            if (isMatch(trigger, item)) {
+        for (const auto &[trigger, action] : mFilters) {
+            if (isWildcardMatch(trigger, item) ==
+                    mediametrics::Item::RECURSIVE_WILDCARD_CHECK_MATCH_FOUND) {
                 actions.push_back(action);
             }
         }
 
-        // Optimization: for wildcard URLs we go backwards until there is no
-        // match with the prefix before the wildcard.
-        while (it != mFilters.begin()) {  // this walks backwards, cannot start at begin.
-            const auto &[trigger, action] = *--it;  // look backwards
-            int ret = isWildcardMatch(trigger, item);
-            if (ret == mediametrics::Item::RECURSIVE_WILDCARD_CHECK_MATCH_FOUND) {
-                actions.push_back(action);    // match found.
-            } else if (ret == mediametrics::Item::RECURSIVE_WILDCARD_CHECK_NO_MATCH_NO_WILDCARD) {
-                break;                        // no match before wildcard.
-            }
-            // a wildcard was encountered when matching prefix, so we should check again.
-        }
+        // TODO: Optimize for prefix search and wildcarding.
+
         return actions;
     }
 
@@ -144,7 +124,9 @@
     }
 
     mutable std::mutex mLock;
-    std::map<Trigger, Action> mFilters; // GUARDED_BY mLock
+
+    using FilterType = std::multimap<Trigger, Action>;
+    FilterType mFilters GUARDED_BY(mLock);
 };
 
 } // namespace android::mediametrics
diff --git a/services/mediametrics/AnalyticsState.h b/services/mediametrics/AnalyticsState.h
index 290ed21..b648947 100644
--- a/services/mediametrics/AnalyticsState.h
+++ b/services/mediametrics/AnalyticsState.h
@@ -84,8 +84,11 @@
      * delivered.
      *
      * \param lines the maximum number of lines in the string returned.
+     * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+     * \param prefix the desired key prefix to match (nullptr shows all)
      */
-    std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const {
+    std::pair<std::string, int32_t> dump(
+            int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const {
         std::stringstream ss;
         int32_t ll = lines;
 
@@ -94,7 +97,7 @@
             --ll;
         }
         if (ll > 0) {
-            auto [s, l] = mTransactionLog.dump(ll);
+            auto [s, l] = mTransactionLog.dump(ll, sinceNs, prefix);
             ss << s;
             ll -= l;
         }
@@ -103,7 +106,7 @@
             --ll;
         }
         if (ll > 0) {
-            auto [s, l] = mTimeMachine.dump(ll);
+            auto [s, l] = mTimeMachine.dump(ll, sinceNs, prefix);
             ss << s;
             ll -= l;
         }
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index ec59ec1..8e5bc79 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -27,6 +27,7 @@
         "-Wall",
         "-Werror",
         "-Wextra",
+        "-Wthread-safety",
     ],
 }
 
@@ -57,6 +58,7 @@
         "liblog",
         "libmediametrics",
         "libmediautils",
+        "libmemunreachable",
         "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
@@ -74,5 +76,6 @@
         "-Wall",
         "-Werror",
         "-Wextra",
+        "-Wthread-safety",
     ],
 }
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 126e501..fe3a34d 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -19,8 +19,12 @@
 #include <utils/Log.h>
 
 #include "AudioAnalytics.h"
+#include "MediaMetricsService.h"  // package info
+#include <audio_utils/clock.h>    // clock conversions
+#include <statslog.h>             // statsd
 
-#include <audio_utils/clock.h>                 // clock conversions
+// Enable for testing of delivery to statsd
+// #define STATSD
 
 namespace android::mediametrics {
 
@@ -87,11 +91,53 @@
                     // report this for Bluetooth
                 }
             }));
+
+    // Handle device use thread statistics
+    mActions.addAction(
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
+        std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
+        std::make_shared<AnalyticsActions::Function>(
+            [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+                mDeviceUse.endAudioIntervalGroup(item, false /* isTrack */);
+            }));
+
+    // Handle device use track statistics
+    mActions.addAction(
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_EVENT,
+        std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP),
+        std::make_shared<AnalyticsActions::Function>(
+            [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+                mDeviceUse.endAudioIntervalGroup(item, true /* isTrack */);
+            }));
+
+    // Handle device routing statistics
+
+    // We track connections (not disconnections) for the time to connect.
+    // TODO: consider BT requests in their A2dp service
+    // AudioManager.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
+    // AudioDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
+    // AudioDeviceBroker.postA2dpActiveDeviceChange
+    mActions.addAction(
+        "audio.device.a2dp.state",
+        std::string("connected"),
+        std::make_shared<AnalyticsActions::Function>(
+            [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+                mDeviceConnection.a2dpConnected(item);
+            }));
+    // If audio is active, we expect to see a createAudioPatch after the device is connected.
+    mActions.addAction(
+        AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT,
+        std::string("createAudioPatch"),
+        std::make_shared<AnalyticsActions::Function>(
+            [this](const std::shared_ptr<const android::mediametrics::Item> &item){
+                mDeviceConnection.createPatch(item);
+            }));
 }
 
 AudioAnalytics::~AudioAnalytics()
 {
     ALOGD("%s", __func__);
+    mTimedAction.quit(); // ensure no deferred access during destructor.
 }
 
 status_t AudioAnalytics::submit(
@@ -107,13 +153,14 @@
     return NO_ERROR;
 }
 
-std::pair<std::string, int32_t> AudioAnalytics::dump(int32_t lines) const
+std::pair<std::string, int32_t> AudioAnalytics::dump(
+        int32_t lines, int64_t sinceNs, const char *prefix) const
 {
     std::stringstream ss;
     int32_t ll = lines;
 
     if (ll > 0) {
-        auto [s, l] = mAnalyticsState->dump(ll);
+        auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
         ss << s;
         ll -= l;
     }
@@ -122,7 +169,7 @@
         --ll;
     }
     if (ll > 0) {
-        auto [s, l] = mPreviousAnalyticsState->dump(ll);
+        auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
         ss << s;
         ll -= l;
     }
@@ -150,4 +197,220 @@
     return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32);
 }
 
+// DeviceUse helper class.
+void AudioAnalytics::DeviceUse::endAudioIntervalGroup(
+       const std::shared_ptr<const android::mediametrics::Item> &item, bool isTrack) const {
+    const std::string& key = item->getKey();
+    const std::string id = key.substr(
+            (isTrack ? sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
+            : sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD))
+             - 1);
+    // deliver statistics
+    int64_t deviceTimeNs = 0;
+    mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            key, AMEDIAMETRICS_PROP_DEVICETIMENS, &deviceTimeNs);
+    std::string encoding;
+    mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            key, AMEDIAMETRICS_PROP_ENCODING, &encoding);
+    int32_t frameCount = 0;
+    mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            key, AMEDIAMETRICS_PROP_FRAMECOUNT, &frameCount);
+    int32_t intervalCount = 0;
+    mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            key, AMEDIAMETRICS_PROP_INTERVALCOUNT, &intervalCount);
+    std::string outputDevices;
+    mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            key, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
+    int32_t sampleRate = 0;
+    mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            key, AMEDIAMETRICS_PROP_SAMPLERATE, &sampleRate);
+    int32_t underrun = 0;
+    mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            key, AMEDIAMETRICS_PROP_UNDERRUN, &underrun);
+
+    // Get connected device name if from bluetooth.
+    bool isBluetooth = false;
+    std::string name;
+    if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
+        isBluetooth = true;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+            "audio.device.bt_a2dp", AMEDIAMETRICS_PROP_NAME, &name);
+    }
+
+    // We may have several devices.  We only list the first device.
+    // TODO: consider whether we should list all the devices separated by |
+    std::string firstDevice = "unknown";
+    auto devaddrvec = MediaMetricsService::getDeviceAddressPairs(outputDevices);
+    if (devaddrvec.size() != 0) {
+        firstDevice = devaddrvec[0].first;
+        // DO NOT show the address.
+    }
+
+    if (isTrack) {
+        std::string callerName;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_CALLERNAME, &callerName);
+        std::string contentType;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_CONTENTTYPE, &contentType);
+        double deviceLatencyMs = 0.;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_DEVICELATENCYMS, &deviceLatencyMs);
+        double deviceStartupMs = 0.;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_DEVICESTARTUPMS, &deviceStartupMs);
+        double deviceVolume = 0.;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_DEVICEVOLUME, &deviceVolume);
+        std::string packageName;
+        int64_t versionCode = 0;
+        int32_t uid = -1;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_ALLOWUID, &uid);
+        if (uid != -1) {
+            std::tie(packageName, versionCode) =
+                    MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
+        }
+        double playbackPitch = 0.;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_PLAYBACK_PITCH, &playbackPitch);
+        double playbackSpeed = 0.;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_PLAYBACK_SPEED, &playbackSpeed);
+        int32_t selectedDeviceId = 0;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_SELECTEDDEVICEID, &selectedDeviceId);
+
+        std::string usage;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_USAGE, &usage);
+
+        ALOGD("(key=%s) id:%s endAudioIntervalGroup device:%s name:%s "
+                 "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
+                 "sampleRate:%d underrun:%d "
+                 "callerName:%s contentType:%s "
+                 "deviceLatencyMs:%lf deviceStartupMs:%lf deviceVolume:%lf"
+                 "packageName:%s playbackPitch:%lf playbackSpeed:%lf "
+                 "selectedDevceId:%d usage:%s",
+                key.c_str(), id.c_str(), firstDevice.c_str(), name.c_str(),
+                (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
+                sampleRate, underrun,
+                callerName.c_str(), contentType.c_str(),
+                deviceLatencyMs, deviceStartupMs, deviceVolume,
+                packageName.c_str(), playbackPitch, playbackSpeed,
+                selectedDeviceId, usage.c_str());
+#ifdef STATSD
+        if (mAudioAnalytics.mDeliverStatistics) {
+            (void)android::util::stats_write(
+                    android::util::MEDIAMETRICS_AUDIOTRACKDEVICEUSAGE_REPORTED
+                    /* timestamp, */
+                    /* mediaApexVersion, */
+                    , firstDevice.c_str()
+                    , name.c_str()
+                    , deviceTimeNs
+                    , encoding.c_str()
+                    , frameCount
+                    , intervalCount
+                    , sampleRate
+                    , underrun
+
+                    , packageName.c_str()
+                    , (float)deviceLatencyMs
+                    , (float)deviceStartupMs
+                    , (float)deviceVolume
+                    , selectedDeviceId
+                    , usage.c_str()
+                    , contentType.c_str()
+                    , callerName.c_str()
+                    );
+        }
+#endif
+    } else {
+
+        std::string flags;
+        mAudioAnalytics.mAnalyticsState->timeMachine().get(
+                key, AMEDIAMETRICS_PROP_FLAGS, &flags);
+
+        ALOGD("(key=%s) id:%s endAudioIntervalGroup device:%s name:%s "
+                 "deviceTimeNs:%lld encoding:%s frameCount:%d intervalCount:%d "
+                 "sampleRate:%d underrun:%d "
+                 "flags:%s",
+                key.c_str(), id.c_str(), firstDevice.c_str(), name.c_str(),
+                (long long)deviceTimeNs, encoding.c_str(), frameCount, intervalCount,
+                sampleRate, underrun,
+                flags.c_str());
+#ifdef STATSD
+        if (mAudioAnalytics.mDeliverStatistics) {
+            (void)android::util::stats_write(
+                android::util::MEDIAMETRICS_AUDIOTHREADDEVICEUSAGE_REPORTED
+                /* timestamp, */
+                /* mediaApexVersion, */
+                , firstDevice.c_str()
+                , name.c_str()
+                , deviceTimeNs
+                , encoding.c_str()
+                , frameCount
+                , intervalCount
+                , sampleRate
+                , underrun
+            );
+        }
+#endif
+    }
+
+    // Report this as needed.
+    if (isBluetooth) {
+        // report this for Bluetooth
+    }
+}
+
+// DeviceConnection helper class.
+void AudioAnalytics::DeviceConnection::a2dpConnected(
+       const std::shared_ptr<const android::mediametrics::Item> &item) {
+    const std::string& key = item->getKey();
+
+    const int64_t connectedAtNs = item->getTimestamp();
+    {
+        std::lock_guard l(mLock);
+        mA2dpTimeConnectedNs = connectedAtNs;
+         ++mA2dpConnectedAttempts;
+    }
+    std::string name;
+    item->get(AMEDIAMETRICS_PROP_NAME, &name);
+    ALOGD("(key=%s) a2dp connected device:%s "
+             "connectedAtNs:%lld",
+            key.c_str(), name.c_str(),
+            (long long)connectedAtNs);
+    // Note - we need to be able to cancel a timed event
+    mAudioAnalytics.mTimedAction.postIn(std::chrono::seconds(5), [this](){ expire(); });
+    // This sets the time we were connected.  Now we look for the delta in the future.
+}
+
+void AudioAnalytics::DeviceConnection::createPatch(
+       const std::shared_ptr<const android::mediametrics::Item> &item) {
+    std::lock_guard l(mLock);
+    if (mA2dpTimeConnectedNs == 0) return; // ignore
+    const std::string& key = item->getKey();
+    std::string outputDevices;
+    item->get(AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices);
+    if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) {
+        // TODO compare address
+        const int64_t timeDiff = item->getTimestamp() - mA2dpTimeConnectedNs;
+        ALOGD("(key=%s) A2DP device connection time: %lld", key.c_str(), (long long)timeDiff);
+        mA2dpTimeConnectedNs = 0; // reset counter.
+        ++mA2dpConnectedSuccesses;
+    }
+}
+
+void AudioAnalytics::DeviceConnection::expire() {
+    std::lock_guard l(mLock);
+    if (mA2dpTimeConnectedNs == 0) return; // ignore
+
+    // An expiration may occur because there is no audio playing.
+    // TODO: disambiguate this case.
+    ALOGD("A2DP device connection expired");
+    ++mA2dpConnectedFailures; // this is not a true failure.
+    mA2dpTimeConnectedNs = 0;
+}
+
 } // namespace android
diff --git a/services/mediametrics/AudioAnalytics.h b/services/mediametrics/AudioAnalytics.h
index 4a42e22..eb9c228 100644
--- a/services/mediametrics/AudioAnalytics.h
+++ b/services/mediametrics/AudioAnalytics.h
@@ -16,8 +16,10 @@
 
 #pragma once
 
+#include <android-base/thread_annotations.h>
 #include "AnalyticsActions.h"
 #include "AnalyticsState.h"
+#include "TimedAction.h"
 #include "Wrap.h"
 
 namespace android::mediametrics {
@@ -60,8 +62,17 @@
      * delivered.
      *
      * \param lines the maximum number of lines in the string returned.
+     * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+     * \param prefix the desired key prefix to match (nullptr shows all)
      */
-    std::pair<std::string, int32_t> dump(int32_t lines = INT32_MAX) const;
+    std::pair<std::string, int32_t> dump(
+            int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const;
+
+    void clear() {
+        // underlying state is locked.
+        mPreviousAnalyticsState->clear();
+        mAnalyticsState->clear();
+    }
 
 private:
 
@@ -80,6 +91,8 @@
      */
     std::string getThreadFromTrack(const std::string& track) const;
 
+    const bool mDeliverStatistics __unused = true;
+
     // Actions is individually locked
     AnalyticsActions mActions;
 
@@ -88,6 +101,54 @@
 
     SharedPtrWrap<AnalyticsState> mAnalyticsState;
     SharedPtrWrap<AnalyticsState> mPreviousAnalyticsState;
+
+    TimedAction mTimedAction; // locked internally
+
+    // DeviceUse is a nested class which handles audio device usage accounting.
+    // We define this class at the end to ensure prior variables all properly constructed.
+    // TODO: Track / Thread interaction
+    // TODO: Consider statistics aggregation.
+    class DeviceUse {
+    public:
+        explicit DeviceUse(AudioAnalytics &audioAnalytics) : mAudioAnalytics{audioAnalytics} {}
+
+        // Called every time an endAudioIntervalGroup message is received.
+        void endAudioIntervalGroup(
+                const std::shared_ptr<const android::mediametrics::Item> &item,
+                bool isTrack) const;
+    private:
+        AudioAnalytics &mAudioAnalytics;
+    } mDeviceUse{*this};
+
+    // DeviceConnected is a nested class which handles audio device connection
+    // We define this class at the end to ensure prior variables all properly constructed.
+    // TODO: Track / Thread interaction
+    // TODO: Consider statistics aggregation.
+    class DeviceConnection {
+    public:
+        explicit DeviceConnection(AudioAnalytics &audioAnalytics)
+            : mAudioAnalytics{audioAnalytics} {}
+
+        // Called every time an endAudioIntervalGroup message is received.
+        void a2dpConnected(
+                const std::shared_ptr<const android::mediametrics::Item> &item);
+
+        // Called when we have an AudioFlinger createPatch
+        void createPatch(
+                const std::shared_ptr<const android::mediametrics::Item> &item);
+
+        // When the timer expires.
+        void expire();
+
+    private:
+        AudioAnalytics &mAudioAnalytics;
+
+        mutable std::mutex mLock;
+        int64_t mA2dpTimeConnectedNs GUARDED_BY(mLock) = 0;
+        int32_t mA2dpConnectedAttempts GUARDED_BY(mLock) = 0;
+        int32_t mA2dpConnectedSuccesses GUARDED_BY(mLock) = 0;
+        int32_t mA2dpConnectedFailures GUARDED_BY(mLock) = 0;
+    } mDeviceConnection{*this};
 };
 
 } // namespace android::mediametrics
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index a6fefd2..3b3dc3e 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -26,6 +26,8 @@
 #include <audio_utils/clock.h>                 // clock conversions
 #include <binder/IPCThreadState.h>             // get calling uid
 #include <cutils/properties.h>                 // for property_get
+#include <mediautils/MemoryLeakTrackUtil.h>
+#include <memunreachable/memunreachable.h>
 #include <private/android_filesystem_config.h> // UID
 
 namespace android {
@@ -76,6 +78,74 @@
     }
 }
 
+/* static */
+std::pair<std::string, int64_t>
+MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid_t uid) {
+    // Meyer's singleton, initialized on first access.
+    // mUidInfo is locked internally.
+    static mediautils::UidInfo uidInfo;
+
+    // get info.
+    mediautils::UidInfo::Info info = uidInfo.getInfo(uid);
+    if (useUidForPackage(info.package, info.installer)) {
+        return { std::to_string(uid), /* versionCode */ 0 };
+    } else {
+        return { info.package, info.versionCode };
+    }
+}
+
+/* static */
+std::string MediaMetricsService::tokenizer(std::string::const_iterator& it,
+        const std::string::const_iterator& end, const char *reserved) {
+    // consume leading white space
+    for (; it != end && std::isspace(*it); ++it);
+    if (it == end) return {};
+
+    auto start = it;
+    // parse until we hit a reserved keyword or space
+    if (strchr(reserved, *it)) return {start, ++it};
+    for (;;) {
+        ++it;
+        if (it == end || std::isspace(*it) || strchr(reserved, *it)) return {start, it};
+    }
+}
+
+/* static */
+std::vector<std::pair<std::string, std::string>>
+MediaMetricsService::getDeviceAddressPairs(const std::string& devices) {
+    std::vector<std::pair<std::string, std::string>> result;
+
+    // Currently, the device format is EXACTLY
+    // (device1, addr1)|(device2, addr2)|...
+
+    static constexpr char delim[] = "()|,";
+    for (auto it = devices.begin(); ; ) {
+        auto token = tokenizer(it, devices.end(), delim);
+        if (token != "(") return result;
+
+        auto device = tokenizer(it, devices.end(), delim);
+        if (device.empty() || !std::isalnum(device[0])) return result;
+
+        token = tokenizer(it, devices.end(), delim);
+        if (token != ",") return result;
+
+        // special handling here for empty addresses
+        auto address = tokenizer(it, devices.end(), delim);
+        if (address.empty() || !std::isalnum(device[0])) return result;
+        if (address == ")") {  // no address, just the ")"
+            address.clear();
+        } else {
+            token = tokenizer(it, devices.end(), delim);
+            if (token != ")") return result;
+        }
+
+        result.emplace_back(std::move(device), std::move(address));
+
+        token = tokenizer(it, devices.end(), delim);
+        if (token != "|") return result;  // this includes end of string detection
+    }
+}
+
 MediaMetricsService::MediaMetricsService()
         : mMaxRecords(kMaxRecords),
           mMaxRecordAgeNs(kMaxRecordAgeNs),
@@ -134,16 +204,10 @@
     // Overwrite package name and version if the caller was untrusted or empty
     if (!isTrusted || item->getPkgName().empty()) {
         const uid_t uid = item->getUid();
-        mediautils::UidInfo::Info info = mUidInfo.getInfo(uid);
-        if (useUidForPackage(info.package, info.installer)) {
-            // remove uid information of unknown installed packages.
-            // TODO: perhaps this can be done just before uploading to Westworld.
-            item->setPkgName(std::to_string(uid));
-            item->setPkgVersionCode(0);
-        } else {
-            item->setPkgName(info.package);
-            item->setPkgVersionCode(info.versionCode);
-        }
+        const auto [ pkgName, version ] =
+                MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid);
+        item->setPkgName(pkgName);
+        item->setPkgVersionCode(version);
     }
 
     ALOGV("%s: isTrusted:%d given uid %d; sanitized uid: %d sanitized pkg: %s "
@@ -205,91 +269,112 @@
         return NO_ERROR;
     }
 
-    // crack any parameters
-    const String16 protoOption("--proto");
-    const String16 clearOption("--clear");
+    static const String16 allOption("--all");
+    static const String16 clearOption("--clear");
+    static const String16 heapOption("--heap");
+    static const String16 helpOption("--help");
+    static const String16 prefixOption("--prefix");
+    static const String16 sinceOption("--since");
+    static const String16 unreachableOption("--unreachable");
+
+    bool all = false;
     bool clear = false;
-    const String16 sinceOption("--since");
-    nsecs_t ts_since = 0;
-    const String16 helpOption("--help");
-    const String16 onlyOption("--only");
-    std::string only;
-    const int n = args.size();
-    for (int i = 0; i < n; i++) {
-        if (args[i] == clearOption) {
+    bool heap = false;
+    bool unreachable = false;
+    int64_t sinceNs = 0;
+    std::string prefix;
+
+    const size_t n = args.size();
+    for (size_t i = 0; i < n; i++) {
+        if (args[i] == allOption) {
+            all = true;
+        } else if (args[i] == clearOption) {
             clear = true;
-        } else if (args[i] == protoOption) {
-            i++;
-            if (i < n) {
-                // ignore
-            } else {
-                result.append("missing value for -proto\n\n");
-            }
-        } else if (args[i] == sinceOption) {
-            i++;
-            if (i < n) {
-                String8 value(args[i]);
-                char *endp;
-                const char *p = value.string();
-                ts_since = strtoll(p, &endp, 10);
-                if (endp == p || *endp != '\0') {
-                    ts_since = 0;
-                }
-            } else {
-                ts_since = 0;
-            }
-            // command line is milliseconds; internal units are nano-seconds
-            ts_since *= NANOS_PER_MILLISECOND;
-        } else if (args[i] == onlyOption) {
-            i++;
-            if (i < n) {
-                String8 value(args[i]);
-                only = value.string();
-            }
+        } else if (args[i] == heapOption) {
+            heap = true;
         } else if (args[i] == helpOption) {
             // TODO: consider function area dumping.
             // dumpsys media.metrics audiotrack,codec
             // or dumpsys media.metrics audiotrack codec
 
             result.append("Recognized parameters:\n");
-            result.append("--help        this help message\n");
-            result.append("--proto #     dump using protocol #");
-            result.append("--clear       clears out saved records\n");
-            result.append("--only X      process records for component X\n");
-            result.append("--since X     include records since X\n");
-            result.append("             (X is milliseconds since the UNIX epoch)\n");
+            result.append("--all         show all records\n");
+            result.append("--clear       clear out saved records\n");
+            result.append("--heap        show heap usage (top 100)\n");
+            result.append("--help        display help\n");
+            result.append("--prefix X    process records for component X\n");
+            result.append("--since X     X < 0: records from -X seconds in the past\n");
+            result.append("              X = 0: ignore\n");
+            result.append("              X > 0: records from X seconds since Unix epoch\n");
+            result.append("--unreachable show unreachable memory (leaks)\n");
             write(fd, result.string(), result.size());
             return NO_ERROR;
+        } else if (args[i] == prefixOption) {
+            ++i;
+            if (i < n) {
+                prefix = String8(args[i]).string();
+            }
+        } else if (args[i] == sinceOption) {
+            ++i;
+            if (i < n) {
+                String8 value(args[i]);
+                char *endp;
+                const char *p = value.string();
+                long long sec = strtoll(p, &endp, 10);
+                if (endp == p || *endp != '\0' || sec == 0) {
+                    sinceNs = 0;
+                } else if (sec < 0) {
+                    sinceNs = systemTime(SYSTEM_TIME_REALTIME) + sec * NANOS_PER_SECOND;
+                } else {
+                    sinceNs = sec * NANOS_PER_SECOND;
+                }
+            }
+        } else if (args[i] == unreachableOption) {
+            unreachable = true;
         }
     }
 
     {
         std::lock_guard _l(mLock);
 
-        result.appendFormat("Dump of the %s process:\n", kServiceName);
-        dumpHeaders_l(result, ts_since);
-        dumpRecent_l(result, ts_since, only.c_str());
-
         if (clear) {
             mItemsDiscarded += mItems.size();
             mItems.clear();
-            // shall we clear the summary data too?
-        }
-        // TODO: maybe consider a better way of dumping audio analytics info.
-        constexpr int32_t linesToDump = 1000;
-        auto [ dumpString, lines ] = mAudioAnalytics.dump(linesToDump);
-        result.append(dumpString.c_str());
-        if (lines == linesToDump) {
-            result.append("-- some lines may be truncated --\n");
+            mAudioAnalytics.clear();
+        } else {
+            result.appendFormat("Dump of the %s process:\n", kServiceName);
+            const char *prefixptr = prefix.size() > 0 ? prefix.c_str() : nullptr;
+            dumpHeaders(result, sinceNs, prefixptr);
+            dumpQueue(result, sinceNs, prefixptr);
+
+            // TODO: maybe consider a better way of dumping audio analytics info.
+            const int32_t linesToDump = all ? INT32_MAX : 1000;
+            auto [ dumpString, lines ] = mAudioAnalytics.dump(linesToDump, sinceNs, prefixptr);
+            result.append(dumpString.c_str());
+            if (lines == linesToDump) {
+                result.append("-- some lines may be truncated --\n");
+            }
         }
     }
-
     write(fd, result.string(), result.size());
+
+    // Check heap and unreachable memory outside of lock.
+    if (heap) {
+        dprintf(fd, "\nDumping heap:\n");
+        std::string s = dumpMemoryAddresses(100 /* limit */);
+        write(fd, s.c_str(), s.size());
+    }
+    if (unreachable) {
+        dprintf(fd, "\nDumping unreachable memory:\n");
+        // TODO - should limit be an argument parameter?
+        std::string s = GetUnreachableMemoryString(true /* contents */, 100 /* limit */);
+        write(fd, s.c_str(), s.size());
+    }
     return NO_ERROR;
 }
 
 // dump headers
-void MediaMetricsService::dumpHeaders_l(String8 &result, nsecs_t ts_since)
+void MediaMetricsService::dumpHeaders(String8 &result, int64_t sinceNs, const char* prefix)
 {
     if (mediametrics::Item::isEnabled()) {
         result.append("Metrics gathering: enabled\n");
@@ -303,54 +388,36 @@
             "Records Discarded: %lld (by Count: %lld by Expiration: %lld)\n",
             (long long)mItemsDiscarded, (long long)mItemsDiscardedCount,
             (long long)mItemsDiscardedExpire);
-    if (ts_since != 0) {
+    if (prefix != nullptr) {
+        result.appendFormat("Restricting to prefix %s", prefix);
+    }
+    if (sinceNs != 0) {
         result.appendFormat(
             "Emitting Queue entries more recent than: %lld\n",
-            (long long)ts_since);
+            (long long)sinceNs);
     }
 }
 
-void MediaMetricsService::dumpRecent_l(
-        String8 &result, nsecs_t ts_since, const char * only)
+// TODO: should prefix be a set<string>?
+void MediaMetricsService::dumpQueue(String8 &result, int64_t sinceNs, const char* prefix)
 {
-    if (only != nullptr && *only == '\0') {
-        only = nullptr;
-    }
-    result.append("\nFinalized Metrics (oldest first):\n");
-    dumpQueue_l(result, ts_since, only);
-
-    // show who is connected and injecting records?
-    // talk about # records fed to the 'readers'
-    // talk about # records we discarded, perhaps "discarded w/o reading" too
-}
-
-void MediaMetricsService::dumpQueue_l(String8 &result) {
-    dumpQueue_l(result, (nsecs_t) 0, nullptr /* only */);
-}
-
-void MediaMetricsService::dumpQueue_l(
-        String8 &result, nsecs_t ts_since, const char * only) {
-    int slot = 0;
-
     if (mItems.empty()) {
         result.append("empty\n");
-    } else {
-        for (const auto &item : mItems) {
-            nsecs_t when = item->getTimestamp();
-            if (when < ts_since) {
-                continue;
-            }
-            // TODO: Only should be a set<string>
-            if (only != nullptr &&
-                    item->getKey() /* std::string */ != only) {
-                ALOGV("%s: omit '%s', it's not '%s'",
-                        __func__, item->getKey().c_str(), only);
-                continue;
-            }
-            result.appendFormat("%5d: %s\n",
-                   slot, item->toString().c_str());
-            slot++;
+        return;
+    }
+
+    int slot = 0;
+    for (const auto &item : mItems) {         // TODO: consider std::lower_bound() on mItems
+        if (item->getTimestamp() < sinceNs) { // sinceNs == 0 means all items shown
+            continue;
         }
+        if (prefix != nullptr && !startsWith(item->getKey(), prefix)) {
+            ALOGV("%s: omit '%s', it's not '%s'",
+                    __func__, item->getKey().c_str(), prefix);
+            continue;
+        }
+        result.appendFormat("%5d: %s\n", slot, item->toString().c_str());
+        slot++;
     }
 }
 
@@ -359,7 +426,7 @@
 
 // if item != NULL, it's the item we just inserted
 // true == more items eligible to be recovered
-bool MediaMetricsService::expirations_l(const std::shared_ptr<const mediametrics::Item>& item)
+bool MediaMetricsService::expirations(const std::shared_ptr<const mediametrics::Item>& item)
 {
     bool more = false;
 
@@ -414,7 +481,7 @@
     do {
         sleep(1);
         std::lock_guard _l(mLock);
-        more = expirations_l(nullptr);
+        more = expirations(nullptr);
     } while (more);
 }
 
@@ -424,7 +491,7 @@
     // we assume the items are roughly in time order.
     mItems.emplace_back(item);
     ++mItemsFinalized;
-    if (expirations_l(item)
+    if (expirations(item)
             && (!mExpireFuture.valid()
                || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)) {
         mExpireFuture = std::async(std::launch::async, [this] { processExpirations(); });
diff --git a/services/mediametrics/MediaMetricsService.h b/services/mediametrics/MediaMetricsService.h
index 935bee2..b8eb267 100644
--- a/services/mediametrics/MediaMetricsService.h
+++ b/services/mediametrics/MediaMetricsService.h
@@ -23,6 +23,7 @@
 #include <unordered_map>
 
 // IMediaMetricsService must include Vector, String16, Errors
+#include <android-base/thread_annotations.h>
 #include <media/IMediaMetricsService.h>
 #include <mediautils/ServiceUtilities.h>
 #include <utils/String8.h>
@@ -68,6 +69,28 @@
      */
     static bool useUidForPackage(const std::string& package, const std::string& installer);
 
+    /**
+     * Returns a std::pair of packageName and versionCode for a given uid.
+     *
+     * The value is sanitized - i.e. if the result is not approved to send,
+     * we use the uid as a string and a version code of 0.
+     */
+    static std::pair<std::string, int64_t> getSanitizedPackageNameAndVersionCode(uid_t uid);
+
+    /**
+     * Return string tokens from iterator, separated by spaces and reserved chars.
+     */
+    static std::string tokenizer(std::string::const_iterator& it,
+            const std::string::const_iterator& end, const char *reserved);
+
+    /**
+     * Parse the devices string and return a vector of device address pairs.
+     *
+     * A failure to parse returns early with the contents that were able to be parsed.
+     */
+    static std::vector<std::pair<std::string, std::string>>
+    getDeviceAddressPairs(const std::string &devices);
+
 protected:
 
     // Internal call where release is true if ownership of item is transferred
@@ -81,15 +104,11 @@
     bool isRateLimited(mediametrics::Item *) const;
     void saveItem(const std::shared_ptr<const mediametrics::Item>& item);
 
-    // The following methods are GUARDED_BY(mLock)
-    bool expirations_l(const std::shared_ptr<const mediametrics::Item>& item);
+    bool expirations(const std::shared_ptr<const mediametrics::Item>& item) REQUIRES(mLock);
 
     // support for generating output
-    void dumpQueue_l(String8 &result);
-    void dumpQueue_l(String8 &result, nsecs_t, const char *only);
-    void dumpHeaders_l(String8 &result, nsecs_t ts_since);
-    void dumpSummaries_l(String8 &result, nsecs_t ts_since, const char * only);
-    void dumpRecent_l(String8 &result, nsecs_t ts_since, const char * only);
+    void dumpQueue(String8 &result, int64_t sinceNs, const char* prefix) REQUIRES(mLock);
+    void dumpHeaders(String8 &result, int64_t sinceNs, const char* prefix) REQUIRES(mLock);
 
     // The following variables accessed without mLock
 
@@ -103,24 +122,22 @@
 
     std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
 
-    mediautils::UidInfo mUidInfo;  // mUidInfo can be accessed without lock (locked internally)
-
-    mediametrics::AudioAnalytics mAudioAnalytics;
+    mediametrics::AudioAnalytics mAudioAnalytics; // mAudioAnalytics is locked internally.
 
     std::mutex mLock;
     // statistics about our analytics
-    int64_t mItemsFinalized = 0;        // GUARDED_BY(mLock)
-    int64_t mItemsDiscarded = 0;        // GUARDED_BY(mLock)
-    int64_t mItemsDiscardedExpire = 0;  // GUARDED_BY(mLock)
-    int64_t mItemsDiscardedCount = 0;   // GUARDED_BY(mLock)
+    int64_t mItemsFinalized GUARDED_BY(mLock) = 0;
+    int64_t mItemsDiscarded GUARDED_BY(mLock) = 0;
+    int64_t mItemsDiscardedExpire GUARDED_BY(mLock) = 0;
+    int64_t mItemsDiscardedCount GUARDED_BY(mLock) = 0;
 
     // If we have a worker thread to garbage collect
-    std::future<void> mExpireFuture;    // GUARDED_BY(mLock)
+    std::future<void> mExpireFuture GUARDED_BY(mLock);
 
     // Our item queue, generally (oldest at front)
     // TODO: Make separate class, use segmented queue, write lock only end.
     // Note: Another analytics module might have ownership of an item longer than the log.
-    std::deque<std::shared_ptr<const mediametrics::Item>> mItems; // GUARDED_BY(mLock)
+    std::deque<std::shared_ptr<const mediametrics::Item>> mItems GUARDED_BY(mLock);
 };
 
 } // namespace android
diff --git a/services/mediametrics/TimeMachine.h b/services/mediametrics/TimeMachine.h
index a4c3693..c82778b 100644
--- a/services/mediametrics/TimeMachine.h
+++ b/services/mediametrics/TimeMachine.h
@@ -23,6 +23,7 @@
 #include <variant>
 #include <vector>
 
+#include <android-base/thread_annotations.h>
 #include <media/MediaMetricsItem.h>
 #include <utils/Timers.h>
 
@@ -74,25 +75,35 @@
     class KeyHistory  {
     public:
         template <typename T>
-        KeyHistory(T key, pid_t pid, uid_t uid, int64_t time)
+        KeyHistory(T key, uid_t allowUid, int64_t time)
             : mKey(key)
-            , mPid(pid)
-            , mUid(uid)
+            , mAllowUid(allowUid)
             , mCreationTime(time)
             , mLastModificationTime(time)
         {
-            putValue(BUNDLE_PID, (int32_t)pid, time);
-            putValue(BUNDLE_UID, (int32_t)uid, time);
+            // allowUid allows an untrusted client with a matching uid to set properties
+            // in this key.
+            // If allowUid == (uid_t)-1, no untrusted client may set properties in the key.
+            if (allowUid != (uid_t)-1) {
+                // Set ALLOWUID property here; does not change after key creation.
+                putValue(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)allowUid, time);
+            }
         }
 
         KeyHistory(const KeyHistory &other) = default;
 
+        // Return NO_ERROR only if the passed in uidCheck is -1 or matches
+        // the internal mAllowUid.
+        // An external submit will always have a valid uidCheck parameter.
+        // An internal get request within mediametrics will have a uidCheck == -1 which
+        // we allow to proceed.
         status_t checkPermission(uid_t uidCheck) const {
-            return uidCheck != (uid_t)-1 && uidCheck != mUid ? PERMISSION_DENIED : NO_ERROR;
+            return uidCheck != (uid_t)-1 && uidCheck != mAllowUid ? PERMISSION_DENIED : NO_ERROR;
         }
 
         template <typename T>
-        status_t getValue(const std::string &property, T* value, int64_t time = 0) const {
+        status_t getValue(const std::string &property, T* value, int64_t time = 0) const
+                REQUIRES(mPseudoKeyHistoryLock) {
             if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
             const auto tsptr = mPropertyMap.find(property);
             if (tsptr == mPropertyMap.end()) return BAD_VALUE;
@@ -108,20 +119,22 @@
         }
 
         template <typename T>
-        status_t getValue(const std::string &property, T defaultValue, int64_t time = 0) const {
+        status_t getValue(const std::string &property, T defaultValue, int64_t time = 0) const
+                REQUIRES(mPseudoKeyHistoryLock){
             T value;
             return getValue(property, &value, time) != NO_ERROR ? defaultValue : value;
         }
 
         void putProp(
-                const std::string &name, const mediametrics::Item::Prop &prop, int64_t time = 0) {
+                const std::string &name, const mediametrics::Item::Prop &prop, int64_t time = 0)
+                REQUIRES(mPseudoKeyHistoryLock) {
             //alternatively: prop.visit([&](auto value) { putValue(name, value, time); });
             putValue(name, prop.get(), time);
         }
 
         template <typename T>
-        void putValue(const std::string &property,
-                T&& e, int64_t time = 0) {
+        void putValue(const std::string &property, T&& e, int64_t time = 0)
+                REQUIRES(mPseudoKeyHistoryLock) {
             if (time == 0) time = systemTime(SYSTEM_TIME_REALTIME);
             mLastModificationTime = time;
             if (mPropertyMap.size() >= kKeyMaxProperties &&
@@ -134,7 +147,7 @@
             if (timeSequence.empty()           // no elements
                     || property.back() == AMEDIAMETRICS_PROP_SUFFIX_CHAR_DUPLICATES_ALLOWED
                     || timeSequence.rbegin()->second != el) { // value changed
-                timeSequence.emplace(time, std::move(el));
+                timeSequence.emplace_hint(timeSequence.end(), time, std::move(el));
 
                 if (timeSequence.size() > kTimeSequenceMaxElements) {
                     ALOGV("%s: restricting maximum elements (discarding oldest) for %s",
@@ -144,18 +157,24 @@
             }
         }
 
-        std::pair<std::string, int32_t> dump(int32_t lines, int64_t time) const {
+        std::pair<std::string, int32_t> dump(int32_t lines, int64_t time) const
+                REQUIRES(mPseudoKeyHistoryLock) {
             std::stringstream ss;
             int32_t ll = lines;
             for (auto& tsPair : mPropertyMap) {
                 if (ll <= 0) break;
-                ss << dump(mKey, tsPair, time);
-                --ll;
+                std::string s = dump(mKey, tsPair, time);
+                if (s.size() > 0) {
+                    --ll;
+                    ss << s;
+                }
             }
             return { ss.str(), lines - ll };
         }
 
-        int64_t getLastModificationTime() const { return mLastModificationTime; }
+        int64_t getLastModificationTime() const REQUIRES(mPseudoKeyHistoryLock) {
+            return mLastModificationTime;
+        }
 
     private:
         static std::string dump(
@@ -165,7 +184,7 @@
             const auto timeSequence = tsPair.second;
             auto eptr = timeSequence.lower_bound(time);
             if (eptr == timeSequence.end()) {
-                return tsPair.first + "={};\n";
+                return {}; // don't dump anything. tsPair.first + "={};\n";
             }
             std::stringstream ss;
             ss << key << "." << tsPair.first << "={";
@@ -189,8 +208,7 @@
         }
 
         const std::string mKey;
-        const pid_t mPid __unused;
-        const uid_t mUid;
+        const uid_t mAllowUid;
         const int64_t mCreationTime __unused;
 
         int64_t mLastModificationTime;
@@ -264,12 +282,15 @@
             if (it == mHistory.end()) {
                 if (!isTrusted) return PERMISSION_DENIED;
 
-                (void)gc_l(garbage);
+                (void)gc(garbage);
 
+                // We set the allowUid for client access on key creation.
+                int32_t allowUid = -1;
+                (void)item->get(AMEDIAMETRICS_PROP_ALLOWUID, &allowUid);
                 // no keylock needed here as we are sole owner
                 // until placed on mHistory.
                 keyHistory = std::make_shared<KeyHistory>(
-                    key, item->getPid(), item->getUid(), time);
+                    key, allowUid, time);
                 mHistory[key] = keyHistory;
             } else {
                 keyHistory = it->second;
@@ -316,7 +337,7 @@
                 if (it == mHistory.end()) continue;
                 remoteKeyHistory = it->second;
             }
-            std::lock_guard(getLockForKey(remoteKey));
+            std::lock_guard lock(getLockForKey(remoteKey));
             remoteKeyHistory->putProp(remoteName, prop, time);
         }
         return NO_ERROR;
@@ -407,24 +428,22 @@
      *
      * \param lines the maximum number of lines in the string returned.
      * \param key selects only that key.
-     * \param time to start the dump from.
+     * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+     * \param prefix the desired key prefix to match (nullptr shows all)
      */
     std::pair<std::string, int32_t> dump(
-            int32_t lines = INT32_MAX, const std::string &key = {}, int64_t time = 0) const {
+            int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const {
         std::lock_guard lock(mLock);
-        if (!key.empty()) {  // use std::regex
-            const auto it = mHistory.find(key);
-            if (it == mHistory.end()) return {};
-            std::lock_guard lock(getLockForKey(it->first));
-            return it->second->dump(lines, time);
-        }
-
         std::stringstream ss;
         int32_t ll = lines;
-        for (const auto &[lkey, lhist] : mHistory) {
-            std::lock_guard lock(getLockForKey(lkey));
-            if (lines <= 0) break;
-            auto [s, l] = lhist->dump(ll, time);
+
+        for (auto it = prefix != nullptr ? mHistory.lower_bound(prefix) : mHistory.begin();
+                it != mHistory.end();
+                ++it) {
+            if (ll <= 0) break;
+            if (prefix != nullptr && !startsWith(it->first, prefix)) break;
+            std::lock_guard lock(getLockForKey(it->first));
+            auto [s, l] = it->second->dump(ll, sinceNs);
             ss << s;
             ll -= l;
         }
@@ -434,13 +453,14 @@
 private:
 
     // Obtains the lock for a KeyHistory.
-    std::mutex &getLockForKey(const std::string &key) const {
+    std::mutex &getLockForKey(const std::string &key) const
+            RETURN_CAPABILITY(mPseudoKeyHistoryLock) {
         return mKeyLocks[std::hash<std::string>{}(key) % std::size(mKeyLocks)];
     }
 
     // Finds a KeyHistory from a URL.  Returns nullptr if not found.
     std::shared_ptr<KeyHistory> getKeyHistoryFromUrl(
-            std::string url, std::string* key, std::string *prop) const {
+            const std::string& url, std::string* key, std::string *prop) const {
         std::lock_guard lock(mLock);
 
         auto it = mHistory.upper_bound(url);
@@ -458,7 +478,6 @@
         return it->second;
     }
 
-    // GUARDED_BY mLock
     /**
      * Garbage collects if the TimeMachine size exceeds the high water mark.
      *
@@ -470,7 +489,7 @@
      *
      * \return true if garbage collection was done.
      */
-    bool gc_l(std::vector<std::any>& garbage) {
+    bool gc(std::vector<std::any>& garbage) REQUIRES(mLock) {
         // TODO: something better than this for garbage collection.
         if (mHistory.size() < mKeyHighWaterMark) return false;
 
@@ -539,12 +558,17 @@
      */
 
     mutable std::mutex mLock;           // Lock for mHistory
-    History mHistory;                   // GUARDED_BY mLock
+    History mHistory GUARDED_BY(mLock);
 
     // KEY_LOCKS is the number of mutexes for keys.
     // It need not be a power of 2, but faster that way.
     static inline constexpr size_t KEY_LOCKS = 256;
     mutable std::mutex mKeyLocks[KEY_LOCKS];  // Hash-striped lock for KeyHistory based on key.
+
+    // Used for thread-safety analysis, we create a fake mutex object to represent
+    // the hash stripe lock mechanism, which is then tracked by the compiler.
+    class CAPABILITY("mutex") PseudoLock {};
+    static inline PseudoLock mPseudoKeyHistoryLock;
 };
 
 } // namespace android::mediametrics
diff --git a/services/mediametrics/TimedAction.h b/services/mediametrics/TimedAction.h
new file mode 100644
index 0000000..c7ef585
--- /dev/null
+++ b/services/mediametrics/TimedAction.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <chrono>
+#include <map>
+#include <mutex>
+#include <thread>
+
+namespace android::mediametrics {
+
+class TimedAction {
+public:
+    TimedAction() : mThread{[this](){threadLoop();}} {}
+
+    ~TimedAction() {
+        quit();
+    }
+
+    // TODO: return a handle for cancelling the action?
+    template <typename T> // T is in units of std::chrono::duration.
+    void postIn(const T& time, std::function<void()> f) {
+        postAt(std::chrono::steady_clock::now() + time, f);
+    }
+
+    template <typename T> // T is in units of std::chrono::time_point
+    void postAt(const T& targetTime, std::function<void()> f) {
+        std::lock_guard l(mLock);
+        if (mQuit) return;
+        if (mMap.empty() || targetTime < mMap.begin()->first) {
+            mMap.emplace_hint(mMap.begin(), targetTime, std::move(f));
+            mCondition.notify_one();
+        } else {
+            mMap.emplace(targetTime, std::move(f));
+        }
+    }
+
+    void clear() {
+        std::lock_guard l(mLock);
+        mMap.clear();
+    }
+
+    void quit() {
+        {
+            std::lock_guard l(mLock);
+            if (mQuit) return;
+            mQuit = true;
+            mMap.clear();
+            mCondition.notify_all();
+        }
+        mThread.join();
+    }
+
+    size_t size() const {
+        std::lock_guard l(mLock);
+        return mMap.size();
+    }
+
+private:
+    void threadLoop() NO_THREAD_SAFETY_ANALYSIS { // thread safety doesn't cover unique_lock
+        std::unique_lock l(mLock);
+        while (!mQuit) {
+            auto sleepUntilTime = std::chrono::time_point<std::chrono::steady_clock>::max();
+            if (!mMap.empty()) {
+                sleepUntilTime = mMap.begin()->first;
+                if (sleepUntilTime <= std::chrono::steady_clock::now()) {
+                    auto node = mMap.extract(mMap.begin()); // removes from mMap.
+                    l.unlock();
+                    node.mapped()();
+                    l.lock();
+                    continue;
+                }
+            }
+            mCondition.wait_until(l, sleepUntilTime);
+        }
+    }
+
+    mutable std::mutex mLock;
+    std::condition_variable mCondition GUARDED_BY(mLock);
+    bool mQuit GUARDED_BY(mLock) = false;
+    std::multimap<std::chrono::time_point<std::chrono::steady_clock>, std::function<void()>>
+            mMap GUARDED_BY(mLock); // multiple functions could execute at the same time.
+
+    // needs to be initialized after the variables above, done in constructor initializer list.
+    std::thread mThread;
+};
+
+} // namespace android::mediametrics
diff --git a/services/mediametrics/TransactionLog.h b/services/mediametrics/TransactionLog.h
index 190a99e..8a22826 100644
--- a/services/mediametrics/TransactionLog.h
+++ b/services/mediametrics/TransactionLog.h
@@ -21,6 +21,7 @@
 #include <sstream>
 #include <string>
 
+#include <android-base/thread_annotations.h>
 #include <media/MediaMetricsItem.h>
 
 namespace android::mediametrics {
@@ -92,9 +93,9 @@
         std::vector<std::any> garbage;  // objects destroyed after lock.
         std::lock_guard lock(mLock);
 
-        (void)gc_l(garbage);
-        mLog.emplace(time, item);
-        mItemMap[key].emplace(time, item);
+        (void)gc(garbage);
+        mLog.emplace_hint(mLog.end(), time, item);
+        mItemMap[key].emplace_hint(mItemMap[key].end(), time, item);
         return NO_ERROR;  // no errors for now.
     }
 
@@ -104,7 +105,7 @@
     std::vector<std::shared_ptr<const mediametrics::Item>> get(
             int64_t startTime = 0, int64_t endTime = INT64_MAX) const {
         std::lock_guard lock(mLock);
-        return getItemsInRange_l(mLog, startTime, endTime);
+        return getItemsInRange(mLog, startTime, endTime);
     }
 
     /**
@@ -116,7 +117,7 @@
         std::lock_guard lock(mLock);
         auto mapIt = mItemMap.find(key);
         if (mapIt == mItemMap.end()) return {};
-        return getItemsInRange_l(mapIt->second, startTime, endTime);
+        return getItemsInRange(mapIt->second, startTime, endTime);
     }
 
     /**
@@ -127,8 +128,11 @@
      * for subsequent line limiting.
      *
      * \param lines the maximum number of lines in the string returned.
+     * \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
+     * \param prefix the desired key prefix to match (nullptr shows all)
      */
-    std::pair<std::string, int32_t> dump(int32_t lines) const {
+    std::pair<std::string, int32_t> dump(
+            int32_t lines, int64_t sinceNs, const char *prefix = nullptr) const {
         std::stringstream ss;
         int32_t ll = lines;
         std::lock_guard lock(mLock);
@@ -138,26 +142,25 @@
             ss << "Consolidated:\n";
             --ll;
         }
-        for (const auto &log : mLog) {
-            if (ll <= 0) break;
-            ss << "  " << log.second->toString() << "\n";
-            --ll;
-        }
+        auto [s, l] = dumpMapTimeItem(mLog, ll, sinceNs, prefix);
+        ss << s;
+        ll -= l;
 
         // Grouped by item key (category)
         if (ll > 0) {
             ss << "Categorized:\n";
             --ll;
         }
-        for (const auto &itemMap : mItemMap) {
+
+        for (auto it = prefix != nullptr ? mItemMap.lower_bound(prefix) : mItemMap.begin();
+                it != mItemMap.end();
+                ++it) {
             if (ll <= 0) break;
-            ss << " " << itemMap.first << "\n";
-            --ll;
-            for (const auto &item : itemMap.second) {
-                if (ll <= 0) break;
-                ss << "  " << item.second->toString() << "\n";
-                --ll;
-            }
+            if (prefix != nullptr && !startsWith(it->first, prefix)) break;
+            auto [s, l] = dumpMapTimeItem(it->second, ll - 1, sinceNs, prefix);
+            if (l == 0) continue; // don't show empty groups (due to sinceNs).
+            ss << " " << it->first << "\n" << s;
+            ll -= l + 1;
         }
         return { ss.str(), lines - ll };
     }
@@ -184,7 +187,24 @@
     using MapTimeItem =
             std::multimap<int64_t /* time */, std::shared_ptr<const mediametrics::Item>>;
 
-    // GUARDED_BY mLock
+    static std::pair<std::string, int32_t> dumpMapTimeItem(
+            const MapTimeItem& mapTimeItem,
+            int32_t lines, int64_t sinceNs = 0, const char *prefix = nullptr) {
+        std::stringstream ss;
+        int32_t ll = lines;
+        // Note: for our data, mapTimeItem.lower_bound(0) == mapTimeItem.begin().
+        for (auto it = mapTimeItem.lower_bound(sinceNs);
+                it != mapTimeItem.end(); ++it) {
+            if (ll <= 0) break;
+            if (prefix != nullptr && !startsWith(it->second->getKey(), prefix)) {
+                continue;
+            }
+            ss << "  " << it->second->toString() << "\n";
+            --ll;
+        }
+        return { ss.str(), lines - ll };
+    }
+
     /**
      * Garbage collects if the TimeMachine size exceeds the high water mark.
      *
@@ -193,7 +213,7 @@
      *
      * \return true if garbage collection was done.
      */
-    bool gc_l(std::vector<std::any>& garbage) {
+    bool gc(std::vector<std::any>& garbage) REQUIRES(mLock) {
         if (mLog.size() < mHighWaterMark) return false;
 
         ALOGD("%s: garbage collection", __func__);
@@ -248,7 +268,7 @@
         return true;
     }
 
-    static std::vector<std::shared_ptr<const mediametrics::Item>> getItemsInRange_l(
+    static std::vector<std::shared_ptr<const mediametrics::Item>> getItemsInRange(
             const MapTimeItem& map,
             int64_t startTime = 0, int64_t endTime = INT64_MAX) {
         auto it = map.lower_bound(startTime);
@@ -269,11 +289,8 @@
 
     mutable std::mutex mLock;
 
-    // GUARDED_BY mLock
-    MapTimeItem mLog;
-
-    // GUARDED_BY mLock
-    std::map<std::string /* item_key */, MapTimeItem> mItemMap;
+    MapTimeItem mLog GUARDED_BY(mLock);
+    std::map<std::string /* item_key */, MapTimeItem> mItemMap GUARDED_BY(mLock);
 };
 
 } // namespace android::mediametrics
diff --git a/services/mediametrics/main_mediametrics.cpp b/services/mediametrics/main_mediametrics.cpp
index ec392e2..6992c32 100644
--- a/services/mediametrics/main_mediametrics.cpp
+++ b/services/mediametrics/main_mediametrics.cpp
@@ -23,12 +23,17 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
-
+#include <mediautils/LimitProcessMemory.h>
 
 int main(int argc __unused, char **argv __unused)
 {
     using namespace android;
 
+    limitProcessMemory(
+        "media.metrics.maxmem", /* property that defines limit */
+        (size_t)128 * (1 << 20), /* SIZE_MAX, upper limit in bytes */
+        10 /* upper limit as percentage of physical RAM */);
+
     signal(SIGPIPE, SIG_IGN);
 
     // to match the service name
diff --git a/services/mediametrics/mediametrics.rc b/services/mediametrics/mediametrics.rc
index 1efde5e..2a6c817 100644
--- a/services/mediametrics/mediametrics.rc
+++ b/services/mediametrics/mediametrics.rc
@@ -3,4 +3,4 @@
     user media
     group media
     ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    task_profiles ProcessCapacityHigh HighPerformance
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index b8e566e..b465ecd 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -79,7 +79,7 @@
     const int mFinal;
 
     public:
-      Thunk(decltype(mF) f, int final) : mF(f), mFinal(final) {}
+      explicit Thunk(decltype(mF) f, int final) : mF(std::move(f)), mFinal(final) {}
       ~Thunk() { mF(mFinal); }
       void thunk(int value) { mF(value); }
   };
@@ -139,7 +139,7 @@
     std::function<void()> mF;
 
     public:
-      Thunk(decltype(mF) f) : mF(f) {}
+      explicit Thunk(decltype(mF) f) : mF(std::move(f)) {}
       void thunk() { mF(); }
   };
 
@@ -813,6 +813,42 @@
   ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
 }
 
+TEST(mediametrics_tests, audio_analytics_permission2) {
+  constexpr int32_t transactionUid = 1010; // arbitrary
+  auto item = std::make_shared<mediametrics::Item>("audio.1");
+  (*item).set("one", (int32_t)1)
+         .set("two", (int32_t)2)
+         .set(AMEDIAMETRICS_PROP_ALLOWUID, transactionUid)
+         .setTimestamp(10);
+
+  // item2 submitted untrusted
+  auto item2 = std::make_shared<mediametrics::Item>("audio.1");
+  (*item2).set("three", (int32_t)3)
+         .setUid(transactionUid)
+         .setTimestamp(11);
+
+  auto item3 = std::make_shared<mediametrics::Item>("audio.2");
+  (*item3).set("four", (int32_t)4)
+          .setTimestamp(12);
+
+  android::mediametrics::AudioAnalytics audioAnalytics;
+
+  // untrusted entities cannot create a new key.
+  ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item, false /* isTrusted */));
+  ASSERT_EQ(PERMISSION_DENIED, audioAnalytics.submit(item2, false /* isTrusted */));
+
+  // TODO: Verify contents of AudioAnalytics.
+  // Currently there is no getter API in AudioAnalytics besides dump.
+  ASSERT_EQ(9, audioAnalytics.dump(1000).second /* lines */);
+
+  ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
+  // untrusted entities can add to an existing key
+  ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
+
+  // Check that we have some info in the dump.
+  ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+}
+
 TEST(mediametrics_tests, audio_analytics_dump) {
   auto item = std::make_shared<mediametrics::Item>("audio.1");
   (*item).set("one", (int32_t)1)
@@ -847,6 +883,48 @@
   }
 }
 
+TEST(mediametrics_tests, device_parsing) {
+    auto devaddr = android::MediaMetricsService::getDeviceAddressPairs("(DEVICE, )");
+    ASSERT_EQ((size_t)1, devaddr.size());
+    ASSERT_EQ("DEVICE", devaddr[0].first);
+    ASSERT_EQ("", devaddr[0].second);
+
+    devaddr = android::MediaMetricsService::getDeviceAddressPairs(
+            "(DEVICE1, A)|(D, ADDRB)");
+    ASSERT_EQ((size_t)2, devaddr.size());
+    ASSERT_EQ("DEVICE1", devaddr[0].first);
+    ASSERT_EQ("A", devaddr[0].second);
+    ASSERT_EQ("D", devaddr[1].first);
+    ASSERT_EQ("ADDRB", devaddr[1].second);
+
+    devaddr = android::MediaMetricsService::getDeviceAddressPairs(
+            "(A,B)|(C,D)");
+    ASSERT_EQ((size_t)2, devaddr.size());
+    ASSERT_EQ("A", devaddr[0].first);
+    ASSERT_EQ("B", devaddr[0].second);
+    ASSERT_EQ("C", devaddr[1].first);
+    ASSERT_EQ("D", devaddr[1].second);
+
+    devaddr = android::MediaMetricsService::getDeviceAddressPairs(
+            "  ( A1 , B )  | ( C , D2 )  ");
+    ASSERT_EQ((size_t)2, devaddr.size());
+    ASSERT_EQ("A1", devaddr[0].first);
+    ASSERT_EQ("B", devaddr[0].second);
+    ASSERT_EQ("C", devaddr[1].first);
+    ASSERT_EQ("D2", devaddr[1].second);
+}
+
+TEST(mediametrics_tests, timed_action) {
+    android::mediametrics::TimedAction timedAction;
+    std::atomic_int value1 = 0;
+
+    timedAction.postIn(std::chrono::seconds(0), [&value1] { ++value1; });
+    timedAction.postIn(std::chrono::seconds(1000), [&value1] { ++value1; });
+    usleep(100000);
+    ASSERT_EQ(1, value1);
+    ASSERT_EQ((size_t)1, timedAction.size());
+}
+
 #if 0
 // Stress test code for garbage collection, you need to enable AID_SHELL as trusted to run
 // in MediaMetricsService.cpp.
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index be5af00..ff45c87 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -114,6 +114,7 @@
         info.uid = uid;
         info.clientId = clientId;
         info.client = client;
+        info.pendingRemoval = false;
 
         index = infos.add(clientId, info);
     }
@@ -648,6 +649,36 @@
     return Status::ok();
 }
 
+Status ResourceManagerService::markClientForPendingRemoval(int32_t pid, int64_t clientId) {
+    String8 log = String8::format(
+            "markClientForPendingRemoval(pid %d, clientId %lld)",
+            pid, (long long) clientId);
+    mServiceLog->add(log);
+
+    Mutex::Autolock lock(mLock);
+    if (!mProcessInfo->isValidPid(pid)) {
+        ALOGE("Rejected markClientForPendingRemoval call with invalid pid.");
+        return Status::fromServiceSpecificError(BAD_VALUE);
+    }
+    ssize_t index = mMap.indexOfKey(pid);
+    if (index < 0) {
+        ALOGV("markClientForPendingRemoval: didn't find pid %d for clientId %lld",
+              pid, (long long)clientId);
+        return Status::ok();
+    }
+    ResourceInfos &infos = mMap.editValueAt(index);
+
+    index = infos.indexOfKey(clientId);
+    if (index < 0) {
+        ALOGV("markClientForPendingRemoval: didn't find clientId %lld", (long long) clientId);
+        return Status::ok();
+    }
+
+    ResourceInfo &info = infos.editValueAt(index);
+    info.pendingRemoval = true;
+    return Status::ok();
+}
+
 bool ResourceManagerService::getPriority_l(int pid, int* priority) {
     int newPid = pid;
 
@@ -693,6 +724,12 @@
     int lowestPriorityPid;
     int lowestPriority;
     int callingPriority;
+
+    // Before looking into other processes, check if we have clients marked for
+    // pending removal in the same process.
+    if (getBiggestClient_l(callingPid, type, client, true /* pendingRemovalOnly */)) {
+        return true;
+    }
     if (!getPriority_l(callingPid, &callingPriority)) {
         ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
                 callingPid);
@@ -761,7 +798,8 @@
 }
 
 bool ResourceManagerService::getBiggestClient_l(
-        int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client) {
+        int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client,
+        bool pendingRemovalOnly) {
     ssize_t index = mMap.indexOfKey(pid);
     if (index < 0) {
         ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
@@ -773,6 +811,9 @@
     const ResourceInfos &infos = mMap.valueAt(index);
     for (size_t i = 0; i < infos.size(); ++i) {
         const ResourceList &resources = infos[i].resources;
+        if (pendingRemovalOnly && !infos[i].pendingRemoval) {
+            continue;
+        }
         for (auto it = resources.begin(); it != resources.end(); it++) {
             const MediaResourceParcel &resource = it->second;
             if (resource.type == type) {
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f500c62..ee982b7 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -18,6 +18,8 @@
 #ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
 #define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
 
+#include <map>
+
 #include <aidl/android/media/BnResourceManagerService.h>
 #include <arpa/inet.h>
 #include <media/MediaResource.h>
@@ -50,6 +52,7 @@
     std::shared_ptr<IResourceManagerClient> client;
     sp<DeathNotifier> deathNotifier;
     ResourceList resources;
+    bool pendingRemoval{false};
 };
 
 // TODO: convert these to std::map
@@ -122,6 +125,8 @@
             int originalPid,
             int newPid) override;
 
+    Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
+
     Status removeResource(int pid, int64_t clientId, bool checkValid);
 
 private:
@@ -146,7 +151,8 @@
     // Gets the client who owns biggest piece of specified resource type from pid.
     // Returns false if failed. The client will remain unchanged if failed.
     bool getBiggestClient_l(int pid, MediaResource::Type type,
-            std::shared_ptr<IResourceManagerClient> *client);
+            std::shared_ptr<IResourceManagerClient> *client,
+            bool pendingRemovalOnly = false);
 
     bool isCallingPriorityHigher_l(int callingPid, int pid);
 
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 5d839fa..702935d 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -472,6 +472,56 @@
         }
     }
 
+    void testMarkClientForPendingRemoval() {
+        bool result;
+
+        {
+            addResource();
+            mService->mSupportsSecureWithNonSecureCodec = true;
+
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+            // Remove low priority clients
+            mService->removeClient(kTestPid1, getId(mTestClient1));
+
+            // no lower priority client
+            CHECK_STATUS_FALSE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+
+            mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+            // client marked for pending removal from the same process got reclaimed
+            CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+            // clean up client 3 which still left
+            mService->removeClient(kTestPid2, getId(mTestClient3));
+        }
+
+        {
+            addResource();
+            mService->mSupportsSecureWithNonSecureCodec = true;
+
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+            mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+            // client marked for pending removal from the same process got reclaimed
+            // first, even though there are lower priority process
+            CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+            // lower priority client got reclaimed
+            CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+            verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+
+            // clean up client 3 which still left
+            mService->removeClient(kTestPid2, getId(mTestClient3));
+        }
+    }
+
     void testRemoveClient() {
         addResource();
 
@@ -900,4 +950,8 @@
     testOverridePid();
 }
 
+TEST_F(ResourceManagerServiceTest, markClientForPendingRemoval) {
+    testMarkClientForPendingRemoval();
+}
+
 } // namespace android
diff --git a/services/mediatranscoding/mediatranscoding.rc b/services/mediatranscoding/mediatranscoding.rc
index 2dc547f..5bfef59 100644
--- a/services/mediatranscoding/mediatranscoding.rc
+++ b/services/mediatranscoding/mediatranscoding.rc
@@ -3,4 +3,4 @@
     user media
     group media
     ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    task_profiles ProcessCapacityHigh HighPerformance
diff --git a/services/minijail/Android.bp b/services/minijail/Android.bp
index 0713a87..5ea6d1e 100644
--- a/services/minijail/Android.bp
+++ b/services/minijail/Android.bp
@@ -39,4 +39,5 @@
     srcs: [
         "av_services_minijail_unittest.cpp",
     ],
+    test_suites: ["device-tests"],
 }
diff --git a/services/minijail/TEST_MAPPING b/services/minijail/TEST_MAPPING
new file mode 100644
index 0000000..0d89760
--- /dev/null
+++ b/services/minijail/TEST_MAPPING
@@ -0,0 +1,5 @@
+{
+  "presubmit": [
+    { "name": "libavservices_minijail_unittest" }
+  ]
+}
diff --git a/services/minijail/av_services_minijail_unittest.cpp b/services/minijail/av_services_minijail_unittest.cpp
index 31313f8..896a764 100644
--- a/services/minijail/av_services_minijail_unittest.cpp
+++ b/services/minijail/av_services_minijail_unittest.cpp
@@ -34,13 +34,32 @@
         "mmap: 1\n"
         "munmap: 1\n";
 
+    const std::string third_policy_ =
+        "open: 1\n"
+        "close: 1\n";
+
     const std::string full_policy_ = base_policy_ + std::string("\n") + additional_policy_;
+    const std::string triple_policy_ = base_policy_ +
+                                       std::string("\n") + additional_policy_ +
+                                       std::string("\n") + third_policy_;
 };
 
 TEST_F(WritePolicyTest, OneFile)
 {
     std::string final_string;
-    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, std::string()));
+    // vector with an empty pathname
+    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, {std::string()}));
+    EXPECT_LE(0, fd.get());
+    bool success = android::base::ReadFdToString(fd.get(), &final_string);
+    EXPECT_TRUE(success);
+    EXPECT_EQ(final_string, base_policy_);
+}
+
+TEST_F(WritePolicyTest, OneFileAlternate)
+{
+    std::string final_string;
+    // empty vector
+    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, {}));
     EXPECT_LE(0, fd.get());
     bool success = android::base::ReadFdToString(fd.get(), &final_string);
     EXPECT_TRUE(success);
@@ -50,9 +69,19 @@
 TEST_F(WritePolicyTest, TwoFiles)
 {
     std::string final_string;
-    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, additional_policy_));
+    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, {additional_policy_}));
     EXPECT_LE(0, fd.get());
     bool success = android::base::ReadFdToString(fd.get(), &final_string);
     EXPECT_TRUE(success);
     EXPECT_EQ(final_string, full_policy_);
 }
+
+TEST_F(WritePolicyTest, ThreeFiles)
+{
+    std::string final_string;
+    android::base::unique_fd fd(android::WritePolicyToPipe(base_policy_, {additional_policy_, third_policy_}));
+    EXPECT_LE(0, fd.get());
+    bool success = android::base::ReadFdToString(fd.get(), &final_string);
+    EXPECT_TRUE(success);
+    EXPECT_EQ(final_string, triple_policy_);
+}
diff --git a/services/minijail/minijail.cpp b/services/minijail/minijail.cpp
index f213287..c7832b9 100644
--- a/services/minijail/minijail.cpp
+++ b/services/minijail/minijail.cpp
@@ -29,7 +29,7 @@
 namespace android {
 
 int WritePolicyToPipe(const std::string& base_policy_content,
-                      const std::string& additional_policy_content)
+                      const std::vector<std::string>& additional_policy_contents)
 {
     int pipefd[2];
     if (pipe(pipefd) == -1) {
@@ -40,9 +40,11 @@
     base::unique_fd write_end(pipefd[1]);
     std::string content = base_policy_content;
 
-    if (additional_policy_content.length() > 0) {
-        content += "\n";
-        content += additional_policy_content;
+    for (auto one_content : additional_policy_contents) {
+        if (one_content.length() > 0) {
+            content += "\n";
+            content += one_content;
+        }
     }
 
     if (!base::WriteStringToFd(content, write_end.get())) {
@@ -53,29 +55,34 @@
     return pipefd[0];
 }
 
-void SetUpMinijail(const std::string& base_policy_path, const std::string& additional_policy_path)
+void SetUpMinijail(const std::string& base_policy_path,
+                   const std::string& additional_policy_path)
 {
-    // No seccomp policy defined for this architecture.
-    if (access(base_policy_path.c_str(), R_OK) == -1) {
-        LOG(WARNING) << "No seccomp policy defined for this architecture.";
-        return;
-    }
+    SetUpMinijailList(base_policy_path, {additional_policy_path});
+}
 
+void SetUpMinijailList(const std::string& base_policy_path,
+                   const std::vector<std::string>& additional_policy_paths)
+{
     std::string base_policy_content;
-    std::string additional_policy_content;
+    std::vector<std::string> additional_policy_contents;
     if (!base::ReadFileToString(base_policy_path, &base_policy_content,
                                 false /* follow_symlinks */)) {
         LOG(FATAL) << "Could not read base policy file '" << base_policy_path << "'";
     }
 
-    if (additional_policy_path.length() > 0 &&
-        !base::ReadFileToString(additional_policy_path, &additional_policy_content,
-                                false /* follow_symlinks */)) {
-        LOG(WARNING) << "Could not read additional policy file '" << additional_policy_path << "'";
-        additional_policy_content = std::string();
+    for (auto one_policy_path : additional_policy_paths) {
+        std::string one_policy_content;
+        if (one_policy_path.length() > 0 &&
+                !base::ReadFileToString(one_policy_path, &one_policy_content,
+                    false /* follow_symlinks */)) {
+            // TODO: harder failure (fatal unless ENOENT?)
+            LOG(WARNING) << "Could not read additional policy file '" << one_policy_path << "'";
+        }
+        additional_policy_contents.push_back(one_policy_content);
     }
 
-    base::unique_fd policy_fd(WritePolicyToPipe(base_policy_content, additional_policy_content));
+    base::unique_fd policy_fd(WritePolicyToPipe(base_policy_content, additional_policy_contents));
     if (policy_fd.get() == -1) {
         LOG(FATAL) << "Could not write seccomp policy to fd";
     }
diff --git a/services/minijail/minijail.h b/services/minijail/minijail.h
index c8a2149..298af86 100644
--- a/services/minijail/minijail.h
+++ b/services/minijail/minijail.h
@@ -16,11 +16,15 @@
 #define AV_SERVICES_MINIJAIL_MINIJAIL
 
 #include <string>
+#include <vector>
 
 namespace android {
 int WritePolicyToPipe(const std::string& base_policy_content,
-                      const std::string& additional_policy_content);
-void SetUpMinijail(const std::string& base_policy_path, const std::string& additional_policy_path);
+                      const std::vector<std::string>& additional_policy_contents);
+void SetUpMinijail(const std::string& base_policy_path,
+                   const std::string& additional_policy_path);
+void SetUpMinijailList(const std::string& base_policy_path,
+                       const std::vector<std::string>& additional_policy_paths);
 }
 
 #endif  // AV_SERVICES_MINIJAIL_MINIJAIL
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 82cc90e..c9bf72f 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -76,6 +76,7 @@
         result << "  ExclusiveFoundCount:   " << mExclusiveFoundCount << "\n";
         result << "  ExclusiveOpenCount:    " << mExclusiveOpenCount << "\n";
         result << "  ExclusiveCloseCount:   " << mExclusiveCloseCount << "\n";
+        result << "  ExclusiveStolenCount:  " << mExclusiveStolenCount << "\n";
         result << "\n";
 
         if (isExclusiveLocked) {
@@ -142,7 +143,13 @@
 sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
                                         const aaudio::AAudioStreamRequest &request) {
     if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
-        return openExclusiveEndpoint(audioService, request);
+        sp<AAudioServiceEndpoint> endpointToSteal;
+        sp<AAudioServiceEndpoint> foundEndpoint =
+                openExclusiveEndpoint(audioService, request, endpointToSteal);
+        if (endpointToSteal.get()) {
+            endpointToSteal->releaseRegisteredStreams(); // free the MMAP resource
+        }
+        return foundEndpoint;
     } else {
         return openSharedEndpoint(audioService, request);
     }
@@ -150,7 +157,8 @@
 
 sp<AAudioServiceEndpoint> AAudioEndpointManager::openExclusiveEndpoint(
         AAudioService &aaudioService,
-        const aaudio::AAudioStreamRequest &request) {
+        const aaudio::AAudioStreamRequest &request,
+        sp<AAudioServiceEndpoint> &endpointToSteal) {
 
     std::lock_guard<std::mutex> lock(mExclusiveLock);
 
@@ -161,18 +169,22 @@
 
     // If we find an existing one then this one cannot be exclusive.
     if (endpoint.get() != nullptr) {
-        ALOGW("openExclusiveEndpoint() already in use");
-        // Already open so do not allow a second stream.
+        if (kStealingEnabled
+                && !endpoint->isForSharing() // not currently SHARED
+                && !request.isSharingModeMatchRequired()) { // app did not request a shared stream
+            ALOGD("%s() endpoint in EXCLUSIVE use. Steal it!", __func__);
+            mExclusiveStolenCount++;
+            endpointToSteal = endpoint;
+        }
         return nullptr;
     } else {
         sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP(aaudioService);
-        ALOGV("openExclusiveEndpoint(), no match so try to open MMAP %p for dev %d",
-              endpointMMap.get(), configuration.getDeviceId());
+        ALOGV("%s(), no match so try to open MMAP %p for dev %d",
+              __func__, endpointMMap.get(), configuration.getDeviceId());
         endpoint = endpointMMap;
 
         aaudio_result_t result = endpoint->open(request);
         if (result != AAUDIO_OK) {
-            ALOGV("openExclusiveEndpoint(), open failed");
             endpoint.clear();
         } else {
             mExclusiveStreams.push_back(endpointMMap);
@@ -183,7 +195,9 @@
     if (endpoint.get() != nullptr) {
         // Increment the reference count under this lock.
         endpoint->setOpenCount(endpoint->getOpenCount() + 1);
+        endpoint->setForSharing(request.isSharingModeMatchRequired());
     }
+
     return endpoint;
 }
 
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index ba17853..ae776b1 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -19,6 +19,7 @@
 
 #include <map>
 #include <mutex>
+#include <sys/types.h>
 #include <utils/Singleton.h>
 
 #include "binding/AAudioServiceMessage.h"
@@ -62,7 +63,8 @@
 
 private:
     android::sp<AAudioServiceEndpoint> openExclusiveEndpoint(android::AAudioService &aaudioService,
-                                                 const aaudio::AAudioStreamRequest &request);
+                                                 const aaudio::AAudioStreamRequest &request,
+                                                 sp<AAudioServiceEndpoint> &endpointToSteal);
 
     android::sp<AAudioServiceEndpoint> openSharedEndpoint(android::AAudioService &aaudioService,
                                               const aaudio::AAudioStreamRequest &request);
@@ -91,11 +93,16 @@
     int32_t mExclusiveFoundCount  = 0; // number of times we FOUND an exclusive endpoint
     int32_t mExclusiveOpenCount   = 0; // number of times we OPENED an exclusive endpoint
     int32_t mExclusiveCloseCount  = 0; // number of times we CLOSED an exclusive endpoint
+    int32_t mExclusiveStolenCount = 0; // number of times we STOLE an exclusive endpoint
+
     // Same as above but for SHARED endpoints.
     int32_t mSharedSearchCount    = 0;
     int32_t mSharedFoundCount     = 0;
     int32_t mSharedOpenCount      = 0;
     int32_t mSharedCloseCount     = 0;
+
+    // For easily disabling the stealing of exclusive streams.
+    static constexpr bool kStealingEnabled = true;
 };
 } /* namespace aaudio */
 
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index af8c67b..ecbcb7e 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -85,6 +85,17 @@
 
 aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
                                           aaudio::AAudioStreamConfiguration &configurationOutput) {
+    // A lock in is used to order the opening of endpoints when an
+    // EXCLUSIVE endpoint is stolen. We want the order to be:
+    // 1) Thread A opens exclusive MMAP endpoint
+    // 2) Thread B wants to open an exclusive MMAP endpoint so it steals the one from A
+    //    under this lock.
+    // 3) Thread B opens a shared MMAP endpoint.
+    // 4) Thread A can then get the lock and also open a shared stream.
+    // Without the lock. Thread A might sneak in and reallocate an exclusive stream
+    // before B can open the shared stream.
+    std::unique_lock<std::recursive_mutex> lock(mOpenLock);
+
     aaudio_result_t result = AAUDIO_OK;
     sp<AAudioServiceStreamBase> serviceStream;
     const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
@@ -139,11 +150,14 @@
         return result;
     } else {
         aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
-        ALOGV("openStream(): handle = 0x%08X", handle);
         serviceStream->setHandle(handle);
         pid_t pid = request.getProcessId();
         AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
         configurationOutput.copyFrom(*serviceStream);
+        // Log open in MediaMetrics after we have the handle because we need the handle to
+        // create the metrics ID.
+        serviceStream->logOpen(handle);
+        ALOGV("%s(): return handle = 0x%08X", __func__, handle);
         return handle;
     }
 }
@@ -177,7 +191,10 @@
         ALOGE("closeStream(0x%0x), illegal stream handle", streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
+    return closeStream(serviceStream);
+}
 
+aaudio_result_t AAudioService::closeStream(sp<AAudioServiceStreamBase> serviceStream) {
     pid_t pid = serviceStream->getOwnerProcessId();
     AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
 
@@ -310,14 +327,15 @@
 }
 
 aaudio_result_t AAudioService::startClient(aaudio_handle_t streamHandle,
-                                  const android::AudioClient& client,
-                                  audio_port_handle_t *clientHandle) {
+                                           const android::AudioClient& client,
+                                           const audio_attributes_t *attr,
+                                           audio_port_handle_t *clientHandle) {
     sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
     if (serviceStream.get() == nullptr) {
         ALOGE("%s(), illegal stream handle = 0x%0x", __func__, streamHandle);
         return AAUDIO_ERROR_INVALID_HANDLE;
     }
-    aaudio_result_t result = serviceStream->startClient(client, clientHandle);
+    aaudio_result_t result = serviceStream->startClient(client, attr, clientHandle);
     return checkForPendingClose(serviceStream, result);
 }
 
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index 43a59c3..6a2ac1f 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -55,6 +55,10 @@
                                        aaudio::AAudioStreamConfiguration &configurationOutput)
                                        override;
 
+    /*
+     * This is called from Binder. It checks for permissions
+     * and converts the handle passed through Binder to a stream pointer.
+     */
     aaudio_result_t closeStream(aaudio::aaudio_handle_t streamHandle) override;
 
     aaudio_result_t getStreamDescription(
@@ -77,14 +81,25 @@
                                                   pid_t tid) override;
 
     aaudio_result_t startClient(aaudio::aaudio_handle_t streamHandle,
-                                      const android::AudioClient& client,
-                                      audio_port_handle_t *clientHandle) override;
+                                const android::AudioClient& client,
+                                const audio_attributes_t *attr,
+                                audio_port_handle_t *clientHandle) override;
 
     aaudio_result_t stopClient(aaudio::aaudio_handle_t streamHandle,
                                        audio_port_handle_t clientHandle) override;
 
+ // ===============================================================================
+ // The following public methods are only called from the service and NOT by Binder.
+ // ===============================================================================
+
     aaudio_result_t disconnectStreamByPortHandle(audio_port_handle_t portHandle);
 
+    /*
+     * This is only called from within the Service.
+     * It bypasses the permission checks in closeStream(handle).
+     */
+    aaudio_result_t closeStream(sp<aaudio::AAudioServiceStreamBase> serviceStream);
+
 private:
 
     /** @return true if the client is the audioserver
@@ -99,8 +114,6 @@
     sp<aaudio::AAudioServiceStreamBase> convertHandleToServiceStream(
             aaudio::aaudio_handle_t streamHandle);
 
-
-
     bool releaseStream(const sp<aaudio::AAudioServiceStreamBase> &serviceStream);
 
     aaudio_result_t checkForPendingClose(const sp<aaudio::AAudioServiceStreamBase> &serviceStream,
@@ -110,10 +123,15 @@
 
     aaudio::AAudioStreamTracker     mStreamTracker;
 
+    // We use a lock to prevent thread A from reopening an exclusive stream
+    // after thread B steals thread A's exclusive MMAP resource stream.
+    std::recursive_mutex            mOpenLock;
+
     // TODO  Extract the priority constants from services/audioflinger/Threads.cpp
     // and share them with this code. Look for "kPriorityFastMixer".
     static constexpr int32_t        kRealTimeAudioPriorityClient = 2;
     static constexpr int32_t        kRealTimeAudioPriorityService = 3;
+
 };
 
 } /* namespace android */
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 2753f1f..b09cbf4 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -27,13 +27,13 @@
 
 #include <utils/Singleton.h>
 
-#include "AAudioEndpointManager.h"
-#include "AAudioServiceEndpoint.h"
 
 #include "core/AudioStreamBuilder.h"
+
+#include "AAudioEndpointManager.h"
+#include "AAudioClientTracker.h"
 #include "AAudioServiceEndpoint.h"
 #include "AAudioServiceStreamShared.h"
-#include "AAudioServiceEndpointShared.h"
 
 using namespace android;  // TODO just import names needed
 using namespace aaudio;   // TODO just import names needed
@@ -87,16 +87,31 @@
     return false;
 }
 
-void AAudioServiceEndpoint::disconnectRegisteredStreams() {
+std::vector<android::sp<AAudioServiceStreamBase>>
+        AAudioServiceEndpoint::disconnectRegisteredStreams() {
+    std::vector<android::sp<AAudioServiceStreamBase>> streamsDisconnected;
     std::lock_guard<std::mutex> lock(mLockStreams);
     mConnected.store(false);
-    for (const auto& stream : mRegisteredStreams) {
-        ALOGD("disconnectRegisteredStreams() stop and disconnect port %d",
-              stream->getPortHandle());
+    for (const auto &stream : mRegisteredStreams) {
+        ALOGD("%s() - stop and disconnect port %d", __func__, stream->getPortHandle());
         stream->stop();
         stream->disconnect();
     }
-    mRegisteredStreams.clear();
+    mRegisteredStreams.swap(streamsDisconnected);
+    return streamsDisconnected;
+}
+
+void AAudioServiceEndpoint::releaseRegisteredStreams() {
+    // List of streams to be closed after we disconnect everything.
+    std::vector<android::sp<AAudioServiceStreamBase>> streamsToClose
+            = disconnectRegisteredStreams();
+
+    // Close outside the lock to avoid recursive locks.
+    AAudioService *aaudioService = AAudioClientTracker::getInstance().getAAudioService();
+    for (const auto& serviceStream : streamsToClose) {
+        ALOGD("%s() - close stream 0x%08X", __func__, serviceStream->getHandle());
+        aaudioService->closeStream(serviceStream);
+    }
 }
 
 aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamBase>stream) {
@@ -138,3 +153,36 @@
     }
     return true;
 }
+
+// static
+audio_attributes_t AAudioServiceEndpoint::getAudioAttributesFrom(
+        const AAudioStreamParameters *params) {
+    if (params == nullptr) {
+        return {};
+    }
+    const aaudio_direction_t direction = params->getDirection();
+
+    const audio_content_type_t contentType =
+            AAudioConvert_contentTypeToInternal(params->getContentType());
+    // Usage only used for OUTPUT
+    const audio_usage_t usage = (direction == AAUDIO_DIRECTION_OUTPUT)
+            ? AAudioConvert_usageToInternal(params->getUsage())
+            : AUDIO_USAGE_UNKNOWN;
+    const audio_source_t source = (direction == AAUDIO_DIRECTION_INPUT)
+            ? AAudioConvert_inputPresetToAudioSource(params->getInputPreset())
+            : AUDIO_SOURCE_DEFAULT;
+    audio_flags_mask_t flags;
+    if (direction == AAUDIO_DIRECTION_OUTPUT) {
+        flags = AUDIO_FLAG_LOW_LATENCY
+            | AAudioConvert_allowCapturePolicyToAudioFlagsMask(params->getAllowedCapturePolicy());
+    } else {
+        flags = AUDIO_FLAG_LOW_LATENCY
+            | AAudioConvert_privacySensitiveToAudioFlagsMask(params->isPrivacySensitive());
+    }
+    return {
+            .content_type = contentType,
+            .usage = usage,
+            .source = source,
+            .flags = flags,
+            .tags = "" };
+}
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index a2f66a5..a171cb0 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -60,6 +60,7 @@
                                        audio_port_handle_t clientHandle) = 0;
 
     virtual aaudio_result_t startClient(const android::AudioClient& client,
+                                        const audio_attributes_t *attr,
                                         audio_port_handle_t *clientHandle) {
         ALOGD("AAudioServiceEndpoint::startClient(...) AAUDIO_ERROR_UNAVAILABLE");
         return AAUDIO_ERROR_UNAVAILABLE;
@@ -108,6 +109,23 @@
         return mConnected;
     }
 
+    static audio_attributes_t getAudioAttributesFrom(const AAudioStreamParameters *params);
+
+    // Stop, disconnect and release any streams registered on this endpoint.
+    void releaseRegisteredStreams();
+
+    bool isForSharing() const {
+        return mForSharing;
+    }
+
+    /**
+     *
+     * @param flag true if this endpoint is to be shared between multiple streams
+     */
+    void setForSharing(bool flag) {
+        mForSharing = flag;
+    }
+
 protected:
 
     /**
@@ -116,7 +134,7 @@
      */
     bool                     isStreamRegistered(audio_port_handle_t portHandle);
 
-    void                     disconnectRegisteredStreams();
+    std::vector<android::sp<AAudioServiceStreamBase>> disconnectRegisteredStreams();
 
     mutable std::mutex       mLockStreams;
     std::vector<android::sp<AAudioServiceStreamBase>> mRegisteredStreams;
@@ -129,7 +147,11 @@
     int32_t                  mOpenCount = 0;
     int32_t                  mRequestedDeviceId = 0;
 
+    // True if this will be shared by one or more other streams.
+    bool                     mForSharing = false;
+
     std::atomic<bool>        mConnected{true};
+
 };
 
 } /* namespace aaudio */
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 5bdb8eb..9dab770 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -79,32 +79,7 @@
 
     copyFrom(request.getConstantConfiguration());
 
-    aaudio_direction_t direction = getDirection();
-
-    const audio_content_type_t contentType =
-            AAudioConvert_contentTypeToInternal(getContentType());
-    // Usage only used for OUTPUT
-    const audio_usage_t usage = (direction == AAUDIO_DIRECTION_OUTPUT)
-            ? AAudioConvert_usageToInternal(getUsage())
-            : AUDIO_USAGE_UNKNOWN;
-    const audio_source_t source = (direction == AAUDIO_DIRECTION_INPUT)
-            ? AAudioConvert_inputPresetToAudioSource(getInputPreset())
-            : AUDIO_SOURCE_DEFAULT;
-    audio_flags_mask_t flags;
-    if (direction == AAUDIO_DIRECTION_OUTPUT) {
-        flags = AUDIO_FLAG_LOW_LATENCY
-            | AAudioConvert_allowCapturePolicyToAudioFlagsMask(getAllowedCapturePolicy());
-    } else {
-        flags = AUDIO_FLAG_LOW_LATENCY
-            | AAudioConvert_privacySensitiveToAudioFlagsMask(isPrivacySensitive());
-    }
-    const audio_attributes_t attributes = {
-            .content_type = contentType,
-            .usage = usage,
-            .source = source,
-            .flags = flags,
-            .tags = ""
-    };
+    const audio_attributes_t attributes = getAudioAttributesFrom(this);
 
     mMmapClient.clientUid = request.getUserId();
     mMmapClient.clientPid = request.getProcessId();
@@ -127,6 +102,8 @@
 
     int32_t aaudioSamplesPerFrame = getSamplesPerFrame();
 
+    const aaudio_direction_t direction = getDirection();
+
     if (direction == AAUDIO_DIRECTION_OUTPUT) {
         config.channel_mask = (aaudioSamplesPerFrame == AAUDIO_UNSPECIFIED)
                               ? AUDIO_CHANNEL_OUT_STEREO
@@ -252,7 +229,7 @@
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::close() {
-    if (mMmapStream != 0) {
+    if (mMmapStream != nullptr) {
         // Needs to be explicitly cleared or CTS will fail but it is not clear why.
         mMmapStream.clear();
         // Apparently the above close is asynchronous. An attempt to open a new device
@@ -269,7 +246,12 @@
     // Start the client on behalf of the AAudio service.
     // Use the port handle that was provided by openMmapStream().
     audio_port_handle_t tempHandle = mPortHandle;
-    aaudio_result_t result = startClient(mMmapClient, &tempHandle);
+    audio_attributes_t attr = {};
+    if (stream != nullptr) {
+        attr = getAudioAttributesFrom(stream.get());
+    }
+    aaudio_result_t result = startClient(
+            mMmapClient, stream == nullptr ? nullptr : &attr, &tempHandle);
     // When AudioFlinger is passed a valid port handle then it should not change it.
     LOG_ALWAYS_FATAL_IF(tempHandle != mPortHandle,
                         "%s() port handle not expected to change from %d to %d",
@@ -294,9 +276,10 @@
 }
 
 aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
+                                                       const audio_attributes_t *attr,
                                                        audio_port_handle_t *clientHandle) {
     if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
-    status_t status = mMmapStream->start(client, clientHandle);
+    status_t status = mMmapStream->start(client, attr, clientHandle);
     return AAudioConvert_androidToAAudioResult(status);
 }
 
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index 5e815e0..f599066 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -59,7 +59,8 @@
                                audio_port_handle_t clientHandle) override;
 
     aaudio_result_t startClient(const android::AudioClient& client,
-                                        audio_port_handle_t *clientHandle)  override;
+                                const audio_attributes_t *attr,
+                                audio_port_handle_t *clientHandle)  override;
 
     aaudio_result_t stopClient(audio_port_handle_t clientHandle)  override;
 
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 9b3b3b8..21253c8 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -152,7 +152,9 @@
     }
 
     if (result == AAUDIO_OK) {
-        result = getStreamInternal()->startClient(sharedStream->getAudioClient(), clientHandle);
+        const audio_attributes_t attr = getAudioAttributesFrom(sharedStream.get());
+        result = getStreamInternal()->startClient(
+                sharedStream->getAudioClient(), &attr, clientHandle);
         if (result != AAUDIO_OK) {
             if (--mRunningStreamCount == 0) { // atomic
                 stopSharingThread();
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 39e90b1..dba9fb9 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -22,8 +22,12 @@
 #include <iostream>
 #include <mutex>
 
+#include <media/MediaMetricsItem.h>
+#include <media/TypeConverter.h>
+
 #include "binding/IAAudioService.h"
 #include "binding/AAudioServiceMessage.h"
+#include "core/AudioGlobal.h"
 #include "utility/AudioClock.h"
 
 #include "AAudioEndpointManager.h"
@@ -51,6 +55,14 @@
 }
 
 AAudioServiceStreamBase::~AAudioServiceStreamBase() {
+    // May not be set if open failed.
+    if (mMetricsId.size() > 0) {
+        mediametrics::LogItem(mMetricsId)
+                .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+                .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+                .record();
+    }
+
     // If the stream is deleted when OPEN or in use then audio resources will leak.
     // This would indicate an internal error. So we want to find this ASAP.
     LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
@@ -81,6 +93,36 @@
     return result.str();
 }
 
+void AAudioServiceStreamBase::logOpen(aaudio_handle_t streamHandle) {
+    // This is the first log sent from the AAudio Service for a stream.
+    mMetricsId = std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM)
+            + std::to_string(streamHandle);
+
+    audio_attributes_t attributes = AAudioServiceEndpoint::getAudioAttributesFrom(this);
+
+    // Once this item is logged by the server, the client with the same PID, UID
+    // can also log properties.
+    mediametrics::LogItem(mMetricsId)
+        .setPid(getOwnerProcessId())
+        .setUid(getOwnerUserId())
+        .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)getOwnerUserId())
+        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN)
+        // the following are immutable
+        .set(AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, (int32_t)getBufferCapacity())
+        .set(AMEDIAMETRICS_PROP_BURSTFRAMES, (int32_t)getFramesPerBurst())
+        .set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)getSamplesPerFrame())
+        .set(AMEDIAMETRICS_PROP_CONTENTTYPE, toString(attributes.content_type).c_str())
+        .set(AMEDIAMETRICS_PROP_DIRECTION,
+                AudioGlobal_convertDirectionToText(getDirection()))
+        .set(AMEDIAMETRICS_PROP_ENCODING, toString(getFormat()).c_str())
+        .set(AMEDIAMETRICS_PROP_ROUTEDDEVICEID, (int32_t)getDeviceId())
+        .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)getSampleRate())
+        .set(AMEDIAMETRICS_PROP_SESSIONID, (int32_t)getSessionId())
+        .set(AMEDIAMETRICS_PROP_SOURCE, toString(attributes.source).c_str())
+        .set(AMEDIAMETRICS_PROP_USAGE, toString(attributes.usage).c_str())
+        .record();
+}
+
 aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request) {
     AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
     aaudio_result_t result = AAUDIO_OK;
@@ -154,6 +196,10 @@
     }
 
     setState(AAUDIO_STREAM_STATE_CLOSED);
+
+    mediametrics::LogItem(mMetricsId)
+        .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE)
+        .record();
     return result;
 }
 
@@ -173,8 +219,17 @@
  * An AAUDIO_SERVICE_EVENT_STARTED will be sent to the client when complete.
  */
 aaudio_result_t AAudioServiceStreamBase::start() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAUDIO_OK;
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     if (isRunning()) {
         return AAUDIO_OK;
     }
@@ -204,11 +259,20 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::pause() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAUDIO_OK;
     if (!isRunning()) {
         return result;
     }
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_PAUSE)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     // Send it now because the timestamp gets rounded up when stopStream() is called below.
     // Also we don't need the timestamps while we are shutting down.
     sendCurrentTimestamp();
@@ -222,7 +286,8 @@
     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
     if (endpoint == nullptr) {
         ALOGE("%s() has no endpoint", __func__);
-        return AAUDIO_ERROR_INVALID_STATE;
+        result =  AAUDIO_ERROR_INVALID_STATE; // for MediaMetric tracking
+        return result;
     }
     result = endpoint->stopStream(this, mClientHandle);
     if (result != AAUDIO_OK) {
@@ -236,11 +301,20 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::stop() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAUDIO_OK;
     if (!isRunning()) {
         return result;
     }
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_STOP)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     setState(AAUDIO_STREAM_STATE_STOPPING);
 
     // Send it now because the timestamp gets rounded up when stopStream() is called below.
@@ -255,7 +329,8 @@
     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
     if (endpoint == nullptr) {
         ALOGE("%s() has no endpoint", __func__);
-        return AAUDIO_ERROR_INVALID_STATE;
+        result =  AAUDIO_ERROR_INVALID_STATE; // for MediaMetric tracking
+        return result;
     }
     // TODO wait for data to be played out
     result = endpoint->stopStream(this, mClientHandle);
@@ -280,11 +355,20 @@
 }
 
 aaudio_result_t AAudioServiceStreamBase::flush() {
+    const int64_t beginNs = AudioClock::getNanoseconds();
     aaudio_result_t result = AAudio_isFlushAllowed(getState());
     if (result != AAUDIO_OK) {
         return result;
     }
 
+    mediametrics::Defer defer([&] {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH)
+            .set(AMEDIAMETRICS_PROP_DURATIONNS, (int64_t)(AudioClock::getNanoseconds() - beginNs))
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)result)
+            .record(); });
+
     // Data will get flushed when the client receives the FLUSHED event.
     sendServiceEvent(AAUDIO_SERVICE_EVENT_FLUSHED);
     setState(AAUDIO_STREAM_STATE_FLUSHED);
@@ -321,6 +405,10 @@
 
 void AAudioServiceStreamBase::disconnect() {
     if (getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
+        mediametrics::LogItem(mMetricsId)
+            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT)
+            .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
+            .record();
         sendServiceEvent(AAUDIO_SERVICE_EVENT_DISCONNECTED);
         setState(AAUDIO_STREAM_STATE_DISCONNECTED);
     }
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 097bc64..79dd738 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -68,12 +68,15 @@
     // does not include EOL
     virtual std::string dump() const;
 
-    // -------------------------------------------------------------------
     /**
      * Open the device.
      */
     virtual aaudio_result_t open(const aaudio::AAudioStreamRequest &request) = 0;
 
+    // We log the CLOSE from the close() method. We needed this separate method to log the OPEN
+    // because we had to wait until we generated the handle.
+    void logOpen(aaudio_handle_t streamHandle);
+
     virtual aaudio_result_t close();
 
     /**
@@ -111,7 +114,8 @@
     virtual aaudio_result_t flush();
 
 
-    virtual aaudio_result_t startClient(const android::AudioClient& client __unused,
+    virtual aaudio_result_t startClient(const android::AudioClient& client,
+                                        const audio_attributes_t *attr __unused,
                                         audio_port_handle_t *clientHandle __unused) {
         ALOGD("AAudioServiceStreamBase::startClient(%p, ...) AAUDIO_ERROR_UNAVAILABLE", &client);
         return AAUDIO_ERROR_UNAVAILABLE;
@@ -311,6 +315,8 @@
     android::sp<AAudioServiceEndpoint> mServiceEndpoint;
     android::wp<AAudioServiceEndpoint> mServiceEndpointWeak;
 
+    std::string mMetricsId;  // set once during open()
+
 private:
 
     /**
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index f4e72b7..639a0a8 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -86,7 +86,7 @@
     aaudio_result_t result = AAudioServiceStreamBase::startDevice();
     if (!mInService && result == AAUDIO_OK) {
         // Note that this can sometimes take 200 to 300 msec for a cold start!
-        result = startClient(mMmapClient, &mClientHandle);
+        result = startClient(mMmapClient, nullptr /*const audio_attributes_t* */, &mClientHandle);
     }
     return result;
 }
@@ -117,14 +117,15 @@
 }
 
 aaudio_result_t AAudioServiceStreamMMAP::startClient(const android::AudioClient& client,
-                                                       audio_port_handle_t *clientHandle) {
+                                                     const audio_attributes_t *attr,
+                                                     audio_port_handle_t *clientHandle) {
     sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
     if (endpoint == nullptr) {
         ALOGE("%s() has no endpoint", __func__);
         return AAUDIO_ERROR_INVALID_STATE;
     }
     // Start the client on behalf of the application. Generate a new porthandle.
-    aaudio_result_t result = endpoint->startClient(client, clientHandle);
+    aaudio_result_t result = endpoint->startClient(client, attr, clientHandle);
     return result;
 }
 
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 3d56623..9105469 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -63,6 +63,7 @@
     aaudio_result_t stop() override;
 
     aaudio_result_t startClient(const android::AudioClient& client,
+                                const audio_attributes_t *attr,
                                 audio_port_handle_t *clientHandle) override;
 
     aaudio_result_t stopClient(audio_port_handle_t clientHandle) override;
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 64d835b..8b1e2c0 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -47,11 +47,13 @@
         "libaudioclient",
         "libaudioflinger",
         "libaudioutils",
+        "libmedia_helper",
+        "libmediametrics",
+        "libmediautils",
         "libbase",
         "libbinder",
         "libcutils",
         "liblog",
-        "libmediautils",
         "libutils",
     ],