Merge "Make file_contexts as "android:path" property" am: b8ec243b5f am: aba4ae6692
am: 7dfdf76702

Change-Id: Ibbaaa6241345c1ffe4bba60fdcb559c3db423ce8
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index f56e1b5..ec8f049 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -38,9 +38,14 @@
 namespace.platform.isolated = true
 
 namespace.platform.search.paths  = /system/${LIB}
-namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
 namespace.platform.asan.search.paths  = /data/asan/system/${LIB}
 namespace.platform.asan.search.paths +=           /system/${LIB}
+
+# TODO(b/140790209): These directories are wrong in R and later because they
+# only contain Bionic internal libraries dependencies that should not be
+# accessed from the outside. However, they may be necessary for APEX builds that
+# are pushed to Q. Remove them as soon as Q compatibility is no longer required.
+namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
 namespace.platform.asan.search.paths += /apex/com.android.runtime/${LIB}
 
 # /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
diff --git a/apex/manifest.json b/apex/manifest.json
index 3011ee8..ddd642e 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.media",
-  "version": 290000000
+  "version": 300000000
 }
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index 83a5178..2320fd7 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.media.swcodec",
-  "version": 290000000
+  "version": 300000000
 }
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index c6c35ef..84d1d93 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -347,6 +347,20 @@
     return c->setPreviewCallbackTarget(callbackProducer);
 }
 
+status_t Camera::setAudioRestriction(int32_t mode)
+{
+    sp <::android::hardware::ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->setAudioRestriction(mode);
+}
+
+int32_t Camera::getGlobalAudioRestriction()
+{
+    sp <::android::hardware::ICamera> c = mCamera;
+    if (c == 0) return NO_INIT;
+    return c->getGlobalAudioRestriction();
+}
+
 // callback from camera service
 void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
 {
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index f0945c7..b83edf7 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -56,6 +56,8 @@
     SET_VIDEO_BUFFER_TARGET,
     RELEASE_RECORDING_FRAME_HANDLE,
     RELEASE_RECORDING_FRAME_HANDLE_BATCH,
+    SET_AUDIO_RESTRICTION,
+    GET_GLOBAL_AUDIO_RESTRICTION,
 };
 
 class BpCamera: public BpInterface<ICamera>
@@ -191,6 +193,21 @@
         }
     }
 
+    status_t setAudioRestriction(int32_t mode) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        data.writeInt32(mode);
+        remote()->transact(SET_AUDIO_RESTRICTION, data, &reply);
+        return reply.readInt32();
+    }
+
+    int32_t getGlobalAudioRestriction() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+        remote()->transact(GET_GLOBAL_AUDIO_RESTRICTION, data, &reply);
+        return reply.readInt32();
+    }
+
     status_t setVideoBufferMode(int32_t videoBufferMode)
     {
         ALOGV("setVideoBufferMode: %d", videoBufferMode);
@@ -494,6 +511,17 @@
             reply->writeInt32(setVideoTarget(st));
             return NO_ERROR;
         } break;
+        case SET_AUDIO_RESTRICTION: {
+            CHECK_INTERFACE(ICamera, data, reply);
+            int32_t mode = data.readInt32();
+            reply->writeInt32(setAudioRestriction(mode));
+            return NO_ERROR;
+        } break;
+        case GET_GLOBAL_AUDIO_RESTRICTION: {
+            CHECK_INTERFACE(ICamera, data, reply);
+            reply->writeInt32(getGlobalAudioRestriction());
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 3e8992a..62dbb5e 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -87,6 +87,7 @@
     ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,
             String cameraId,
             String opPackageName,
+            @nullable String featureId,
             int clientUid);
 
     /**
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 49dfde8..93549e0 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -155,4 +155,26 @@
     void updateOutputConfiguration(int streamId, in OutputConfiguration outputConfiguration);
 
     void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
+
+
+    // Keep in sync with public API in
+    // frameworks/base/core/java/android/hardware/camera2/CameraDevice.java
+    const int AUDIO_RESTRICTION_NONE = 0;
+    const int AUDIO_RESTRICTION_VIBRATION = 1;
+    const int AUDIO_RESTRICTION_VIBRATION_SOUND = 3;
+
+    /**
+      * Set audio restriction mode for this camera device.
+      *
+      * @param mode the audio restriction mode ID as above
+      *
+      */
+    void setCameraAudioRestriction(int mode);
+
+    /**
+      * Get global audio restriction mode for all camera clients.
+      *
+      * @return the currently applied system-wide audio restriction mode
+      */
+    int getGlobalAudioRestriction();
 }
diff --git a/camera/include/camera/Camera.h b/camera/include/camera/Camera.h
index 430aa1c..2cdb617 100644
--- a/camera/include/camera/Camera.h
+++ b/camera/include/camera/Camera.h
@@ -167,6 +167,9 @@
 
             sp<ICameraRecordingProxy> getRecordingProxy();
 
+            status_t     setAudioRestriction(int32_t mode);
+            int32_t      getGlobalAudioRestriction();
+
     // ICameraClient interface
     virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
     virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
diff --git a/camera/include/camera/android/hardware/ICamera.h b/camera/include/camera/android/hardware/ICamera.h
index 80823d6..ec19e5d 100644
--- a/camera/include/camera/android/hardware/ICamera.h
+++ b/camera/include/camera/android/hardware/ICamera.h
@@ -140,6 +140,12 @@
     // Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
     virtual status_t        setVideoTarget(
             const sp<IGraphicBufferProducer>& bufferProducer) = 0;
+
+    // Set the audio restriction mode
+    virtual status_t        setAudioRestriction(int32_t mode) = 0;
+
+    // Get the global audio restriction mode
+    virtual int32_t         getGlobalAudioRestriction() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index d6f1412..68db233 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -33,7 +33,9 @@
         dev->unlockDevice();
     }
     // Fire onClosed callback
-    (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+    if (mUserSessionCallback.onClosed != nullptr) {
+        (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
+    }
     ALOGV("~ACameraCaptureSession: %p is deleted", this);
 }
 
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 9d40fd7..8eb030a 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -517,7 +517,7 @@
     // No way to get package name from native.
     // Send a zero length package name and let camera service figure it out from UID
     binder::Status serviceRet = cs->connectDevice(
-            callbacks, String16(cameraId), String16(""),
+            callbacks, String16(cameraId), String16(""), std::unique_ptr<String16>(),
             hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
 
     if (!serviceRet.isOk()) {
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 77dcd48..7c41b5e 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -479,6 +479,7 @@
         case ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE:
         case ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST:
         case ACAMERA_CONTROL_ENABLE_ZSL:
+        case ACAMERA_CONTROL_BOKEH_MODE:
         case ACAMERA_EDGE_MODE:
         case ACAMERA_FLASH_MODE:
         case ACAMERA_HOT_PIXEL_MODE:
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 8dd6e00..825f308 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -140,7 +140,7 @@
      * application controls how the color mapping is performed.</p>
      * <p>We define the expected processing pipeline below. For consistency
      * across devices, this is always the case with TRANSFORM_MATRIX.</p>
-     * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+     * <p>When either FAST or HIGH_QUALITY is used, the camera device may
      * do additional processing but ACAMERA_COLOR_CORRECTION_GAINS and
      * ACAMERA_COLOR_CORRECTION_TRANSFORM will still be provided by the
      * camera device (in the results) and be roughly correct.</p>
@@ -1126,10 +1126,17 @@
      * </ul>
      * <p>For devices at the LIMITED level or above:</p>
      * <ul>
-     * <li>For YUV_420_888 burst capture use case, this list will always include (<code>min</code>, <code>max</code>)
-     * and (<code>max</code>, <code>max</code>) where <code>min</code> &lt;= 15 and <code>max</code> = the maximum output frame rate of the
+     * <li>For devices that advertise NIR color filter arrangement in
+     * ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, this list will always include
+     * (<code>max</code>, <code>max</code>) where <code>max</code> = the maximum output frame rate of the maximum YUV_420_888
+     * output size.</li>
+     * <li>For devices advertising any color filter arrangement other than NIR, or devices not
+     * advertising color filter arrangement, this list will always include (<code>min</code>, <code>max</code>) and
+     * (<code>max</code>, <code>max</code>) where <code>min</code> &lt;= 15 and <code>max</code> = the maximum output frame rate of the
      * maximum YUV_420_888 output size.</li>
      * </ul>
+     *
+     * @see ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
      */
     ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES =            // int32[2*n]
             ACAMERA_CONTROL_START + 20,
@@ -1727,6 +1734,77 @@
      */
     ACAMERA_CONTROL_AF_SCENE_CHANGE =                           // byte (acamera_metadata_enum_android_control_af_scene_change_t)
             ACAMERA_CONTROL_START + 42,
+    /**
+     * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
+     * maximum streaming (non-stall) size with bokeh effect.</p>
+     *
+     * <p>Type: int32[3*n]</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+     * </ul></p>
+     *
+     * <p>For OFF mode, the camera behaves normally with no bokeh effect.</p>
+     * <p>For STILL_CAPTURE mode, the maximum streaming dimension specifies the limit under which
+     * bokeh is effective when capture intent is PREVIEW. Note that when capture intent is
+     * PREVIEW, the bokeh effect may not be as high quality compared to STILL_CAPTURE intent
+     * in order to maintain reasonable frame rate. The maximum streaming dimension must be one
+     * of the YUV_420_888 or PRIVATE resolutions in availableStreamConfigurations, or (0, 0)
+     * if preview bokeh is not supported. If the application configures a stream larger than
+     * the maximum streaming dimension, bokeh effect may not be applied for this stream for
+     * PREVIEW intent.</p>
+     * <p>For CONTINUOUS mode, the maximum streaming dimension specifies the limit under which
+     * bokeh is effective. This dimension must be one of the YUV_420_888 or PRIVATE resolutions
+     * in availableStreamConfigurations, and if the sensor maximum resolution is larger than or
+     * equal to 1080p, the maximum streaming dimension must be at least 1080p. If the
+     * application configures a stream with larger dimension, the stream may not have bokeh
+     * effect applied.</p>
+     */
+    ACAMERA_CONTROL_AVAILABLE_BOKEH_CAPABILITIES =              // int32[3*n]
+            ACAMERA_CONTROL_START + 43,
+    /**
+     * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+     *
+     * <p>Type: byte (acamera_metadata_enum_android_control_bokeh_mode_t)</p>
+     *
+     * <p>This tag may appear in:
+     * <ul>
+     *   <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+     *   <li>ACaptureRequest</li>
+     * </ul></p>
+     *
+     * <p>With bokeh mode, the camera device may blur out the parts of scene that are not in
+     * focus, creating a bokeh (or shallow depth of field) effect for people or objects.</p>
+     * <p>When set to STILL_CAPTURE bokeh mode with STILL_CAPTURE capture intent, due to the extra
+     * processing needed for high quality bokeh effect, the stall may be longer than when
+     * capture intent is not STILL_CAPTURE.</p>
+     * <p>When set to STILL_CAPTURE bokeh mode with PREVIEW capture intent,</p>
+     * <ul>
+     * <li>If the camera device has BURST_CAPTURE capability, the frame rate requirement of
+     * BURST_CAPTURE must still be met.</li>
+     * <li>All streams not larger than the maximum streaming dimension for STILL_CAPTURE mode
+     * (queried via {@link ACAMERA_CONTROL_AVAILABLE_BOKEH_CAPABILITIES })
+     * will have preview bokeh effect applied.</li>
+     * </ul>
+     * <p>When set to CONTINUOUS mode, configured streams dimension should not exceed this mode's
+     * maximum streaming dimension in order to have bokeh effect applied. Bokeh effect may not
+     * be available for streams larger than the maximum streaming dimension.</p>
+     * <p>Switching between different bokeh modes may involve reconfiguration of the camera
+     * pipeline, resulting in long latency. The application should check this key against the
+     * available session keys queried via
+     * {@link ACameraManager_getCameraCharacteristics }.</p>
+     * <p>When bokeh mode is on, the camera device may override certain control parameters, such as
+     * reduce frame rate or use face priority scene mode, to achieve best power and quality
+     * tradeoffs. When turned on, AE, AWB, and AF run in auto modes, and only the mandatory
+     * stream combinations of LIMITED hardware level are guaranteed.</p>
+     * <p>For a logical multi-camera, bokeh may be implemented by stereo vision from sub-cameras
+     * with different field of view. As a result, when bokeh mode is enabled, the camera device
+     * may override android.scaler.CropRegion, and the field of view will be smaller than when
+     * bokeh mode is off.</p>
+     */
+    ACAMERA_CONTROL_BOKEH_MODE =                                // byte (acamera_metadata_enum_android_control_bokeh_mode_t)
+            ACAMERA_CONTROL_START + 44,
     ACAMERA_CONTROL_END,
 
     /**
@@ -3536,11 +3614,19 @@
      * output capture result.</p>
      * <p>This control is only effective if ACAMERA_CONTROL_AE_MODE or ACAMERA_CONTROL_MODE is set to
      * OFF; otherwise the auto-exposure algorithm will override this value.</p>
+     * <p>Note that for devices supporting postRawSensitivityBoost, the total sensitivity applied
+     * to the final processed image is the combination of ACAMERA_SENSOR_SENSITIVITY and
+     * ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST. In case the application uses the sensor
+     * sensitivity from last capture result of an auto request for a manual request, in order
+     * to achieve the same brightness in the output image, the application should also
+     * set postRawSensitivityBoost.</p>
      *
      * @see ACAMERA_CONTROL_AE_MODE
      * @see ACAMERA_CONTROL_MODE
+     * @see ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST
      * @see ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE
      * @see ACAMERA_SENSOR_MAX_ANALOG_SENSITIVITY
+     * @see ACAMERA_SENSOR_SENSITIVITY
      */
     ACAMERA_SENSOR_SENSITIVITY =                                // int32
             ACAMERA_SENSOR_START + 2,
@@ -6987,6 +7073,31 @@
 
 } acamera_metadata_enum_android_control_af_scene_change_t;
 
+// ACAMERA_CONTROL_BOKEH_MODE
+typedef enum acamera_metadata_enum_acamera_control_bokeh_mode {
+    /**
+     * <p>Bokeh mode is disabled.</p>
+     */
+    ACAMERA_CONTROL_BOKEH_MODE_OFF                                   = 0,
+
+    /**
+     * <p>High quality bokeh mode is enabled for all non-raw streams (including YUV,
+     * JPEG, and IMPLEMENTATION_DEFINED) when capture intent is STILL_CAPTURE. Due to the
+     * extra image processing, this mode may introduce additional stall to non-raw streams.
+     * This mode should be used in high quality still capture use case.</p>
+     */
+    ACAMERA_CONTROL_BOKEH_MODE_STILL_CAPTURE                         = 1,
+
+    /**
+     * <p>Bokeh effect must not slow down capture rate relative to sensor raw output,
+     * and the effect is applied to all processed streams no larger than the maximum
+     * streaming dimension. This mode should be used if performance and power are a
+     * priority, such as video recording.</p>
+     */
+    ACAMERA_CONTROL_BOKEH_MODE_CONTINUOUS                            = 2,
+
+} acamera_metadata_enum_android_control_bokeh_mode_t;
+
 
 
 // ACAMERA_EDGE_MODE
@@ -7751,6 +7862,13 @@
      */
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA         = 13,
 
+    /**
+     * <p>The camera device is only accessible by Android's system components and privileged
+     * applications. Processes need to have the android.permission.SYSTEM_CAMERA in
+     * addition to android.permission.CAMERA in order to connect to this camera device.</p>
+     */
+    ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA             = 14,
+
 } acamera_metadata_enum_android_request_available_capabilities_t;
 
 
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 7ab0124..938b5f5 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -253,21 +253,9 @@
         return true;
     }
 
-    static void onDeviceDisconnected(void* /*obj*/, ACameraDevice* /*device*/) {}
-
-    static void onDeviceError(void* /*obj*/, ACameraDevice* /*device*/, int /*errorCode*/) {}
-
-    static void onSessionClosed(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
-    static void onSessionReady(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
-    static void onSessionActive(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
-
    private:
-    ACameraDevice_StateCallbacks mDeviceCb{this, onDeviceDisconnected,
-                                           onDeviceError};
-    ACameraCaptureSession_stateCallbacks mSessionCb{
-        this, onSessionClosed, onSessionReady, onSessionActive};
+    ACameraDevice_StateCallbacks mDeviceCb{this, nullptr, nullptr};
+    ACameraCaptureSession_stateCallbacks mSessionCb{ this, nullptr, nullptr, nullptr};
 
     native_handle_t* mImgReaderAnw = nullptr;  // not owned by us.
 
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 8fe029a..9a18b10 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -57,7 +57,7 @@
 #include <algorithm>
 
 using namespace android;
-using ::android::hardware::ICameraServiceDefault;
+using ::android::hardware::ICameraService;
 using ::android::hardware::camera2::ICameraDeviceUser;
 
 #define ASSERT_NOT_NULL(x) \
@@ -361,7 +361,8 @@
         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
         sp<hardware::camera2::ICameraDeviceUser> device;
         res = service->connectDevice(callbacks, cameraId, String16("meeeeeeeee!"),
-                hardware::ICameraService::USE_CALLING_UID, /*out*/&device);
+                std::unique_ptr<String16>(), hardware::ICameraService::USE_CALLING_UID,
+                /*out*/&device);
         EXPECT_TRUE(res.isOk()) << res;
         ASSERT_NE(nullptr, device.get());
         device->disconnect();
@@ -403,7 +404,8 @@
         {
             SCOPED_TRACE("openNewDevice");
             binder::Status res = service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"),
-                    hardware::ICameraService::USE_CALLING_UID, /*out*/&device);
+                    std::unique_ptr<String16>(), hardware::ICameraService::USE_CALLING_UID,
+                    /*out*/&device);
             EXPECT_TRUE(res.isOk()) << res;
         }
         auto p = std::make_pair(callbacks, device);
@@ -507,7 +509,7 @@
         bool queryStatus;
         res = device->isSessionConfigurationSupported(sessionConfiguration, &queryStatus);
         EXPECT_TRUE(res.isOk() ||
-                (res.serviceSpecificErrorCode() == ICameraServiceDefault::ERROR_INVALID_OPERATION))
+                (res.serviceSpecificErrorCode() == ICameraService::ERROR_INVALID_OPERATION))
                 << res;
         if (res.isOk()) {
             EXPECT_TRUE(queryStatus);
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index f2a71b3..4a24b96 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -37,6 +37,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <utils/Errors.h>
+#include <utils/SystemClock.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
 
@@ -73,6 +74,7 @@
 using android::MediaMuxer;
 using android::Overlay;
 using android::PersistentSurface;
+using android::PhysicalDisplayId;
 using android::ProcessState;
 using android::Rect;
 using android::String8;
@@ -95,6 +97,8 @@
 static const uint32_t kFallbackWidth = 1280;        // 720p
 static const uint32_t kFallbackHeight = 720;
 static const char* kMimeTypeAvc = "video/avc";
+static const char* kMimeTypeApplicationOctetstream = "application/octet-stream";
+static const char* kWinscopeMagicString = "#VV1NSC0PET1ME!#";
 
 // Command-line parameters.
 static bool gVerbose = false;           // chatty on stdout
@@ -113,7 +117,7 @@
 static uint32_t gBitRate = 20000000;     // 20Mbps
 static uint32_t gTimeLimitSec = kMaxTimeLimitSec;
 static uint32_t gBframes = 0;
-
+static PhysicalDisplayId gPhysicalDisplayId;
 // Set by signal handler to stop recording.
 static volatile bool gStopRequested = false;
 
@@ -266,14 +270,14 @@
 static status_t setDisplayProjection(
         SurfaceComposerClient::Transaction& t,
         const sp<IBinder>& dpy,
-        const DisplayInfo& mainDpyInfo) {
+        const DisplayInfo& displayInfo) {
 
     // Set the region of the layer stack we're interested in, which in our
     // case is "all of it".
-    Rect layerStackRect(mainDpyInfo.viewportW, mainDpyInfo.viewportH);
+    Rect layerStackRect(displayInfo.viewportW, displayInfo.viewportH);
 
     // We need to preserve the aspect ratio of the display.
-    float displayAspect = (float) mainDpyInfo.viewportH / (float) mainDpyInfo.viewportW;
+    float displayAspect = (float) displayInfo.viewportH / (float) displayInfo.viewportW;
 
 
     // Set the way we map the output onto the display surface (which will
@@ -332,16 +336,15 @@
  * Configures the virtual display.  When this completes, virtual display
  * frames will start arriving from the buffer producer.
  */
-static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
+static status_t prepareVirtualDisplay(const DisplayInfo& displayInfo,
         const sp<IGraphicBufferProducer>& bufferProducer,
         sp<IBinder>* pDisplayHandle) {
     sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
             String8("ScreenRecorder"), false /*secure*/);
-
     SurfaceComposerClient::Transaction t;
     t.setDisplaySurface(dpy, bufferProducer);
-    setDisplayProjection(t, dpy, mainDpyInfo);
-    t.setDisplayLayerStack(dpy, 0);    // default stack
+    setDisplayProjection(t, dpy, displayInfo);
+    t.setDisplayLayerStack(dpy, displayInfo.layerStack);
     t.apply();
 
     *pDisplayHandle = dpy;
@@ -350,6 +353,50 @@
 }
 
 /*
+ * Writes an unsigned integer byte-by-byte in little endian order regardless
+ * of the platform endianness.
+ */
+template <typename UINT>
+static void writeValueLE(UINT value, uint8_t* buffer) {
+    for (int i = 0; i < sizeof(UINT); ++i) {
+        buffer[i] = static_cast<uint8_t>(value);
+        value >>= 8;
+    }
+}
+
+/*
+ * Saves frames presentation time relative to the elapsed realtime clock in microseconds
+ * preceded by a Winscope magic string and frame count to a metadata track.
+ * This metadata is used by the Winscope tool to sync video with SurfaceFlinger
+ * and WindowManager traces.
+ *
+ * The metadata is written as a binary array as follows:
+ * - winscope magic string (kWinscopeMagicString constant), without trailing null char,
+ * - the number of recorded frames (as little endian uint32),
+ * - for every frame its presentation time relative to the elapsed realtime clock in microseconds
+ *   (as little endian uint64).
+ */
+static status_t writeWinscopeMetadata(const Vector<int64_t>& timestamps,
+        const ssize_t metaTrackIdx, const sp<MediaMuxer>& muxer) {
+    ALOGV("Writing metadata");
+    int64_t systemTimeToElapsedTimeOffsetMicros = (android::elapsedRealtimeNano()
+        - systemTime(SYSTEM_TIME_MONOTONIC)) / 1000;
+    sp<ABuffer> buffer = new ABuffer(timestamps.size() * sizeof(int64_t)
+        + sizeof(uint32_t) + strlen(kWinscopeMagicString));
+    uint8_t* pos = buffer->data();
+    strcpy(reinterpret_cast<char*>(pos), kWinscopeMagicString);
+    pos += strlen(kWinscopeMagicString);
+    writeValueLE<uint32_t>(timestamps.size(), pos);
+    pos += sizeof(uint32_t);
+    for (size_t idx = 0; idx < timestamps.size(); ++idx) {
+        writeValueLE<uint64_t>(static_cast<uint64_t>(timestamps[idx]
+            + systemTimeToElapsedTimeOffsetMicros), pos);
+        pos += sizeof(uint64_t);
+    }
+    return muxer->writeSampleData(buffer, metaTrackIdx, timestamps[0], 0);
+}
+
+/*
  * Runs the MediaCodec encoder, sending the output to the MediaMuxer.  The
  * input frames are coming from the virtual display as fast as SurfaceFlinger
  * wants to send them.
@@ -359,15 +406,17 @@
  * The muxer must *not* have been started before calling.
  */
 static status_t runEncoder(const sp<MediaCodec>& encoder,
-        const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& mainDpy,
+        const sp<MediaMuxer>& muxer, FILE* rawFp, const sp<IBinder>& display,
         const sp<IBinder>& virtualDpy, uint8_t orientation) {
     static int kTimeout = 250000;   // be responsive on signal
     status_t err;
     ssize_t trackIdx = -1;
+    ssize_t metaTrackIdx = -1;
     uint32_t debugNumFrames = 0;
     int64_t startWhenNsec = systemTime(CLOCK_MONOTONIC);
     int64_t endWhenNsec = startWhenNsec + seconds_to_nanoseconds(gTimeLimitSec);
-    DisplayInfo mainDpyInfo;
+    DisplayInfo displayInfo;
+    Vector<int64_t> timestamps;
     bool firstFrame = true;
 
     assert((rawFp == NULL && muxer != NULL) || (rawFp != NULL && muxer == NULL));
@@ -423,16 +472,16 @@
                     //
                     // Polling for changes is inefficient and wrong, but the
                     // useful stuff is hard to get at without a Dalvik VM.
-                    err = SurfaceComposerClient::getDisplayInfo(mainDpy,
-                            &mainDpyInfo);
+                    err = SurfaceComposerClient::getDisplayInfo(display,
+                            &displayInfo);
                     if (err != NO_ERROR) {
                         ALOGW("getDisplayInfo(main) failed: %d", err);
-                    } else if (orientation != mainDpyInfo.orientation) {
-                        ALOGD("orientation changed, now %d", mainDpyInfo.orientation);
+                    } else if (orientation != displayInfo.orientation) {
+                        ALOGD("orientation changed, now %d", displayInfo.orientation);
                         SurfaceComposerClient::Transaction t;
-                        setDisplayProjection(t, virtualDpy, mainDpyInfo);
+                        setDisplayProjection(t, virtualDpy, displayInfo);
                         t.apply();
-                        orientation = mainDpyInfo.orientation;
+                        orientation = displayInfo.orientation;
                     }
                 }
 
@@ -471,6 +520,9 @@
                             "Failed writing data to muxer (err=%d)\n", err);
                         return err;
                     }
+                    if (gOutputFormat == FORMAT_MP4) {
+                        timestamps.add(ptsUsec);
+                    }
                 }
                 debugNumFrames++;
             }
@@ -497,6 +549,11 @@
                 encoder->getOutputFormat(&newFormat);
                 if (muxer != NULL) {
                     trackIdx = muxer->addTrack(newFormat);
+                    if (gOutputFormat == FORMAT_MP4) {
+                        sp<AMessage> metaFormat = new AMessage;
+                        metaFormat->setString(KEY_MIME, kMimeTypeApplicationOctetstream);
+                        metaTrackIdx = muxer->addTrack(metaFormat);
+                    }
                     ALOGV("Starting muxer");
                     err = muxer->start();
                     if (err != NO_ERROR) {
@@ -533,6 +590,13 @@
                         systemTime(CLOCK_MONOTONIC) - startWhenNsec));
         fflush(stdout);
     }
+    if (metaTrackIdx >= 0 && !timestamps.isEmpty()) {
+        err = writeWinscopeMetadata(timestamps, metaTrackIdx, muxer);
+        if (err != NO_ERROR) {
+            fprintf(stderr, "Failed writing metadata to muxer (err=%d)\n", err);
+            return err;
+        }
+    }
     return NO_ERROR;
 }
 
@@ -597,32 +661,33 @@
     self->startThreadPool();
 
     // Get main display parameters.
-    const sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
-    if (mainDpy == nullptr) {
+    sp<IBinder> display = SurfaceComposerClient::getPhysicalDisplayToken(
+            gPhysicalDisplayId);
+    if (display == nullptr) {
         fprintf(stderr, "ERROR: no display\n");
         return NAME_NOT_FOUND;
     }
 
-    DisplayInfo mainDpyInfo;
-    err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+    DisplayInfo displayInfo;
+    err = SurfaceComposerClient::getDisplayInfo(display, &displayInfo);
     if (err != NO_ERROR) {
         fprintf(stderr, "ERROR: unable to get display characteristics\n");
         return err;
     }
 
     if (gVerbose) {
-        printf("Main display is %dx%d @%.2ffps (orientation=%u)\n",
-                mainDpyInfo.viewportW, mainDpyInfo.viewportH, mainDpyInfo.fps,
-                mainDpyInfo.orientation);
+        printf("Display is %dx%d @%.2ffps (orientation=%u), layerStack=%u\n",
+                displayInfo.viewportW, displayInfo.viewportH, displayInfo.fps,
+                displayInfo.orientation, displayInfo.layerStack);
         fflush(stdout);
     }
 
     // Encoder can't take odd number as config
     if (gVideoWidth == 0) {
-        gVideoWidth = floorToEven(mainDpyInfo.viewportW);
+        gVideoWidth = floorToEven(displayInfo.viewportW);
     }
     if (gVideoHeight == 0) {
-        gVideoHeight = floorToEven(mainDpyInfo.viewportH);
+        gVideoHeight = floorToEven(displayInfo.viewportH);
     }
 
     // Configure and start the encoder.
@@ -630,7 +695,7 @@
     sp<FrameOutput> frameOutput;
     sp<IGraphicBufferProducer> encoderInputSurface;
     if (gOutputFormat != FORMAT_FRAMES && gOutputFormat != FORMAT_RAW_FRAMES) {
-        err = prepareEncoder(mainDpyInfo.fps, &encoder, &encoderInputSurface);
+        err = prepareEncoder(displayInfo.fps, &encoder, &encoderInputSurface);
 
         if (err != NO_ERROR && !gSizeSpecified) {
             // fallback is defined for landscape; swap if we're in portrait
@@ -643,7 +708,7 @@
                         gVideoWidth, gVideoHeight, newWidth, newHeight);
                 gVideoWidth = newWidth;
                 gVideoHeight = newHeight;
-                err = prepareEncoder(mainDpyInfo.fps, &encoder,
+                err = prepareEncoder(displayInfo.fps, &encoder,
                         &encoderInputSurface);
             }
         }
@@ -691,7 +756,7 @@
 
     // Configure virtual display.
     sp<IBinder> dpy;
-    err = prepareVirtualDisplay(mainDpyInfo, bufferProducer, &dpy);
+    err = prepareVirtualDisplay(displayInfo, bufferProducer, &dpy);
     if (err != NO_ERROR) {
         if (encoder != NULL) encoder->release();
         return err;
@@ -774,8 +839,8 @@
         }
     } else {
         // Main encoder loop.
-        err = runEncoder(encoder, muxer, rawFp, mainDpy, dpy,
-                mainDpyInfo.orientation);
+        err = runEncoder(encoder, muxer, rawFp, display, dpy,
+                displayInfo.orientation);
         if (err != NO_ERROR) {
             fprintf(stderr, "Encoder failed (err=%d)\n", err);
             // fall through to cleanup
@@ -941,6 +1006,9 @@
         "    in videos captured to illustrate bugs.\n"
         "--time-limit TIME\n"
         "    Set the maximum recording time, in seconds.  Default / maximum is %d.\n"
+        "--display-id ID\n"
+        "    specify the physical display ID to record. Default is the primary display.\n"
+        "    see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
         "--verbose\n"
         "    Display interesting information on stdout.\n"
         "--help\n"
@@ -972,9 +1040,18 @@
         { "monotonic-time",     no_argument,        NULL, 'm' },
         { "persistent-surface", no_argument,        NULL, 'p' },
         { "bframes",            required_argument,  NULL, 'B' },
+        { "display-id",         required_argument,  NULL, 'd' },
         { NULL,                 0,                  NULL, 0 }
     };
 
+    std::optional<PhysicalDisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
+    if (!displayId) {
+        fprintf(stderr, "Failed to get token for internal display\n");
+        return 1;
+    }
+
+    gPhysicalDisplayId = *displayId;
+
     while (true) {
         int optionIndex = 0;
         int ic = getopt_long(argc, argv, "", longOptions, &optionIndex);
@@ -1069,6 +1146,18 @@
                 return 2;
             }
             break;
+        case 'd':
+            gPhysicalDisplayId = atoll(optarg);
+            if (gPhysicalDisplayId == 0) {
+                fprintf(stderr, "Please specify a valid physical display id\n");
+                return 2;
+            } else if (SurfaceComposerClient::
+                    getPhysicalDisplayToken(gPhysicalDisplayId) == nullptr) {
+                fprintf(stderr, "Invalid physical display id: %"
+                        ANDROID_PHYSICAL_DISPLAY_ID_FORMAT "\n", gPhysicalDisplayId);
+                return 2;
+            }
+            break;
         default:
             if (ic != '?') {
                 fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/cmds/screenrecord/screenrecord.h b/cmds/screenrecord/screenrecord.h
index 9b058c2..cec7c13 100644
--- a/cmds/screenrecord/screenrecord.h
+++ b/cmds/screenrecord/screenrecord.h
@@ -18,6 +18,6 @@
 #define SCREENRECORD_SCREENRECORD_H
 
 #define kVersionMajor 1
-#define kVersionMinor 2
+#define kVersionMinor 3
 
 #endif /*SCREENRECORD_SCREENRECORD_H*/
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 02ade94..e8cfece 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -988,7 +988,7 @@
                 failed = false;
                 printf("getFrameAtTime(%s) => OK\n", filename);
 
-                VideoFrame *frame = (VideoFrame *)mem->pointer();
+                VideoFrame *frame = (VideoFrame *)mem->unsecurePointer();
 
                 CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
                             frame->getFlattenedData(),
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 22e2ef3..fe613a8 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -116,7 +116,7 @@
 
     sp<IMemory> mem = mBuffers.itemAt(index);
 
-    ssize_t n = read(mFd, mem->pointer(), mem->size());
+    ssize_t n = read(mFd, mem->unsecurePointer(), mem->size());
     if (n <= 0) {
         mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
     } else {
@@ -238,7 +238,7 @@
             copy = mem->size() - mCurrentBufferOffset;
         }
 
-        memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy);
+        memcpy((uint8_t *)mem->unsecurePointer() + mCurrentBufferOffset, data, copy);
         mCurrentBufferOffset += copy;
 
         if (mCurrentBufferOffset == mem->size()) {
diff --git a/drm/drmserver/Android.bp b/drm/drmserver/Android.bp
index c25a0a1..fd71837 100644
--- a/drm/drmserver/Android.bp
+++ b/drm/drmserver/Android.bp
@@ -25,6 +25,7 @@
 
     shared_libs: [
         "libmedia",
+        "libmediametrics",
         "libutils",
         "liblog",
         "libbinder",
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index afbcb39..e2ea83a 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -19,7 +19,10 @@
 #include "utils/Log.h"
 
 #include <utils/String8.h>
+
+#include <binder/IPCThreadState.h>
 #include <drm/DrmInfo.h>
+
 #include <drm/DrmInfoEvent.h>
 #include <drm/DrmRights.h>
 #include <drm/DrmConstraints.h>
@@ -28,6 +31,7 @@
 #include <drm/DrmInfoRequest.h>
 #include <drm/DrmSupportInfo.h>
 #include <drm/DrmConvertedStatus.h>
+#include <media/MediaAnalyticsItem.h>
 #include <IDrmEngine.h>
 
 #include "DrmManager.h"
@@ -50,6 +54,39 @@
 
 }
 
+void DrmManager::reportEngineMetrics(
+        const char func[], const String8& plugInId, const String8& mimeType) {
+    IDrmEngine& engine = mPlugInManager.getPlugIn(plugInId);
+
+    std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("drmmanager"));
+    item->setUid(IPCThreadState::self()->getCallingUid());
+    item->setCString("function_name", func);
+    item->setCString("plugin_id", plugInId.getPathLeaf().getBasePath().c_str());
+
+    std::unique_ptr<DrmSupportInfo> info(engine.getSupportInfo(0));
+    if (NULL != info) {
+        item->setCString("description", info->getDescription().c_str());
+    }
+
+    if (!mimeType.isEmpty()) {
+        item->setCString("mime_types", mimeType.c_str());
+    } else if (NULL != info) {
+        DrmSupportInfo::MimeTypeIterator mimeIter = info->getMimeTypeIterator();
+        String8 mimes;
+        while (mimeIter.hasNext()) {
+            mimes += mimeIter.next();
+            if (mimeIter.hasNext()) {
+                mimes += ",";
+            }
+        }
+        item->setCString("mime_types", mimes.c_str());
+    }
+
+    if (!item->selfrecord()) {
+        ALOGE("Failed to record metrics");
+    }
+}
+
 int DrmManager::addUniqueId(bool isNative) {
     Mutex::Autolock _l(mLock);
 
@@ -147,27 +184,36 @@
     for (size_t index = 0; index < plugInIdList.size(); index++) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInIdList.itemAt(index));
         rDrmEngine.terminate(uniqueId);
+        reportEngineMetrics(__func__, plugInIdList[index]);
     }
 }
 
 DrmConstraints* DrmManager::getConstraints(int uniqueId, const String8* path, const int action) {
     Mutex::Autolock _l(mLock);
+    DrmConstraints *constraints = NULL;
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getConstraints(uniqueId, path, action);
+        constraints = rDrmEngine.getConstraints(uniqueId, path, action);
     }
-    return NULL;
+    if (NULL != constraints) {
+        reportEngineMetrics(__func__, plugInId);
+    }
+    return constraints;
 }
 
 DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
     Mutex::Autolock _l(mLock);
+    DrmMetadata *meta = NULL;
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getMetadata(uniqueId, path);
+        meta = rDrmEngine.getMetadata(uniqueId, path);
     }
-    return NULL;
+    if (NULL != meta) {
+        reportEngineMetrics(__func__, plugInId);
+    }
+    return meta;
 }
 
 bool DrmManager::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
@@ -175,6 +221,10 @@
     const String8 plugInId = getSupportedPlugInId(mimeType);
     bool result = (EMPTY_STRING != plugInId) ? true : false;
 
+    if (result) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+
     if (0 < path.length()) {
         if (result) {
             IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
@@ -191,12 +241,17 @@
 
 DrmInfoStatus* DrmManager::processDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
     Mutex::Autolock _l(mLock);
-    const String8 plugInId = getSupportedPlugInId(drmInfo->getMimeType());
+    DrmInfoStatus *infoStatus = NULL;
+    const String8 mimeType = drmInfo->getMimeType();
+    const String8 plugInId = getSupportedPlugInId(mimeType);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.processDrmInfo(uniqueId, drmInfo);
+        infoStatus = rDrmEngine.processDrmInfo(uniqueId, drmInfo);
     }
-    return NULL;
+    if (NULL != infoStatus) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return infoStatus;
 }
 
 bool DrmManager::canHandle(int uniqueId, const String8& path) {
@@ -208,6 +263,7 @@
         result = rDrmEngine.canHandle(uniqueId, path);
 
         if (result) {
+            reportEngineMetrics(__func__, plugInPathList[i]);
             break;
         }
     }
@@ -216,54 +272,75 @@
 
 DrmInfo* DrmManager::acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
     Mutex::Autolock _l(mLock);
-    const String8 plugInId = getSupportedPlugInId(drmInfoRequest->getMimeType());
+    DrmInfo *info = NULL;
+    const String8 mimeType = drmInfoRequest->getMimeType();
+    const String8 plugInId = getSupportedPlugInId(mimeType);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
+        info = rDrmEngine.acquireDrmInfo(uniqueId, drmInfoRequest);
     }
-    return NULL;
+    if (NULL != info) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return info;
 }
 
 status_t DrmManager::saveRights(int uniqueId, const DrmRights& drmRights,
             const String8& rightsPath, const String8& contentPath) {
     Mutex::Autolock _l(mLock);
-    const String8 plugInId = getSupportedPlugInId(drmRights.getMimeType());
+    const String8 mimeType = drmRights.getMimeType();
+    const String8 plugInId = getSupportedPlugInId(mimeType);
     status_t result = DRM_ERROR_UNKNOWN;
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
         result = rDrmEngine.saveRights(uniqueId, drmRights, rightsPath, contentPath);
     }
+    if (DRM_NO_ERROR == result) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
     return result;
 }
 
 String8 DrmManager::getOriginalMimeType(int uniqueId, const String8& path, int fd) {
     Mutex::Autolock _l(mLock);
+    String8 mimeType(EMPTY_STRING);
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
+        mimeType = rDrmEngine.getOriginalMimeType(uniqueId, path, fd);
     }
-    return EMPTY_STRING;
+    if (!mimeType.isEmpty()) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return mimeType;
 }
 
 int DrmManager::getDrmObjectType(int uniqueId, const String8& path, const String8& mimeType) {
     Mutex::Autolock _l(mLock);
+    int type = DrmObjectType::UNKNOWN;
     const String8 plugInId = getSupportedPlugInId(uniqueId, path, mimeType);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
+        type = rDrmEngine.getDrmObjectType(uniqueId, path, mimeType);
     }
-    return DrmObjectType::UNKNOWN;
+    if (DrmObjectType::UNKNOWN != type) {
+        reportEngineMetrics(__func__, plugInId, mimeType);
+    }
+    return type;
 }
 
 int DrmManager::checkRightsStatus(int uniqueId, const String8& path, int action) {
     Mutex::Autolock _l(mLock);
+    int rightsStatus = RightsStatus::RIGHTS_INVALID;
     const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, path);
     if (EMPTY_STRING != plugInId) {
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
-        return rDrmEngine.checkRightsStatus(uniqueId, path, action);
+        rightsStatus = rDrmEngine.checkRightsStatus(uniqueId, path, action);
     }
-    return RightsStatus::RIGHTS_INVALID;
+    if (RightsStatus::RIGHTS_INVALID != rightsStatus) {
+        reportEngineMetrics(__func__, plugInId);
+    }
+    return rightsStatus;
 }
 
 status_t DrmManager::consumeRights(
@@ -307,6 +384,9 @@
         IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
         result = rDrmEngine.removeRights(uniqueId, path);
     }
+    if (DRM_NO_ERROR == result) {
+        reportEngineMetrics(__func__, plugInId);
+    }
     return result;
 }
 
@@ -319,6 +399,7 @@
         if (DRM_NO_ERROR != result) {
             break;
         }
+        reportEngineMetrics(__func__, plugInIdList[index]);
     }
     return result;
 }
@@ -335,6 +416,7 @@
             ++mConvertId;
             convertId = mConvertId;
             mConvertSessionMap.add(convertId, &rDrmEngine);
+            reportEngineMetrics(__func__, plugInId, mimeType);
         }
     }
     return convertId;
@@ -415,6 +497,7 @@
             if (DRM_NO_ERROR == result) {
                 ++mDecryptSessionId;
                 mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                reportEngineMetrics(__func__, plugInId, String8(mime));
                 break;
             }
         }
@@ -443,6 +526,7 @@
             if (DRM_NO_ERROR == result) {
                 ++mDecryptSessionId;
                 mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                reportEngineMetrics(__func__, plugInId, String8(mime));
                 break;
             }
         }
@@ -472,6 +556,7 @@
             if (DRM_NO_ERROR == result) {
                 ++mDecryptSessionId;
                 mDecryptSessionMap.add(mDecryptSessionId, &rDrmEngine);
+                reportEngineMetrics(__func__, plugInId, mimeType);
                 break;
             }
         }
diff --git a/drm/drmserver/DrmManager.h b/drm/drmserver/DrmManager.h
index 26222bc..75fc1a8 100644
--- a/drm/drmserver/DrmManager.h
+++ b/drm/drmserver/DrmManager.h
@@ -143,6 +143,9 @@
 
     bool canHandle(int uniqueId, const String8& path);
 
+    void reportEngineMetrics(const char func[],
+            const String8& plugInId, const String8& mimeType = String8(""));
+
 private:
     enum {
         kMaxNumUniqueIds = 0x1000,
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 84f2f6d..34a2f69 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -17,13 +17,10 @@
     srcs: [
         "DrmPluginPath.cpp",
         "DrmSessionManager.cpp",
-        "ICrypto.cpp",
-        "IDrm.cpp",
-        "IDrmClient.cpp",
-        "IMediaDrmService.cpp",
         "SharedLibrary.cpp",
         "DrmHal.cpp",
         "CryptoHal.cpp",
+        "DrmUtils.cpp",
     ],
 
     local_include_dirs: [
@@ -41,11 +38,13 @@
 
     shared_libs: [
         "libbinder",
+        "libbinder_ndk",
         "libcutils",
         "libdl",
         "liblog",
+        "libmedia",
         "libmediadrmmetrics_lite",
-        "libmediametrics",
+        "libmediametrics#1",
         "libmediautils",
         "libstagefright_foundation",
         "libutils",
@@ -56,6 +55,16 @@
         "libhidlbase",
     ],
 
+    static_libs: [
+        "resourcemanager_aidl_interface-ndk_platform",
+    ],
+
+    export_shared_lib_headers: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index d62ccd6..55b9bb8 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -19,9 +19,9 @@
 #include <utils/Log.h>
 
 #include <android/hardware/drm/1.0/types.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
-
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <binder/IMemory.h>
+#include <hidl/ServiceManagement.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -45,9 +45,9 @@
 using ::android::hardware::hidl_memory;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::HidlMemory;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hidl::manager::V1_0::IServiceManager;
 using ::android::sp;
 
 typedef drm::V1_2::Status Status_V1_2;
@@ -119,7 +119,6 @@
 CryptoHal::CryptoHal()
     : mFactories(makeCryptoFactories()),
       mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
-      mNextBufferId(0),
       mHeapSeqNum(0) {
 }
 
@@ -129,9 +128,9 @@
 Vector<sp<ICryptoFactory>> CryptoHal::makeCryptoFactories() {
     Vector<sp<ICryptoFactory>> factories;
 
-    auto manager = ::IServiceManager::getService();
+    auto manager = hardware::defaultServiceManager1_2();
     if (manager != NULL) {
-        manager->listByInterface(drm::V1_0::ICryptoFactory::descriptor,
+        manager->listManifestByInterface(drm::V1_0::ICryptoFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_0::ICryptoFactory::getService(instance);
@@ -142,7 +141,7 @@
                     }
                 }
             );
-        manager->listByInterface(drm::V1_1::ICryptoFactory::descriptor,
+        manager->listManifestByInterface(drm::V1_1::ICryptoFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_1::ICryptoFactory::getService(instance);
@@ -257,21 +256,18 @@
  * size.  Once the heap base is established, shared memory buffers
  * are sent by providing an offset into the heap and a buffer size.
  */
-int32_t CryptoHal::setHeapBase(const sp<IMemoryHeap>& heap) {
-    using ::android::hardware::fromHeap;
-    using ::android::hardware::HidlMemory;
-
-    if (heap == NULL) {
-        ALOGE("setHeapBase(): heap is NULL");
+int32_t CryptoHal::setHeapBase(const sp<HidlMemory>& heap) {
+    if (heap == NULL || mHeapSeqNum < 0) {
+        ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
         return -1;
     }
 
     Mutex::Autolock autoLock(mLock);
 
     int32_t seqNum = mHeapSeqNum++;
-    sp<HidlMemory> hidlMemory = fromHeap(heap);
-    mHeapBases.add(seqNum, HeapBase(mNextBufferId, heap->getSize()));
-    Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
+    uint32_t bufferId = static_cast<uint32_t>(seqNum);
+    mHeapSizes.add(seqNum, heap->size());
+    Return<void> hResult = mPlugin->setSharedBufferBase(*heap, bufferId);
     ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
     return seqNum;
 }
@@ -286,60 +282,40 @@
      * TODO: Add a releaseSharedBuffer method in a future DRM HAL
      * API version to make this explicit.
      */
-    ssize_t index = mHeapBases.indexOfKey(seqNum);
+    ssize_t index = mHeapSizes.indexOfKey(seqNum);
     if (index >= 0) {
         if (mPlugin != NULL) {
-            uint32_t bufferId = mHeapBases[index].getBufferId();
+            uint32_t bufferId = static_cast<uint32_t>(seqNum);
             Return<void> hResult = mPlugin->setSharedBufferBase(hidl_memory(), bufferId);
             ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
         }
-        mHeapBases.removeItem(seqNum);
+        mHeapSizes.removeItem(seqNum);
     }
 }
 
-status_t CryptoHal::toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer) {
-    ssize_t offset;
-    size_t size;
-
-    if (memory == NULL || buffer == NULL) {
-        return UNEXPECTED_NULL;
-    }
-
-    sp<IMemoryHeap> heap = memory->getMemory(&offset, &size);
-    if (heap == NULL) {
-        return UNEXPECTED_NULL;
-    }
-
+status_t CryptoHal::checkSharedBuffer(const ::SharedBuffer &buffer) {
+    int32_t seqNum = static_cast<int32_t>(buffer.bufferId);
     // memory must be in one of the heaps that have been set
-    if (mHeapBases.indexOfKey(seqNum) < 0) {
+    if (mHeapSizes.indexOfKey(seqNum) < 0) {
         return UNKNOWN_ERROR;
     }
 
-    // heap must be the same size as the one that was set in setHeapBase
-    if (mHeapBases.valueFor(seqNum).getSize() != heap->getSize()) {
-        android_errorWriteLog(0x534e4554, "76221123");
-        return UNKNOWN_ERROR;
-     }
-
     // memory must be within the address space of the heap
-    if (memory->pointer() != static_cast<uint8_t *>(heap->getBase()) + memory->offset()  ||
-            heap->getSize() < memory->offset() + memory->size() ||
-            SIZE_MAX - memory->offset() < memory->size()) {
+    size_t heapSize = mHeapSizes.valueFor(seqNum);
+    if (heapSize < buffer.offset + buffer.size ||
+            SIZE_MAX - buffer.offset < buffer.size) {
         android_errorWriteLog(0x534e4554, "76221123");
         return UNKNOWN_ERROR;
     }
 
-    buffer->bufferId = mHeapBases.valueFor(seqNum).getBufferId();
-    buffer->offset = offset >= 0 ? offset : 0;
-    buffer->size = size;
     return OK;
 }
 
 ssize_t CryptoHal::decrypt(const uint8_t keyId[16], const uint8_t iv[16],
         CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-        const ICrypto::SourceBuffer &source, size_t offset,
+        const ::SharedBuffer &hSource, size_t offset,
         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
-        const ICrypto::DestinationBuffer &destination, AString *errorDetailMsg) {
+        const ::DestinationBuffer &hDestination, AString *errorDetailMsg) {
     Mutex::Autolock autoLock(mLock);
 
     if (mInitCheck != OK) {
@@ -377,28 +353,21 @@
     }
     auto hSubSamples = hidl_vec<SubSample>(stdSubSamples);
 
-    int32_t heapSeqNum = source.mHeapSeqNum;
     bool secure;
-    ::DestinationBuffer hDestination;
-    if (destination.mType == kDestinationTypeSharedMemory) {
-        hDestination.type = BufferType::SHARED_MEMORY;
-        status_t status = toSharedBuffer(destination.mSharedMemory, heapSeqNum,
-                &hDestination.nonsecureMemory);
+    if (hDestination.type == BufferType::SHARED_MEMORY) {
+        status_t status = checkSharedBuffer(hDestination.nonsecureMemory);
         if (status != OK) {
             return status;
         }
         secure = false;
-    } else if (destination.mType == kDestinationTypeNativeHandle) {
-        hDestination.type = BufferType::NATIVE_HANDLE;
-        hDestination.secureMemory = hidl_handle(destination.mHandle);
+    } else if (hDestination.type == BufferType::NATIVE_HANDLE) {
         secure = true;
     } else {
         android_errorWriteLog(0x534e4554, "70526702");
         return UNKNOWN_ERROR;
     }
 
-    ::SharedBuffer hSource;
-    status_t status = toSharedBuffer(source.mSharedMemory, heapSeqNum, &hSource);
+    status_t status = checkSharedBuffer(hSource);
     if (status != OK) {
         return status;
     }
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index e79fd4b..f3028d8 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -20,14 +20,14 @@
 
 #include <utils/Log.h>
 
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
+#include <android/binder_manager.h>
 
+#include <aidl/android/media/BnResourceManagerClient.h>
 #include <android/hardware/drm/1.2/types.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
 #include <hidl/ServiceManagement.h>
-
 #include <media/EventMetric.h>
+#include <media/MediaMetrics.h>
 #include <media/PluginMetricsReporting.h>
 #include <media/drm/DrmAPI.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -39,6 +39,8 @@
 #include <mediadrm/DrmSessionClientInterface.h>
 #include <mediadrm/DrmSessionManager.h>
 
+#include <vector>
+
 using drm::V1_0::KeyedVector;
 using drm::V1_0::KeyRequestType;
 using drm::V1_0::KeyType;
@@ -57,7 +59,6 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hidl::manager::V1_0::IServiceManager;
 using ::android::os::PersistableBundle;
 using ::android::sp;
 
@@ -97,17 +98,6 @@
 
 #define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
 
-static inline int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
-static bool checkPermission(const char* permissionString) {
-    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
-    bool ok = checkCallingPermission(String16(permissionString));
-    if (!ok) ALOGE("Request requires %s", permissionString);
-    return ok;
-}
-
 static const Vector<uint8_t> toVector(const hidl_vec<uint8_t> &vec) {
     Vector<uint8_t> vector;
     vector.appendArray(vec.data(), vec.size());
@@ -295,28 +285,19 @@
     }
 }
 
-
 Mutex DrmHal::mLock;
 
-struct DrmSessionClient : public DrmSessionClientInterface {
-    explicit DrmSessionClient(DrmHal* drm) : mDrm(drm) {}
+struct DrmHal::DrmSessionClient : public aidl::android::media::BnResourceManagerClient {
+    explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
+      : mSessionId(sessionId),
+        mDrm(drm) {}
 
-    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
-        sp<DrmHal> drm = mDrm.promote();
-        if (drm == NULL) {
-            return true;
-        }
-        status_t err = drm->closeSession(sessionId);
-        if (err != OK) {
-            return false;
-        }
-        drm->sendEvent(EventType::SESSION_RECLAIMED,
-                toHidlVec(sessionId), hidl_vec<uint8_t>());
-        return true;
-    }
+    ::ndk::ScopedAStatus reclaimResource(bool* _aidl_return) override;
+    ::ndk::ScopedAStatus getName(::std::string* _aidl_return) override;
 
-protected:
-    virtual ~DrmSessionClient() {}
+    const Vector<uint8_t> mSessionId;
+
+    virtual ~DrmSessionClient();
 
 private:
     wp<DrmHal> mDrm;
@@ -324,9 +305,48 @@
     DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
 };
 
+::ndk::ScopedAStatus DrmHal::DrmSessionClient::reclaimResource(bool* _aidl_return) {
+    auto sessionId = mSessionId;
+    sp<DrmHal> drm = mDrm.promote();
+    if (drm == NULL) {
+        *_aidl_return = true;
+        return ::ndk::ScopedAStatus::ok();
+    }
+    status_t err = drm->closeSession(sessionId);
+    if (err != OK) {
+        *_aidl_return = false;
+        return ::ndk::ScopedAStatus::ok();
+    }
+    drm->sendEvent(EventType::SESSION_RECLAIMED,
+            toHidlVec(sessionId), hidl_vec<uint8_t>());
+    *_aidl_return = true;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus DrmHal::DrmSessionClient::getName(::std::string* _aidl_return) {
+    String8 name;
+    sp<DrmHal> drm = mDrm.promote();
+    if (drm == NULL) {
+        name.append("<deleted>");
+    } else if (drm->getPropertyStringInternal(String8("vendor"), name) != OK
+        || name.isEmpty()) {
+      name.append("<Get vendor failed or is empty>");
+    }
+    name.append("[");
+    for (size_t i = 0; i < mSessionId.size(); ++i) {
+        name.appendFormat("%02x", mSessionId[i]);
+    }
+    name.append("]");
+    *_aidl_return = name;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+DrmHal::DrmSessionClient::~DrmSessionClient() {
+    DrmSessionManager::Instance()->removeSession(mSessionId);
+}
+
 DrmHal::DrmHal()
-   : mDrmSessionClient(new DrmSessionClient(this)),
-     mFactories(makeDrmFactories()),
+   : mFactories(makeDrmFactories()),
      mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
 }
 
@@ -335,14 +355,13 @@
     auto openSessions = mOpenSessions;
     for (size_t i = 0; i < openSessions.size(); i++) {
         mLock.unlock();
-        closeSession(openSessions[i]);
+        closeSession(openSessions[i]->mSessionId);
         mLock.lock();
     }
     mOpenSessions.clear();
 }
 
 DrmHal::~DrmHal() {
-    DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
 }
 
 void DrmHal::cleanup() {
@@ -394,7 +413,7 @@
                     }
                 }
             );
-        manager->listByInterface(drm::V1_2::IDrmFactory::descriptor,
+        manager->listManifestByInterface(drm::V1_2::IDrmFactory::descriptor,
                 [&factories](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         auto factory = drm::V1_2::IDrmFactory::getService(instance);
@@ -423,6 +442,7 @@
         const uint8_t uuid[16], const String8& appPackageName) {
     mAppPackageName = appPackageName;
     mMetrics.SetAppPackageName(appPackageName);
+    mMetrics.SetAppUid(AIBinder_getCallingUid());
 
     sp<IDrmPlugin> plugin;
     Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
@@ -449,12 +469,6 @@
 status_t DrmHal::setListener(const sp<IDrmClient>& listener)
 {
     Mutex::Autolock lock(mEventLock);
-    if (mListener != NULL){
-        IInterface::asBinder(mListener)->unlinkToDeath(this);
-    }
-    if (listener != NULL) {
-        IInterface::asBinder(listener)->linkToDeath(this);
-    }
     mListener = listener;
     return NO_ERROR;
 }
@@ -468,10 +482,6 @@
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-        writeByteArray(obj, data);
-
         Mutex::Autolock lock(mNotifyLock);
         DrmPlugin::EventType eventType;
         switch(hEventType) {
@@ -493,7 +503,7 @@
         default:
             return Void();
         }
-        listener->notify(eventType, 0, &obj);
+        listener->sendEvent(eventType, sessionId, data);
     }
     return Void();
 }
@@ -506,12 +516,8 @@
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-        obj.writeInt64(expiryTimeInMS);
-
         Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
+        listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
     }
     return Void();
 }
@@ -528,21 +534,17 @@
 }
 
 Return<void> DrmHal::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
-        const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
+        const hidl_vec<KeyStatus>& hKeyStatusList, bool hasNewUsableKey) {
 
     mEventLock.lock();
     sp<IDrmClient> listener = mListener;
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-
-        size_t nKeys = keyStatusList.size();
-        obj.writeInt32(nKeys);
+        std::vector<DrmKeyStatus> keyStatusList;
+        size_t nKeys = hKeyStatusList.size();
         for (size_t i = 0; i < nKeys; ++i) {
-            const KeyStatus &keyStatus = keyStatusList[i];
-            writeByteArray(obj, keyStatus.keyId);
+            const KeyStatus &keyStatus = hKeyStatusList[i];
             uint32_t type;
             switch(keyStatus.type) {
             case KeyStatusType::USABLE:
@@ -565,19 +567,18 @@
                 type = DrmPlugin::kKeyStatusType_InternalError;
                 break;
             }
-            obj.writeInt32(type);
+            keyStatusList.push_back({type, keyStatus.keyId});
             mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
         }
-        obj.writeInt32(hasNewUsableKey);
 
         Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
+        listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
     } else {
         // There's no listener. But we still want to count the key change
         // events.
-        size_t nKeys = keyStatusList.size();
+        size_t nKeys = hKeyStatusList.size();
         for (size_t i = 0; i < nKeys; i++) {
-            mMetrics.mKeyStatusChangeCounter.Increment(keyStatusList[i].type);
+            mMetrics.mKeyStatusChangeCounter.Increment(hKeyStatusList[i].type);
         }
     }
 
@@ -592,10 +593,8 @@
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
         Mutex::Autolock lock(mNotifyLock);
-        listener->notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &obj);
+        listener->sendSessionLostState(sessionId);
     }
     return Void();
 }
@@ -740,7 +739,7 @@
             // reclaimSession may call back to closeSession, since mLock is
             // shared between Drm instances, we should unlock here to avoid
             // deadlock.
-            retry = DrmSessionManager::Instance()->reclaimSession(getCallingPid());
+            retry = DrmSessionManager::Instance()->reclaimSession(AIBinder_getCallingPid());
             mLock.lock();
         } else {
             retry = false;
@@ -748,9 +747,10 @@
     } while (retry);
 
     if (err == OK) {
-        DrmSessionManager::Instance()->addSession(getCallingPid(),
-                mDrmSessionClient, sessionId);
-        mOpenSessions.push(sessionId);
+        std::shared_ptr<DrmSessionClient> client(new DrmSessionClient(this, sessionId));
+        DrmSessionManager::Instance()->addSession(AIBinder_getCallingPid(),
+                std::static_pointer_cast<IResourceManagerClient>(client), sessionId);
+        mOpenSessions.push_back(client);
         mMetrics.SetSessionStart(sessionId);
     }
 
@@ -766,9 +766,9 @@
     if (status.isOk()) {
         if (status == Status::OK) {
             DrmSessionManager::Instance()->removeSession(sessionId);
-            for (size_t i = 0; i < mOpenSessions.size(); i++) {
-                if (mOpenSessions[i] == sessionId) {
-                    mOpenSessions.removeAt(i);
+            for (auto i = mOpenSessions.begin(); i != mOpenSessions.end(); i++) {
+                if (isEqualSessionId((*i)->mSessionId, sessionId)) {
+                    mOpenSessions.erase(i);
                     break;
                 }
             }
@@ -1531,10 +1531,6 @@
     Mutex::Autolock autoLock(mLock);
     INIT_CHECK();
 
-    if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) {
-        return -EPERM;
-    }
-
     DrmSessionManager::Instance()->useSession(sessionId);
 
     status_t err = UNKNOWN_ERROR;
@@ -1552,39 +1548,23 @@
     return hResult.isOk() ? err : DEAD_OBJECT;
 }
 
-void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
-{
-    cleanup();
-}
-
-void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
-{
-    if (vec.size()) {
-        obj.writeInt32(vec.size());
-        obj.write(vec.data(), vec.size());
-    } else {
-        obj.writeInt32(0);
-    }
-}
-
 void DrmHal::reportFrameworkMetrics() const
 {
-    std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("mediadrm"));
-    item->generateSessionID();
-    item->setPkgName(mMetrics.GetAppPackageName().c_str());
+    mediametrics_handle_t item(mediametrics_create("mediadrm"));
+    mediametrics_setUid(item, mMetrics.GetAppUid());
     String8 vendor;
     String8 description;
     status_t result = getPropertyStringInternal(String8("vendor"), vendor);
     if (result != OK) {
         ALOGE("Failed to get vendor from drm plugin: %d", result);
     } else {
-        item->setCString("vendor", vendor.c_str());
+        mediametrics_setCString(item, "vendor", vendor.c_str());
     }
     result = getPropertyStringInternal(String8("description"), description);
     if (result != OK) {
         ALOGE("Failed to get description from drm plugin: %d", result);
     } else {
-        item->setCString("description", description.c_str());
+        mediametrics_setCString(item, "description", description.c_str());
     }
 
     std::string serializedMetrics;
@@ -1595,11 +1575,12 @@
     std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
                                                         serializedMetrics.size());
     if (!b64EncodedMetrics.empty()) {
-        item->setCString("serialized_metrics", b64EncodedMetrics.c_str());
+        mediametrics_setCString(item, "serialized_metrics", b64EncodedMetrics.c_str());
     }
-    if (!item->selfrecord()) {
+    if (!mediametrics_selfRecord(item)) {
         ALOGE("Failed to self record framework metrics");
     }
+    mediametrics_delete(item);
 }
 
 void DrmHal::reportPluginMetrics() const
@@ -1613,7 +1594,7 @@
         std::string metricsString = toBase64StringNoPad(metricsVector.array(),
                                                         metricsVector.size());
         status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
-                                                       description, mAppPackageName);
+                                                       description, mMetrics.GetAppUid());
         if (res != OK) {
             ALOGE("Metrics were retrieved but could not be reported: %d", res);
         }
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 375644c..7a4e1ae 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -18,17 +18,32 @@
 #define LOG_TAG "DrmSessionManager"
 #include <utils/Log.h>
 
-#include <binder/IPCThreadState.h>
-#include <binder/IProcessInfoService.h>
-#include <binder/IServiceManager.h>
-#include <media/stagefright/ProcessInfo.h>
-#include <mediadrm/DrmSessionClientInterface.h>
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <cutils/properties.h>
+#include <mediadrm/DrmUtils.h>
 #include <mediadrm/DrmSessionManager.h>
 #include <unistd.h>
 #include <utils/String8.h>
 
+#include <vector>
+
 namespace android {
 
+using aidl::android::media::MediaResourceParcel;
+
+namespace {
+void ResourceManagerServiceDied(void* cookie) {
+    auto thiz = static_cast<DrmSessionManager*>(cookie);
+    thiz->binderDied();
+}
+}
+
+using ::ndk::ScopedAStatus;
+
 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
     String8 sessionIdStr;
     for (size_t i = 0; i < sessionId.size(); ++i) {
@@ -37,6 +52,30 @@
     return sessionIdStr;
 }
 
+template <typename Byte = uint8_t>
+static std::vector<Byte> toStdVec(const Vector<uint8_t> &vector) {
+    auto v = reinterpret_cast<const Byte *>(vector.array());
+    std::vector<Byte> vec(v, v + vector.size());
+    return vec;
+}
+
+static std::vector<MediaResourceParcel> toResourceVec(
+        const Vector<uint8_t> &sessionId, int64_t value) {
+    using Type = aidl::android::media::MediaResourceType;
+    using SubType = aidl::android::media::MediaResourceSubType;
+    std::vector<MediaResourceParcel> resources;
+    MediaResourceParcel resource{
+            Type::kDrmSession, SubType::kUnspecifiedSubType,
+            toStdVec<int8_t>(sessionId), value};
+    resources.push_back(resource);
+    return resources;
+}
+
+static std::shared_ptr<IResourceManagerService> getResourceManagerService() {
+    ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_manager"));
+    return IResourceManagerService::fromBinder(binder);
+}
+
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2) {
     if (sessionId1.size() != sessionId2.size()) {
         return false;
@@ -50,190 +89,118 @@
 }
 
 sp<DrmSessionManager> DrmSessionManager::Instance() {
-    static sp<DrmSessionManager> drmSessionManager = new DrmSessionManager();
+    auto drmSessionManager = new DrmSessionManager();
+    drmSessionManager->init();
     return drmSessionManager;
 }
 
 DrmSessionManager::DrmSessionManager()
-    : mProcessInfo(new ProcessInfo()),
-      mTime(0) {}
+    : DrmSessionManager(getResourceManagerService()) {
+}
 
-DrmSessionManager::DrmSessionManager(sp<ProcessInfoInterface> processInfo)
-    : mProcessInfo(processInfo),
-      mTime(0) {}
+DrmSessionManager::DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service)
+    : mService(service),
+      mInitialized(false),
+      mDeathRecipient(AIBinder_DeathRecipient_new(ResourceManagerServiceDied)) {
+    if (mService == NULL) {
+        ALOGE("Failed to init ResourceManagerService");
+    }
+}
 
-DrmSessionManager::~DrmSessionManager() {}
+DrmSessionManager::~DrmSessionManager() {
+    if (mService != NULL) {
+        AIBinder_unlinkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+    }
+}
 
-void DrmSessionManager::addSession(
-        int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t> &sessionId) {
-    ALOGV("addSession(pid %d, drm %p, sessionId %s)", pid, drm.get(),
+void DrmSessionManager::init() {
+    Mutex::Autolock lock(mLock);
+    if (mInitialized) {
+        return;
+    }
+    mInitialized = true;
+    if (mService != NULL) {
+        AIBinder_linkToDeath(mService->asBinder().get(), mDeathRecipient.get(), this);
+    }
+}
+
+void DrmSessionManager::addSession(int pid,
+        const std::shared_ptr<IResourceManagerClient>& drm, const Vector<uint8_t> &sessionId) {
+    uid_t uid = AIBinder_getCallingUid();
+    ALOGV("addSession(pid %d, uid %d, drm %p, sessionId %s)", pid, uid, drm.get(),
             GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    SessionInfo info;
-    info.drm = drm;
-    info.sessionId = sessionId;
-    info.timeStamp = getTime_l();
-    ssize_t index = mSessionMap.indexOfKey(pid);
-    if (index < 0) {
-        // new pid
-        SessionInfos infosForPid;
-        infosForPid.push_back(info);
-        mSessionMap.add(pid, infosForPid);
-    } else {
-        mSessionMap.editValueAt(index).push_back(info);
+    if (mService == NULL) {
+        return;
     }
+
+    static int64_t clientId = 0;
+    mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
+    mService->addResource(pid, uid, clientId++, drm, toResourceVec(sessionId, INT64_MAX));
 }
 
 void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
     ALOGV("useSession(%s)", GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
-            SessionInfo& info = infos.editItemAt(j);
-            if (isEqualSessionId(sessionId, info.sessionId)) {
-                info.timeStamp = getTime_l();
-                return;
-            }
-        }
+    auto it = mSessionMap.find(toStdVec(sessionId));
+    if (mService == NULL || it == mSessionMap.end()) {
+        return;
     }
+
+    auto info = it->second;
+    mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId, -1));
 }
 
 void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
     ALOGV("removeSession(%s)", GetSessionIdString(sessionId).string());
 
     Mutex::Autolock lock(mLock);
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size(); ++j) {
-            if (isEqualSessionId(sessionId, infos[j].sessionId)) {
-                infos.removeAt(j);
-                return;
-            }
-        }
+    auto it = mSessionMap.find(toStdVec(sessionId));
+    if (mService == NULL || it == mSessionMap.end()) {
+        return;
     }
-}
 
-void DrmSessionManager::removeDrm(const sp<DrmSessionClientInterface>& drm) {
-    ALOGV("removeDrm(%p)", drm.get());
-
-    Mutex::Autolock lock(mLock);
-    bool found = false;
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        SessionInfos& infos = mSessionMap.editValueAt(i);
-        for (size_t j = 0; j < infos.size();) {
-            if (infos[j].drm == drm) {
-                ALOGV("removed session (%s)", GetSessionIdString(infos[j].sessionId).string());
-                j = infos.removeAt(j);
-                found = true;
-            } else {
-                ++j;
-            }
-        }
-        if (found) {
-            break;
-        }
-    }
+    auto info = it->second;
+    mService->removeResource(info.pid, info.clientId, toResourceVec(sessionId, INT64_MAX));
+    mSessionMap.erase(it);
 }
 
 bool DrmSessionManager::reclaimSession(int callingPid) {
     ALOGV("reclaimSession(%d)", callingPid);
 
-    sp<DrmSessionClientInterface> drm;
-    Vector<uint8_t> sessionId;
-    int lowestPriorityPid;
-    int lowestPriority;
-    {
-        Mutex::Autolock lock(mLock);
-        int callingPriority;
-        if (!mProcessInfo->getPriority(callingPid, &callingPriority)) {
-            return false;
-        }
-        if (!getLowestPriority_l(&lowestPriorityPid, &lowestPriority)) {
-            return false;
-        }
-        if (lowestPriority <= callingPriority) {
-            return false;
-        }
+    // unlock early because reclaimResource might callback into removeSession
+    mLock.lock();
+    std::shared_ptr<IResourceManagerService> service(mService);
+    mLock.unlock();
 
-        if (!getLeastUsedSession_l(lowestPriorityPid, &drm, &sessionId)) {
-            return false;
-        }
-    }
-
-    if (drm == NULL) {
+    if (service == NULL) {
         return false;
     }
 
-    ALOGV("reclaim session(%s) opened by pid %d",
-            GetSessionIdString(sessionId).string(), lowestPriorityPid);
-
-    return drm->reclaimSession(sessionId);
+    // cannot update mSessionMap because we do not know which sessionId is reclaimed;
+    // we rely on IResourceManagerClient to removeSession in reclaimResource
+    Vector<uint8_t> dummy;
+    bool success;
+    ScopedAStatus status = service->reclaimResource(callingPid, toResourceVec(dummy, INT64_MAX), &success);
+    return status.isOk() && success;
 }
 
-int64_t DrmSessionManager::getTime_l() {
-    return mTime++;
+size_t DrmSessionManager::getSessionCount() const {
+    Mutex::Autolock lock(mLock);
+    return mSessionMap.size();
 }
 
-bool DrmSessionManager::getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority) {
-    int pid = -1;
-    int priority = -1;
-    for (size_t i = 0; i < mSessionMap.size(); ++i) {
-        if (mSessionMap.valueAt(i).size() == 0) {
-            // no opened session by this process.
-            continue;
-        }
-        int tempPid = mSessionMap.keyAt(i);
-        int tempPriority;
-        if (!mProcessInfo->getPriority(tempPid, &tempPriority)) {
-            // shouldn't happen.
-            return false;
-        }
-        if (pid == -1) {
-            pid = tempPid;
-            priority = tempPriority;
-        } else {
-            if (tempPriority > priority) {
-                pid = tempPid;
-                priority = tempPriority;
-            }
-        }
-    }
-    if (pid != -1) {
-        *lowestPriorityPid = pid;
-        *lowestPriority = priority;
-    }
-    return (pid != -1);
+bool DrmSessionManager::containsSession(const Vector<uint8_t>& sessionId) const {
+    Mutex::Autolock lock(mLock);
+    return mSessionMap.count(toStdVec(sessionId));
 }
 
-bool DrmSessionManager::getLeastUsedSession_l(
-        int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId) {
-    ssize_t index = mSessionMap.indexOfKey(pid);
-    if (index < 0) {
-        return false;
-    }
-
-    int leastUsedIndex = -1;
-    int64_t minTs = LLONG_MAX;
-    const SessionInfos& infos = mSessionMap.valueAt(index);
-    for (size_t j = 0; j < infos.size(); ++j) {
-        if (leastUsedIndex == -1) {
-            leastUsedIndex = j;
-            minTs = infos[j].timeStamp;
-        } else {
-            if (infos[j].timeStamp < minTs) {
-                leastUsedIndex = j;
-                minTs = infos[j].timeStamp;
-            }
-        }
-    }
-    if (leastUsedIndex != -1) {
-        *drm = infos[leastUsedIndex].drm;
-        *sessionId = infos[leastUsedIndex].sessionId;
-    }
-    return (leastUsedIndex != -1);
+void DrmSessionManager::binderDied() {
+    ALOGW("ResourceManagerService died.");
+    Mutex::Autolock lock(mLock);
+    mService.reset();
 }
 
 }  // namespace android
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
new file mode 100644
index 0000000..a126a1d
--- /dev/null
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmUtils"
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.2/ICryptoFactory.h>
+#include <android/hardware/drm/1.2/IDrmFactory.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/HidlSupport.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+#include <cutils/properties.h>
+
+#include <mediadrm/CryptoHal.h>
+#include <mediadrm/DrmHal.h>
+#include <mediadrm/DrmUtils.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
+
+using HServiceManager = ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using namespace ::android::hardware::drm;
+
+namespace android {
+namespace DrmUtils {
+
+namespace {
+
+template<typename Hal>
+Hal *MakeObject(status_t *pstatus) {
+    status_t err = OK;
+    status_t &status = pstatus ? *pstatus : err;
+    auto obj = new Hal();
+    status = obj->initCheck();
+    if (status != OK && status != NO_INIT) {
+        return NULL;
+    }
+    return obj;
+}
+
+template <typename Hal, typename V>
+void MakeHidlFactories(const uint8_t uuid[16], V &factories) {
+    sp<HServiceManager> serviceManager = HServiceManager::getService();
+    if (serviceManager == nullptr) {
+        ALOGE("Failed to get service manager");
+        exit(-1);
+    }
+
+    serviceManager->listByInterface(Hal::descriptor, [&](const hidl_vec<hidl_string> &registered) {
+        for (const auto &instance : registered) {
+            auto factory = Hal::getService(instance);
+            if (factory != nullptr) {
+                ALOGI("found %s %s", Hal::descriptor, instance.c_str());
+                if (factory->isCryptoSchemeSupported(uuid)) {
+                    factories.push_back(factory);
+                }
+            }
+        }
+    });
+}
+
+hidl_vec<uint8_t> toHidlVec(const void *ptr, size_t size) {
+    hidl_vec<uint8_t> vec(size);
+    if (ptr != nullptr) {
+        memcpy(vec.data(), ptr, size);
+    }
+    return vec;
+}
+
+hidl_array<uint8_t, 16> toHidlArray16(const uint8_t *ptr) {
+    if (ptr == nullptr) {
+        return hidl_array<uint8_t, 16>();
+    }
+    return hidl_array<uint8_t, 16>(ptr);
+}
+
+sp<::V1_0::IDrmPlugin> MakeDrmPlugin(const sp<::V1_0::IDrmFactory> &factory,
+                                     const uint8_t uuid[16], const char *appPackageName) {
+    sp<::V1_0::IDrmPlugin> plugin;
+    factory->createPlugin(toHidlArray16(uuid), hidl_string(appPackageName),
+                          [&](::V1_0::Status status, const sp<::V1_0::IDrmPlugin> &hPlugin) {
+                              if (status != ::V1_0::Status::OK) {
+                                  return;
+                              }
+                              plugin = hPlugin;
+                          });
+    return plugin;
+}
+
+sp<::V1_0::ICryptoPlugin> MakeCryptoPlugin(const sp<::V1_0::ICryptoFactory> &factory,
+                                           const uint8_t uuid[16], const void *initData,
+                                           size_t initDataSize) {
+    sp<::V1_0::ICryptoPlugin> plugin;
+    factory->createPlugin(toHidlArray16(uuid), toHidlVec(initData, initDataSize),
+                          [&](::V1_0::Status status, const sp<::V1_0::ICryptoPlugin> &hPlugin) {
+                              if (status != ::V1_0::Status::OK) {
+                                  return;
+                              }
+                              plugin = hPlugin;
+                          });
+    return plugin;
+}
+
+} // namespace
+
+bool UseDrmService() {
+    return property_get_bool("mediadrm.use_mediadrmserver", true);
+}
+
+sp<IDrm> MakeDrm(status_t *pstatus) {
+    return MakeObject<DrmHal>(pstatus);
+}
+
+sp<ICrypto> MakeCrypto(status_t *pstatus) {
+    return MakeObject<CryptoHal>(pstatus);
+}
+
+std::vector<sp<::V1_0::IDrmFactory>> MakeDrmFactories(const uint8_t uuid[16]) {
+    std::vector<sp<::V1_0::IDrmFactory>> drmFactories;
+    MakeHidlFactories<::V1_0::IDrmFactory>(uuid, drmFactories);
+    MakeHidlFactories<::V1_1::IDrmFactory>(uuid, drmFactories);
+    MakeHidlFactories<::V1_2::IDrmFactory>(uuid, drmFactories);
+    return drmFactories;
+}
+
+std::vector<sp<::V1_0::IDrmPlugin>> MakeDrmPlugins(const uint8_t uuid[16],
+                                              const char *appPackageName) {
+    std::vector<sp<::V1_0::IDrmPlugin>> plugins;
+    for (const auto &factory : MakeDrmFactories(uuid)) {
+        plugins.push_back(MakeDrmPlugin(factory, uuid, appPackageName));
+    }
+    return plugins;
+}
+
+std::vector<sp<::V1_0::ICryptoFactory>> MakeCryptoFactories(const uint8_t uuid[16]) {
+    std::vector<sp<::V1_0::ICryptoFactory>> cryptoFactories;
+    MakeHidlFactories<::V1_0::ICryptoFactory>(uuid, cryptoFactories);
+    MakeHidlFactories<::V1_1::ICryptoFactory>(uuid, cryptoFactories);
+    MakeHidlFactories<::V1_2::ICryptoFactory>(uuid, cryptoFactories);
+    return cryptoFactories;
+}
+
+std::vector<sp<ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16], const void *initData,
+                                                 size_t initDataSize) {
+    std::vector<sp<ICryptoPlugin>> plugins;
+    for (const auto &factory : MakeCryptoFactories(uuid)) {
+        plugins.push_back(MakeCryptoPlugin(factory, uuid, initData, initDataSize));
+    }
+    return plugins;
+}
+
+}  // namespace DrmUtils
+}  // namespace android
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
deleted file mode 100644
index a2594aa..0000000
--- a/drm/libmediadrm/ICrypto.cpp
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright (C) 2012 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 "ICrypto"
-#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <cutils/log.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <mediadrm/ICrypto.h>
-#include <utils/Log.h>
-
-namespace android {
-
-enum {
-    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
-    IS_CRYPTO_SUPPORTED,
-    CREATE_PLUGIN,
-    DESTROY_PLUGIN,
-    REQUIRES_SECURE_COMPONENT,
-    DECRYPT,
-    NOTIFY_RESOLUTION,
-    SET_MEDIADRM_SESSION,
-    SET_HEAP,
-    UNSET_HEAP,
-};
-
-struct BpCrypto : public BpInterface<ICrypto> {
-    explicit BpCrypto(const sp<IBinder> &impl)
-        : BpInterface<ICrypto>(impl) {
-    }
-
-    virtual status_t initCheck() const {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        remote()->transact(INIT_CHECK, data, &reply);
-
-        return reply.readInt32();
-    }
-
-    virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.write(uuid, 16);
-        remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
-
-        return reply.readInt32() != 0;
-    }
-
-    virtual status_t createPlugin(
-            const uint8_t uuid[16], const void *opaqueData, size_t opaqueSize) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.write(uuid, 16);
-        data.writeInt32(opaqueSize);
-
-        if (opaqueSize > 0) {
-            data.write(opaqueData, opaqueSize);
-        }
-
-        remote()->transact(CREATE_PLUGIN, data, &reply);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t destroyPlugin() {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        remote()->transact(DESTROY_PLUGIN, data, &reply);
-
-        return reply.readInt32();
-    }
-
-    virtual bool requiresSecureDecoderComponent(
-            const char *mime) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeCString(mime);
-        remote()->transact(REQUIRES_SECURE_COMPONENT, data, &reply);
-
-        return reply.readInt32() != 0;
-    }
-
-    virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
-            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const SourceBuffer &source, size_t offset,
-            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
-            const DestinationBuffer &destination, AString *errorDetailMsg) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeInt32(mode);
-        data.writeInt32(pattern.mEncryptBlocks);
-        data.writeInt32(pattern.mSkipBlocks);
-
-        static const uint8_t kDummy[16] = { 0 };
-
-        if (key == NULL) {
-            key = kDummy;
-        }
-
-        if (iv == NULL) {
-            iv = kDummy;
-        }
-
-        data.write(key, 16);
-        data.write(iv, 16);
-
-        size_t totalSize = 0;
-        for (size_t i = 0; i < numSubSamples; ++i) {
-            totalSize += subSamples[i].mNumBytesOfEncryptedData;
-            totalSize += subSamples[i].mNumBytesOfClearData;
-        }
-
-        data.writeInt32(totalSize);
-        data.writeStrongBinder(IInterface::asBinder(source.mSharedMemory));
-        data.writeInt32(source.mHeapSeqNum);
-        data.writeInt32(offset);
-
-        data.writeInt32(numSubSamples);
-        data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
-
-        data.writeInt32((int32_t)destination.mType);
-        if (destination.mType == kDestinationTypeNativeHandle) {
-            if (destination.mHandle == NULL) {
-                return BAD_VALUE;
-            }
-            data.writeNativeHandle(destination.mHandle);
-        } else {
-            if (destination.mSharedMemory == NULL) {
-                return BAD_VALUE;
-            }
-            data.writeStrongBinder(IInterface::asBinder(destination.mSharedMemory));
-        }
-
-        remote()->transact(DECRYPT, data, &reply);
-
-        ssize_t result = reply.readInt32();
-
-        if (isCryptoError(result)) {
-            AString msg = reply.readCString();
-            if (errorDetailMsg) {
-                *errorDetailMsg = msg;
-            }
-        }
-
-        return result;
-    }
-
-    virtual void notifyResolution(
-        uint32_t width, uint32_t height) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeInt32(width);
-        data.writeInt32(height);
-        remote()->transact(NOTIFY_RESOLUTION, data, &reply);
-    }
-
-    virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        remote()->transact(SET_MEDIADRM_SESSION, data, &reply);
-
-        return reply.readInt32();
-    }
-
-    virtual int32_t setHeap(const sp<IMemoryHeap> &heap) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(heap));
-        status_t err = remote()->transact(SET_HEAP, data, &reply);
-        if (err != NO_ERROR) {
-            return -1;
-        }
-        int32_t seqNum;
-        if (reply.readInt32(&seqNum) != NO_ERROR) {
-            return -1;
-        }
-        return seqNum;
-    }
-
-    virtual void unsetHeap(int32_t seqNum) {
-        Parcel data, reply;
-        data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
-        data.writeInt32(seqNum);
-        remote()->transact(UNSET_HEAP, data, &reply);
-        return;
-    }
-
-
-private:
-    void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
-        uint32_t size = reply.readInt32();
-        vector.insertAt((size_t)0, size);
-        reply.read(vector.editArray(), size);
-    }
-
-    void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
-        data.writeInt32(vector.size());
-        data.write(vector.array(), vector.size());
-    }
-
-    DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
-};
-
-IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
-
-////////////////////////////////////////////////////////////////////////////////
-
-void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
-    uint32_t size = data.readInt32();
-    if (vector.insertAt((size_t)0, size) < 0) {
-        vector.clear();
-    }
-    if (data.read(vector.editArray(), size) != NO_ERROR) {
-        vector.clear();
-        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
-    }
-}
-
-void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
-    reply->writeInt32(vector.size());
-    reply->write(vector.array(), vector.size());
-}
-
-status_t BnCrypto::onTransact(
-    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
-    switch (code) {
-        case INIT_CHECK:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-            reply->writeInt32(initCheck());
-
-            return OK;
-        }
-
-        case IS_CRYPTO_SUPPORTED:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-            uint8_t uuid[16];
-            data.read(uuid, sizeof(uuid));
-            reply->writeInt32(isCryptoSchemeSupported(uuid));
-
-            return OK;
-        }
-
-        case CREATE_PLUGIN:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-
-            uint8_t uuid[16];
-            data.read(uuid, sizeof(uuid));
-
-            size_t opaqueSize = data.readInt32();
-            void *opaqueData = NULL;
-
-            const size_t kMaxOpaqueSize = 100 * 1024;
-            if (opaqueSize > kMaxOpaqueSize) {
-                return BAD_VALUE;
-            }
-
-            opaqueData = malloc(opaqueSize);
-            if (NULL == opaqueData) {
-                return NO_MEMORY;
-            }
-
-            data.read(opaqueData, opaqueSize);
-            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));
-
-            free(opaqueData);
-            opaqueData = NULL;
-
-            return OK;
-        }
-
-        case DESTROY_PLUGIN:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-            reply->writeInt32(destroyPlugin());
-
-            return OK;
-        }
-
-        case REQUIRES_SECURE_COMPONENT:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-
-            const char *mime = data.readCString();
-            if (mime == NULL) {
-                reply->writeInt32(BAD_VALUE);
-            } else {
-                reply->writeInt32(requiresSecureDecoderComponent(mime));
-            }
-
-            return OK;
-        }
-
-        case DECRYPT:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-
-            CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
-            CryptoPlugin::Pattern pattern;
-            pattern.mEncryptBlocks = data.readInt32();
-            pattern.mSkipBlocks = data.readInt32();
-
-            uint8_t key[16];
-            data.read(key, sizeof(key));
-
-            uint8_t iv[16];
-            data.read(iv, sizeof(iv));
-
-            size_t totalSize = data.readInt32();
-
-            SourceBuffer source;
-
-            source.mSharedMemory =
-                interface_cast<IMemory>(data.readStrongBinder());
-            if (source.mSharedMemory == NULL) {
-                reply->writeInt32(BAD_VALUE);
-                return OK;
-            }
-            source.mHeapSeqNum = data.readInt32();
-
-            int32_t offset = data.readInt32();
-
-            int32_t numSubSamples = data.readInt32();
-            if (numSubSamples < 0 || numSubSamples > 0xffff) {
-                reply->writeInt32(BAD_VALUE);
-                return OK;
-            }
-
-            std::unique_ptr<CryptoPlugin::SubSample[]> subSamples =
-                    std::make_unique<CryptoPlugin::SubSample[]>(numSubSamples);
-
-            data.read(subSamples.get(),
-                    sizeof(CryptoPlugin::SubSample) * numSubSamples);
-
-            DestinationBuffer destination;
-            destination.mType = (DestinationType)data.readInt32();
-            if (destination.mType == kDestinationTypeNativeHandle) {
-                destination.mHandle = data.readNativeHandle();
-                if (destination.mHandle == NULL) {
-                    reply->writeInt32(BAD_VALUE);
-                    return OK;
-                }
-            } else if (destination.mType == kDestinationTypeSharedMemory) {
-                destination.mSharedMemory =
-                        interface_cast<IMemory>(data.readStrongBinder());
-                if (destination.mSharedMemory == NULL) {
-                    reply->writeInt32(BAD_VALUE);
-                    return OK;
-                }
-                sp<IMemory> dest = destination.mSharedMemory;
-                if (totalSize > dest->size() ||
-                        (size_t)dest->offset() > dest->size() - totalSize) {
-                    reply->writeInt32(BAD_VALUE);
-                    android_errorWriteLog(0x534e4554, "71389378");
-                    return OK;
-                }
-            } else {
-                reply->writeInt32(BAD_VALUE);
-                android_errorWriteLog(0x534e4554, "70526702");
-                return OK;
-            }
-
-            AString errorDetailMsg;
-            ssize_t result;
-
-            size_t sumSubsampleSizes = 0;
-            bool overflow = false;
-            for (int32_t i = 0; i < numSubSamples; ++i) {
-                CryptoPlugin::SubSample &ss = subSamples[i];
-                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
-                    sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
-                } else {
-                    overflow = true;
-                }
-                if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
-                    sumSubsampleSizes += ss.mNumBytesOfClearData;
-                } else {
-                    overflow = true;
-                }
-            }
-
-            if (overflow || sumSubsampleSizes != totalSize) {
-                result = -EINVAL;
-            } else if (totalSize > source.mSharedMemory->size()) {
-                result = -EINVAL;
-            } else if ((size_t)offset > source.mSharedMemory->size() - totalSize) {
-                result = -EINVAL;
-            } else {
-                result = decrypt(key, iv, mode, pattern, source, offset,
-                        subSamples.get(), numSubSamples, destination, &errorDetailMsg);
-            }
-
-            reply->writeInt32(result);
-
-            if (isCryptoError(result)) {
-                reply->writeCString(errorDetailMsg.c_str());
-            }
-
-            if (destination.mType == kDestinationTypeNativeHandle) {
-                int err;
-                if ((err = native_handle_close(destination.mHandle)) < 0) {
-                    ALOGW("secure buffer native_handle_close failed: %d", err);
-                }
-                if ((err = native_handle_delete(destination.mHandle)) < 0) {
-                    ALOGW("secure buffer native_handle_delete failed: %d", err);
-                }
-            }
-
-            subSamples.reset();
-            return OK;
-        }
-
-        case NOTIFY_RESOLUTION:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-
-            int32_t width = data.readInt32();
-            int32_t height = data.readInt32();
-            notifyResolution(width, height);
-
-            return OK;
-        }
-
-        case SET_MEDIADRM_SESSION:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId;
-            readVector(data, sessionId);
-            reply->writeInt32(setMediaDrmSession(sessionId));
-            return OK;
-        }
-
-        case SET_HEAP:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-            sp<IMemoryHeap> heap =
-                interface_cast<IMemoryHeap>(data.readStrongBinder());
-            reply->writeInt32(setHeap(heap));
-            return OK;
-        }
-
-        case UNSET_HEAP:
-        {
-            CHECK_INTERFACE(ICrypto, data, reply);
-            int32_t seqNum = data.readInt32();
-            unsetHeap(seqNum);
-            return OK;
-        }
-
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}  // namespace android
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
deleted file mode 100644
index 51274d1..0000000
--- a/drm/libmediadrm/IDrm.cpp
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*
- * Copyright (C) 2013 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 "IDrm"
-#include <utils/Log.h>
-
-#include <binder/Parcel.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AString.h>
-#include <mediadrm/IDrm.h>
-
-namespace android {
-
-enum {
-    INIT_CHECK = IBinder::FIRST_CALL_TRANSACTION,
-    IS_CRYPTO_SUPPORTED,
-    CREATE_PLUGIN,
-    DESTROY_PLUGIN,
-    OPEN_SESSION,
-    CLOSE_SESSION,
-    GET_KEY_REQUEST,
-    PROVIDE_KEY_RESPONSE,
-    REMOVE_KEYS,
-    RESTORE_KEYS,
-    QUERY_KEY_STATUS,
-    GET_PROVISION_REQUEST,
-    PROVIDE_PROVISION_RESPONSE,
-    GET_SECURE_STOPS,
-    RELEASE_SECURE_STOPS,
-    GET_PROPERTY_STRING,
-    GET_PROPERTY_BYTE_ARRAY,
-    SET_PROPERTY_STRING,
-    SET_PROPERTY_BYTE_ARRAY,
-    GET_METRICS,
-    SET_CIPHER_ALGORITHM,
-    SET_MAC_ALGORITHM,
-    ENCRYPT,
-    DECRYPT,
-    SIGN,
-    SIGN_RSA,
-    VERIFY,
-    SET_LISTENER,
-    GET_SECURE_STOP,
-    REMOVE_ALL_SECURE_STOPS,
-    GET_HDCP_LEVELS,
-    GET_NUMBER_OF_SESSIONS,
-    GET_SECURITY_LEVEL,
-    REMOVE_SECURE_STOP,
-    GET_SECURE_STOP_IDS,
-    GET_OFFLINE_LICENSE_KEYSET_IDS,
-    REMOVE_OFFLINE_LICENSE,
-    GET_OFFLINE_LICENSE_STATE
-};
-
-struct BpDrm : public BpInterface<IDrm> {
-    explicit BpDrm(const sp<IBinder> &impl)
-        : BpInterface<IDrm>(impl) {
-    }
-
-    virtual status_t initCheck() const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-        status_t status = remote()->transact(INIT_CHECK, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
-            DrmPlugin::SecurityLevel level, bool *isSupported) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-        data.write(uuid, 16);
-        data.writeString8(mimeType);
-        data.writeInt32(level);
-
-        status_t status = remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
-        if (status != OK) {
-            ALOGE("isCryptoSchemeSupported: binder call failed: %d", status);
-            return status;
-        }
-        *isSupported = static_cast<bool>(reply.readInt32());
-
-        return reply.readInt32();
-    }
-
-    virtual status_t createPlugin(const uint8_t uuid[16],
-                                  const String8& appPackageName) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-        data.write(uuid, 16);
-        data.writeString8(appPackageName);
-        status_t status = remote()->transact(CREATE_PLUGIN, data, &reply);
-        if (status != OK) {
-            ALOGE("createPlugin: binder call failed: %d", status);
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t destroyPlugin() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-        status_t status = remote()->transact(DESTROY_PLUGIN, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t openSession(DrmPlugin::SecurityLevel level,
-            Vector<uint8_t> &sessionId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-        data.writeInt32(level);
-
-        status_t status = remote()->transact(OPEN_SESSION, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        readVector(reply, sessionId);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t closeSession(Vector<uint8_t> const &sessionId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        status_t status = remote()->transact(CLOSE_SESSION, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t
-        getKeyRequest(Vector<uint8_t> const &sessionId,
-                      Vector<uint8_t> const &initData,
-                      String8 const &mimeType, DrmPlugin::KeyType keyType,
-                      KeyedVector<String8, String8> const &optionalParameters,
-                      Vector<uint8_t> &request, String8 &defaultUrl,
-                      DrmPlugin::KeyRequestType *keyRequestType) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        writeVector(data, initData);
-        data.writeString8(mimeType);
-        data.writeInt32((uint32_t)keyType);
-
-        data.writeInt32(optionalParameters.size());
-        for (size_t i = 0; i < optionalParameters.size(); ++i) {
-            data.writeString8(optionalParameters.keyAt(i));
-            data.writeString8(optionalParameters.valueAt(i));
-        }
-
-        status_t status = remote()->transact(GET_KEY_REQUEST, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        readVector(reply, request);
-        defaultUrl = reply.readString8();
-        *keyRequestType = static_cast<DrmPlugin::KeyRequestType>(reply.readInt32());
-
-        return reply.readInt32();
-    }
-
-    virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
-                                        Vector<uint8_t> const &response,
-                                        Vector<uint8_t> &keySetId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-        writeVector(data, sessionId);
-        writeVector(data, response);
-
-        status_t status = remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        readVector(reply, keySetId);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t removeKeys(Vector<uint8_t> const &keySetId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, keySetId);
-        status_t status = remote()->transact(REMOVE_KEYS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
-                                 Vector<uint8_t> const &keySetId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        writeVector(data, keySetId);
-        status_t status = remote()->transact(RESTORE_KEYS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
-                                        KeyedVector<String8, String8> &infoMap) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        status_t status = remote()->transact(QUERY_KEY_STATUS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        infoMap.clear();
-        size_t count = reply.readInt32();
-        for (size_t i = 0; i < count; i++) {
-            String8 key = reply.readString8();
-            String8 value = reply.readString8();
-            infoMap.add(key, value);
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t getProvisionRequest(String8 const &certType,
-                                         String8 const &certAuthority,
-                                         Vector<uint8_t> &request,
-                                         String8 &defaultUrl) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        data.writeString8(certType);
-        data.writeString8(certAuthority);
-        status_t status = remote()->transact(GET_PROVISION_REQUEST, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        readVector(reply, request);
-        defaultUrl = reply.readString8();
-
-        return reply.readInt32();
-    }
-
-    virtual status_t provideProvisionResponse(Vector<uint8_t> const &response,
-                                              Vector<uint8_t> &certificate,
-                                              Vector<uint8_t> &wrappedKey) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, response);
-        status_t status = remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        readVector(reply, certificate);
-        readVector(reply, wrappedKey);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(GET_SECURE_STOPS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        secureStops.clear();
-        uint32_t count = reply.readInt32();
-        for (size_t i = 0; i < count; i++) {
-            Vector<uint8_t> secureStop;
-            readVector(reply, secureStop);
-            secureStops.push_back(secureStop);
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t getSecureStopIds(List<Vector<uint8_t> > &secureStopIds) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(GET_SECURE_STOP_IDS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        secureStopIds.clear();
-        uint32_t count = reply.readInt32();
-        for (size_t i = 0; i < count; i++) {
-            Vector<uint8_t> secureStopId;
-            readVector(reply, secureStopId);
-            secureStopIds.push_back(secureStopId);
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, ssid);
-        status_t status = remote()->transact(GET_SECURE_STOP, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        readVector(reply, secureStop);
-        return reply.readInt32();
-    }
-
-    virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, ssRelease);
-        status_t status = remote()->transact(RELEASE_SECURE_STOPS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t removeSecureStop(Vector<uint8_t> const &ssid) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, ssid);
-        status_t status = remote()->transact(REMOVE_SECURE_STOP, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t removeAllSecureStops() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(REMOVE_ALL_SECURE_STOPS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t getOfflineLicenseKeySetIds(List<Vector<uint8_t> > &keySetIds) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(GET_OFFLINE_LICENSE_KEYSET_IDS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        keySetIds.clear();
-        uint32_t count = reply.readInt32();
-        for (size_t i = 0; i < count; i++) {
-            Vector<uint8_t> keySetId;
-            readVector(reply, keySetId);
-            keySetIds.push_back(keySetId);
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t removeOfflineLicense(Vector<uint8_t> const &keySetId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, keySetId);
-        status_t status = remote()->transact(REMOVE_OFFLINE_LICENSE, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t getOfflineLicenseState(Vector<uint8_t> const &keySetId,
-            DrmPlugin::OfflineLicenseState *licenseState) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, keySetId);
-        status_t status = remote()->transact(GET_OFFLINE_LICENSE_STATE, data, &reply);
-        if (status != OK) {
-            *licenseState = DrmPlugin::OfflineLicenseState::kOfflineLicenseStateUnknown;
-            return status;
-        }
-        *licenseState = static_cast<DrmPlugin::OfflineLicenseState>(reply.readInt32());
-        return reply.readInt32();
-    }
-
-    virtual status_t getPropertyString(String8 const &name, String8 &value) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        data.writeString8(name);
-        status_t status = remote()->transact(GET_PROPERTY_STRING, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        value = reply.readString8();
-        return reply.readInt32();
-    }
-
-    virtual status_t getHdcpLevels(DrmPlugin::HdcpLevel *connected,
-            DrmPlugin::HdcpLevel *max) const {
-        Parcel data, reply;
-
-        if (connected == NULL || max == NULL) {
-            return BAD_VALUE;
-        }
-
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(GET_HDCP_LEVELS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        *connected = static_cast<DrmPlugin::HdcpLevel>(reply.readInt32());
-        *max = static_cast<DrmPlugin::HdcpLevel>(reply.readInt32());
-        return reply.readInt32();
-    }
-
-    virtual status_t getNumberOfSessions(uint32_t *open, uint32_t *max) const {
-        Parcel data, reply;
-
-        if (open == NULL || max == NULL) {
-            return BAD_VALUE;
-        }
-
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(GET_NUMBER_OF_SESSIONS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        *open = reply.readInt32();
-        *max = reply.readInt32();
-        return reply.readInt32();
-    }
-
-    virtual status_t getSecurityLevel(Vector<uint8_t> const &sessionId,
-            DrmPlugin::SecurityLevel *level) const {
-        Parcel data, reply;
-
-        if (level == NULL) {
-            return BAD_VALUE;
-        }
-
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        status_t status = remote()->transact(GET_SECURITY_LEVEL, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        *level = static_cast<DrmPlugin::SecurityLevel>(reply.readInt32());
-        return reply.readInt32();
-    }
-
-    virtual status_t getPropertyByteArray(String8 const &name, Vector<uint8_t> &value) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        data.writeString8(name);
-        status_t status = remote()->transact(GET_PROPERTY_BYTE_ARRAY, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        readVector(reply, value);
-        return reply.readInt32();
-    }
-
-    virtual status_t setPropertyString(String8 const &name, String8 const &value) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        data.writeString8(name);
-        data.writeString8(value);
-        status_t status = remote()->transact(SET_PROPERTY_STRING, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t setPropertyByteArray(String8 const &name,
-                                          Vector<uint8_t> const &value) const {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        data.writeString8(name);
-        writeVector(data, value);
-        status_t status = remote()->transact(SET_PROPERTY_BYTE_ARRAY, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-
-        return reply.readInt32();
-    }
-
-    virtual status_t getMetrics(os::PersistableBundle *metrics) {
-        if (metrics == NULL) {
-            return BAD_VALUE;
-        }
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        status_t status = remote()->transact(GET_METRICS, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        // The reply data is ordered as
-        // 1) 32 bit integer reply followed by
-        // 2) Serialized PersistableBundle containing metrics.
-        status_t reply_status;
-        if (reply.readInt32(&reply_status) != OK
-           || reply_status != OK) {
-          ALOGE("Failed to read getMetrics response code from parcel. %d",
-                reply_status);
-          return reply_status;
-        }
-
-        status = metrics->readFromParcel(&reply);
-        if (status != OK) {
-            ALOGE("Failed to read metrics from parcel. %d", status);
-            return status;
-        }
-        return reply_status;
-    }
-
-    virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
-                                        String8 const &algorithm) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        data.writeString8(algorithm);
-        status_t status = remote()->transact(SET_CIPHER_ALGORITHM, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
-                                     String8 const &algorithm) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        data.writeString8(algorithm);
-        status_t status = remote()->transact(SET_MAC_ALGORITHM, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        return reply.readInt32();
-    }
-
-    virtual status_t encrypt(Vector<uint8_t> const &sessionId,
-                             Vector<uint8_t> const &keyId,
-                             Vector<uint8_t> const &input,
-                             Vector<uint8_t> const &iv,
-                             Vector<uint8_t> &output) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        writeVector(data, keyId);
-        writeVector(data, input);
-        writeVector(data, iv);
-
-        status_t status = remote()->transact(ENCRYPT, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        readVector(reply, output);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t decrypt(Vector<uint8_t> const &sessionId,
-                             Vector<uint8_t> const &keyId,
-                             Vector<uint8_t> const &input,
-                             Vector<uint8_t> const &iv,
-                             Vector<uint8_t> &output) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        writeVector(data, keyId);
-        writeVector(data, input);
-        writeVector(data, iv);
-
-        status_t status = remote()->transact(DECRYPT, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        readVector(reply, output);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t sign(Vector<uint8_t> const &sessionId,
-                          Vector<uint8_t> const &keyId,
-                          Vector<uint8_t> const &message,
-                          Vector<uint8_t> &signature) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        writeVector(data, keyId);
-        writeVector(data, message);
-
-        status_t status = remote()->transact(SIGN, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        readVector(reply, signature);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t verify(Vector<uint8_t> const &sessionId,
-                            Vector<uint8_t> const &keyId,
-                            Vector<uint8_t> const &message,
-                            Vector<uint8_t> const &signature,
-                            bool &match) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        writeVector(data, keyId);
-        writeVector(data, message);
-        writeVector(data, signature);
-
-        status_t status = remote()->transact(VERIFY, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        match = (bool)reply.readInt32();
-        return reply.readInt32();
-    }
-
-    virtual status_t signRSA(Vector<uint8_t> const &sessionId,
-                             String8 const &algorithm,
-                             Vector<uint8_t> const &message,
-                             Vector<uint8_t> const &wrappedKey,
-                             Vector<uint8_t> &signature) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
-        writeVector(data, sessionId);
-        data.writeString8(algorithm);
-        writeVector(data, message);
-        writeVector(data, wrappedKey);
-
-        status_t status = remote()->transact(SIGN_RSA, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        readVector(reply, signature);
-
-        return reply.readInt32();
-    }
-
-    virtual status_t setListener(const sp<IDrmClient>& listener) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-        data.writeStrongBinder(IInterface::asBinder(listener));
-        status_t status = remote()->transact(SET_LISTENER, data, &reply);
-        if (status != OK) {
-            return status;
-        }
-        return reply.readInt32();
-    }
-
-private:
-    void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
-        uint32_t size = reply.readInt32();
-        vector.insertAt((size_t)0, size);
-        reply.read(vector.editArray(), size);
-    }
-
-    void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
-        data.writeInt32(vector.size());
-        data.write(vector.array(), vector.size());
-    }
-
-    DISALLOW_EVIL_CONSTRUCTORS(BpDrm);
-};
-
-IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm");
-
-////////////////////////////////////////////////////////////////////////////////
-
-void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
-    uint32_t size = data.readInt32();
-    if (vector.insertAt((size_t)0, size) < 0) {
-        vector.clear();
-    }
-    if (data.read(vector.editArray(), size) != NO_ERROR) {
-        vector.clear();
-        android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
-    }
-}
-
-void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
-    reply->writeInt32(vector.size());
-    reply->write(vector.array(), vector.size());
-}
-
-status_t BnDrm::onTransact(
-    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
-    switch (code) {
-        case INIT_CHECK:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            reply->writeInt32(initCheck());
-            return OK;
-        }
-
-        case IS_CRYPTO_SUPPORTED:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            uint8_t uuid[16];
-            data.read(uuid, sizeof(uuid));
-            String8 mimeType = data.readString8();
-            DrmPlugin::SecurityLevel level =
-                    static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
-            bool isSupported = false;
-            status_t result = isCryptoSchemeSupported(uuid, mimeType, level, &isSupported);
-            reply->writeInt32(isSupported);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case CREATE_PLUGIN:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            uint8_t uuid[16];
-            data.read(uuid, sizeof(uuid));
-            String8 appPackageName = data.readString8();
-            reply->writeInt32(createPlugin(uuid, appPackageName));
-            return OK;
-        }
-
-        case DESTROY_PLUGIN:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            reply->writeInt32(destroyPlugin());
-            return OK;
-        }
-
-        case OPEN_SESSION:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            DrmPlugin::SecurityLevel level =
-                    static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
-            Vector<uint8_t> sessionId;
-            status_t result = openSession(level, sessionId);
-            writeVector(reply, sessionId);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case CLOSE_SESSION:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId;
-            readVector(data, sessionId);
-            reply->writeInt32(closeSession(sessionId));
-            return OK;
-        }
-
-        case GET_KEY_REQUEST:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, initData;
-
-            readVector(data, sessionId);
-            readVector(data, initData);
-            String8 mimeType = data.readString8();
-            DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32();
-
-            KeyedVector<String8, String8> optionalParameters;
-            uint32_t count = data.readInt32();
-            for (size_t i = 0; i < count; ++i) {
-                String8 key, value;
-                key = data.readString8();
-                value = data.readString8();
-                optionalParameters.add(key, value);
-            }
-
-            Vector<uint8_t> request;
-            String8 defaultUrl;
-            DrmPlugin::KeyRequestType keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
-
-            status_t result = getKeyRequest(sessionId, initData, mimeType,
-                    keyType, optionalParameters, request, defaultUrl,
-                    &keyRequestType);
-
-            writeVector(reply, request);
-            reply->writeString8(defaultUrl);
-            reply->writeInt32(static_cast<int32_t>(keyRequestType));
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case PROVIDE_KEY_RESPONSE:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, response, keySetId;
-            readVector(data, sessionId);
-            readVector(data, response);
-            uint32_t result = provideKeyResponse(sessionId, response, keySetId);
-            writeVector(reply, keySetId);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case REMOVE_KEYS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> keySetId;
-            readVector(data, keySetId);
-            reply->writeInt32(removeKeys(keySetId));
-            return OK;
-        }
-
-        case RESTORE_KEYS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, keySetId;
-            readVector(data, sessionId);
-            readVector(data, keySetId);
-            reply->writeInt32(restoreKeys(sessionId, keySetId));
-            return OK;
-        }
-
-        case QUERY_KEY_STATUS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId;
-            readVector(data, sessionId);
-            KeyedVector<String8, String8> infoMap;
-            status_t result = queryKeyStatus(sessionId, infoMap);
-            size_t count = infoMap.size();
-            reply->writeInt32(count);
-            for (size_t i = 0; i < count; ++i) {
-                reply->writeString8(infoMap.keyAt(i));
-                reply->writeString8(infoMap.valueAt(i));
-            }
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_PROVISION_REQUEST:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            String8 certType = data.readString8();
-            String8 certAuthority = data.readString8();
-
-            Vector<uint8_t> request;
-            String8 defaultUrl;
-            status_t result = getProvisionRequest(certType, certAuthority,
-                                                  request, defaultUrl);
-            writeVector(reply, request);
-            reply->writeString8(defaultUrl);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case PROVIDE_PROVISION_RESPONSE:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> response;
-            Vector<uint8_t> certificate;
-            Vector<uint8_t> wrappedKey;
-            readVector(data, response);
-            status_t result = provideProvisionResponse(response, certificate, wrappedKey);
-            writeVector(reply, certificate);
-            writeVector(reply, wrappedKey);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_SECURE_STOPS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            List<Vector<uint8_t> > secureStops;
-            status_t result = getSecureStops(secureStops);
-            size_t count = secureStops.size();
-            reply->writeInt32(count);
-            List<Vector<uint8_t> >::iterator iter = secureStops.begin();
-            while(iter != secureStops.end()) {
-                size_t size = iter->size();
-                reply->writeInt32(size);
-                reply->write(iter->array(), iter->size());
-                iter++;
-            }
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_SECURE_STOP_IDS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            List<Vector<uint8_t> > secureStopIds;
-            status_t result = getSecureStopIds(secureStopIds);
-            size_t count = secureStopIds.size();
-            reply->writeInt32(count);
-            List<Vector<uint8_t> >::iterator iter = secureStopIds.begin();
-            while(iter != secureStopIds.end()) {
-                size_t size = iter->size();
-                reply->writeInt32(size);
-                reply->write(iter->array(), iter->size());
-                iter++;
-            }
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_SECURE_STOP:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> ssid, secureStop;
-            readVector(data, ssid);
-            status_t result = getSecureStop(ssid, secureStop);
-            writeVector(reply, secureStop);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case RELEASE_SECURE_STOPS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> ssRelease;
-            readVector(data, ssRelease);
-            reply->writeInt32(releaseSecureStops(ssRelease));
-            return OK;
-        }
-
-        case REMOVE_SECURE_STOP:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> ssid;
-            readVector(data, ssid);
-            reply->writeInt32(removeSecureStop(ssid));
-            return OK;
-        }
-
-        case REMOVE_ALL_SECURE_STOPS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            reply->writeInt32(removeAllSecureStops());
-            return OK;
-        }
-
-        case GET_HDCP_LEVELS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            DrmPlugin::HdcpLevel connected = DrmPlugin::kHdcpLevelUnknown;
-            DrmPlugin::HdcpLevel max = DrmPlugin::kHdcpLevelUnknown;
-            status_t result = getHdcpLevels(&connected, &max);
-            reply->writeInt32(connected);
-            reply->writeInt32(max);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_NUMBER_OF_SESSIONS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            uint32_t open = 0, max = 0;
-            status_t result = getNumberOfSessions(&open, &max);
-            reply->writeInt32(open);
-            reply->writeInt32(max);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_SECURITY_LEVEL:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId;
-            readVector(data, sessionId);
-            DrmPlugin::SecurityLevel level = DrmPlugin::kSecurityLevelUnknown;
-            status_t result = getSecurityLevel(sessionId, &level);
-            reply->writeInt32(level);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_OFFLINE_LICENSE_KEYSET_IDS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            List<Vector<uint8_t> > keySetIds;
-            status_t result = getOfflineLicenseKeySetIds(keySetIds);
-            size_t count = keySetIds.size();
-            reply->writeInt32(count);
-            List<Vector<uint8_t> >::iterator iter = keySetIds.begin();
-            while(iter != keySetIds.end()) {
-                size_t size = iter->size();
-                reply->writeInt32(size);
-                reply->write(iter->array(), iter->size());
-                iter++;
-            }
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case REMOVE_OFFLINE_LICENSE:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> keySetId;
-            readVector(data, keySetId);
-            reply->writeInt32(removeOfflineLicense(keySetId));
-            return OK;
-        }
-
-        case GET_OFFLINE_LICENSE_STATE:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> keySetId;
-            readVector(data, keySetId);
-            DrmPlugin::OfflineLicenseState state;
-            status_t result = getOfflineLicenseState(keySetId, &state);
-            reply->writeInt32(static_cast<DrmPlugin::OfflineLicenseState>(state));
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_PROPERTY_STRING:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            String8 name = data.readString8();
-            String8 value;
-            status_t result = getPropertyString(name, value);
-            reply->writeString8(value);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case GET_PROPERTY_BYTE_ARRAY:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            String8 name = data.readString8();
-            Vector<uint8_t> value;
-            status_t result = getPropertyByteArray(name, value);
-            writeVector(reply, value);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case SET_PROPERTY_STRING:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            String8 name = data.readString8();
-            String8 value = data.readString8();
-            reply->writeInt32(setPropertyString(name, value));
-            return OK;
-        }
-
-        case SET_PROPERTY_BYTE_ARRAY:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            String8 name = data.readString8();
-            Vector<uint8_t> value;
-            readVector(data, value);
-            reply->writeInt32(setPropertyByteArray(name, value));
-            return OK;
-        }
-
-        case GET_METRICS:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-
-            os::PersistableBundle metrics;
-            status_t result = getMetrics(&metrics);
-            // The reply data is ordered as
-            // 1) 32 bit integer reply followed by
-            // 2) Serialized PersistableBundle containing metrics.
-            // Only write the metrics if the getMetrics result was
-            // OK and we successfully added the status to reply.
-            status_t parcel_result = reply->writeInt32(result);
-            if (result == OK && parcel_result == OK) {
-                parcel_result = metrics.writeToParcel(reply);
-            }
-            return parcel_result;
-        }
-
-        case SET_CIPHER_ALGORITHM:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId;
-            readVector(data, sessionId);
-            String8 algorithm = data.readString8();
-            reply->writeInt32(setCipherAlgorithm(sessionId, algorithm));
-            return OK;
-        }
-
-        case SET_MAC_ALGORITHM:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId;
-            readVector(data, sessionId);
-            String8 algorithm = data.readString8();
-            reply->writeInt32(setMacAlgorithm(sessionId, algorithm));
-            return OK;
-        }
-
-        case ENCRYPT:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, keyId, input, iv, output;
-            readVector(data, sessionId);
-            readVector(data, keyId);
-            readVector(data, input);
-            readVector(data, iv);
-            uint32_t result = encrypt(sessionId, keyId, input, iv, output);
-            writeVector(reply, output);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case DECRYPT:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, keyId, input, iv, output;
-            readVector(data, sessionId);
-            readVector(data, keyId);
-            readVector(data, input);
-            readVector(data, iv);
-            uint32_t result = decrypt(sessionId, keyId, input, iv, output);
-            writeVector(reply, output);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case SIGN:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, keyId, message, signature;
-            readVector(data, sessionId);
-            readVector(data, keyId);
-            readVector(data, message);
-            uint32_t result = sign(sessionId, keyId, message, signature);
-            writeVector(reply, signature);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case VERIFY:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, keyId, message, signature;
-            readVector(data, sessionId);
-            readVector(data, keyId);
-            readVector(data, message);
-            readVector(data, signature);
-            bool match = false;
-            uint32_t result = verify(sessionId, keyId, message, signature, match);
-            reply->writeInt32(match);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-        case SIGN_RSA:
-        {
-            CHECK_INTERFACE(IDrm, data, reply);
-            Vector<uint8_t> sessionId, message, wrappedKey, signature;
-            readVector(data, sessionId);
-            String8 algorithm = data.readString8();
-            readVector(data, message);
-            readVector(data, wrappedKey);
-            uint32_t result = signRSA(sessionId, algorithm, message, wrappedKey, signature);
-            writeVector(reply, signature);
-            reply->writeInt32(result);
-            return OK;
-        }
-
-    case SET_LISTENER: {
-        CHECK_INTERFACE(IDrm, data, reply);
-        sp<IDrmClient> listener =
-            interface_cast<IDrmClient>(data.readStrongBinder());
-        reply->writeInt32(setListener(listener));
-        return NO_ERROR;
-    } break;
-
-    default:
-        return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}  // namespace android
diff --git a/drm/libmediadrm/IDrmClient.cpp b/drm/libmediadrm/IDrmClient.cpp
deleted file mode 100644
index 357de9d..0000000
--- a/drm/libmediadrm/IDrmClient.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-**
-** Copyright 2013, 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 "IDrmClient"
-#include <utils/Log.h>
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IMediaPlayerClient.h>
-#include <mediadrm/IDrmClient.h>
-
-namespace android {
-
-enum {
-    NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-class BpDrmClient: public BpInterface<IDrmClient>
-{
-public:
-    explicit BpDrmClient(const sp<IBinder>& impl)
-        : BpInterface<IDrmClient>(impl)
-    {
-    }
-
-    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IDrmClient::getInterfaceDescriptor());
-        data.writeInt32((int)eventType);
-        data.writeInt32(extra);
-        if (obj && obj->dataSize() > 0) {
-            data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
-        }
-        remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(DrmClient, "android.media.IDrmClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnDrmClient::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-        case NOTIFY: {
-            CHECK_INTERFACE(IDrmClient, data, reply);
-            int eventType = data.readInt32();
-            int extra = data.readInt32();
-            Parcel obj;
-            if (data.dataAvail() > 0) {
-                obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
-            }
-
-            notify((DrmPlugin::EventType)eventType, extra, &obj);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-} // namespace android
diff --git a/drm/libmediadrm/IMediaDrmService.cpp b/drm/libmediadrm/IMediaDrmService.cpp
deleted file mode 100644
index f320d0b..0000000
--- a/drm/libmediadrm/IMediaDrmService.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-#include <binder/IMemory.h>
-#include <mediadrm/ICrypto.h>
-#include <mediadrm/IDrm.h>
-#include <mediadrm/IMediaDrmService.h>
-
-#include <utils/Errors.h>  // for status_t
-#include <utils/String8.h>
-
-namespace android {
-
-enum {
-    MAKE_CRYPTO = IBinder::FIRST_CALL_TRANSACTION,
-    MAKE_DRM,
-};
-
-class BpMediaDrmService: public BpInterface<IMediaDrmService>
-{
-public:
-    explicit BpMediaDrmService(const sp<IBinder>& impl)
-        : BpInterface<IMediaDrmService>(impl)
-    {
-    }
-
-    virtual sp<ICrypto> makeCrypto() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
-        remote()->transact(MAKE_CRYPTO, data, &reply);
-        return interface_cast<ICrypto>(reply.readStrongBinder());
-    }
-
-    virtual sp<IDrm> makeDrm() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IMediaDrmService::getInterfaceDescriptor());
-        remote()->transact(MAKE_DRM, data, &reply);
-        return interface_cast<IDrm>(reply.readStrongBinder());
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(MediaDrmService, "android.media.IMediaDrmService");
-
-// ----------------------------------------------------------------------
-
-status_t BnMediaDrmService::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch (code) {
-        case MAKE_CRYPTO: {
-            CHECK_INTERFACE(IMediaDrmService, data, reply);
-            sp<ICrypto> crypto = makeCrypto();
-            reply->writeStrongBinder(IInterface::asBinder(crypto));
-            return NO_ERROR;
-        } break;
-        case MAKE_DRM: {
-            CHECK_INTERFACE(IMediaDrmService, data, reply);
-            sp<IDrm> drm = makeDrm();
-            reply->writeStrongBinder(IInterface::asBinder(drm));
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-} // namespace android
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 8cd6f96..b0abf83 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -21,7 +21,7 @@
 
 #include <inttypes.h>
 
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetrics.h>
 #include <utils/Log.h>
 
 
@@ -33,20 +33,18 @@
 
 status_t reportVendorMetrics(const std::string& metrics,
                              const String8& name,
-                             const String8& appPackageName) {
-    std::unique_ptr<MediaAnalyticsItem> analyticsItem(MediaAnalyticsItem::create(name.c_str()));
-    analyticsItem->generateSessionID();
-
-    std::string app_package_name(appPackageName.c_str(), appPackageName.size());
-    analyticsItem->setPkgName(app_package_name);
+                             uid_t appUid) {
+    mediametrics_handle_t analyticsItem(mediametrics_create(name.c_str()));
+    mediametrics_setUid(analyticsItem, appUid);
     if (metrics.size() > 0) {
-        analyticsItem->setCString(kSerializedMetricsField, metrics.c_str());
+        mediametrics_setCString(analyticsItem, kSerializedMetricsField, metrics.c_str());
     }
 
-    if (!analyticsItem->selfrecord()) {
-      ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem->getSessionID());
+    if (!mediametrics_selfRecord(analyticsItem)) {
+      ALOGE("%s: selfrecord() returned false", __func__);
     }
 
+    mediametrics_delete(analyticsItem);
     return OK;
 }
 
@@ -69,13 +67,13 @@
 status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
                                 const String8& vendor,
                                 const String8& description,
-                                const String8& appPackageName) {
+                                uid_t appUid) {
 
     String8 name = String8::format("drm.vendor.%s.%s",
                                    sanitize(vendor).c_str(),
                                    sanitize(description).c_str());
 
-    return reportVendorMetrics(b64EncodedMetrics, name, appPackageName);
+    return reportVendorMetrics(b64EncodedMetrics, name, appUid);
 }
 
 }  // namespace android
diff --git a/drm/libmediadrm/TEST_MAPPING b/drm/libmediadrm/TEST_MAPPING
new file mode 100644
index 0000000..bc15879
--- /dev/null
+++ b/drm/libmediadrm/TEST_MAPPING
@@ -0,0 +1,26 @@
+{
+  "presubmit": [
+    {
+      "name": "GtsMediaTestCases",
+      "options" : [
+        {
+	  "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+        },
+        {
+          "include-filter": "com.google.android.media.gts.MediaDrmTest"
+        },
+        {
+          "include-filter": "com.google.android.media.gts.WidevineDashPolicyTests"
+        }
+      ]
+    }
+  ],
+  "imports": [
+    {
+      "path": "frameworks/av/drm/mediadrm/plugins"
+    }
+  ]
+}
diff --git a/drm/libmediadrm/include/mediadrm/BundleDrmMetricsConsumer.h b/drm/libmediadrm/include/mediadrm/BundleDrmMetricsConsumer.h
new file mode 100644
index 0000000..1bcb352
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/BundleDrmMetricsConsumer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/PersistableBundle.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
+#include <utils/Errors.h>
+
+#ifndef ANDROID_BUNDLEMETRICSCONSUMER_H_
+
+#define ANDROID_BUNDLEMETRICSCONSUMER_H_
+
+namespace android {
+
+/**
+ * IDrmMetricsConsumer which saves IDrm/ICrypto metrics into a PersistableBundle.
+ *
+ * Example usage:
+ *
+ *   PersistableBundle bundle;
+ *   BundleDrmMetricsConsumer consumer(&bundle);
+ *   drm->exportMetrics(&consumer);
+ *   crypto->exportMetrics(&consumer);
+ *   // bundle now contains metrics from drm/crypto.
+ *
+ */
+struct BundleDrmMetricsConsumer : public IDrmMetricsConsumer {
+    BundleDrmMetricsConsumer(os::PersistableBundle*) {}
+
+    status_t consumeFrameworkMetrics(const MediaDrmMetrics &) override {
+        return OK;
+    }
+
+    status_t consumeHidlMetrics(
+            const String8 &/*vendor*/,
+            const hidl_vec<DrmMetricGroup> &/*pluginMetrics*/) override {
+        return OK;
+    }
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(BundleDrmMetricsConsumer);
+};
+
+}  // namespace android
+
+#endif // ANDROID_BUNDLEMETRICSCONSUMER_H_
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
index 73c029f..c9fda67 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHal.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -31,12 +31,15 @@
 using drm::V1_0::ICryptoFactory;
 using drm::V1_0::ICryptoPlugin;
 using drm::V1_0::SharedBuffer;
+using drm::V1_0::DestinationBuffer;
+
+using ::android::hardware::HidlMemory;
 
 class IMemoryHeap;
 
 namespace android {
 
-struct CryptoHal : public BnCrypto {
+struct CryptoHal : public ICrypto {
     CryptoHal();
     virtual ~CryptoHal();
 
@@ -58,12 +61,12 @@
 
     virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
             CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const ICrypto::SourceBuffer &source, size_t offset,
+            const ::SharedBuffer &source, size_t offset,
             const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
-            const ICrypto::DestinationBuffer &destination,
+            const ::DestinationBuffer &destination,
             AString *errorDetailMsg);
 
-    virtual int32_t setHeap(const sp<IMemoryHeap>& heap) {
+    virtual int32_t setHeap(const sp<HidlMemory>& heap) {
         return setHeapBase(heap);
     }
     virtual void unsetHeap(int32_t seqNum) { clearHeapBase(seqNum); }
@@ -83,31 +86,17 @@
      */
     status_t mInitCheck;
 
-    struct HeapBase {
-        HeapBase() : mBufferId(0), mSize(0) {}
-        HeapBase(uint32_t bufferId, size_t size) :
-            mBufferId(bufferId), mSize(size) {}
-
-        uint32_t getBufferId() const {return mBufferId;}
-        size_t getSize() const {return mSize;}
-
-    private:
-        uint32_t mBufferId;
-        size_t mSize;
-    };
-
-    KeyedVector<int32_t, HeapBase> mHeapBases;
-    uint32_t mNextBufferId;
+    KeyedVector<int32_t, size_t> mHeapSizes;
     int32_t mHeapSeqNum;
 
     Vector<sp<ICryptoFactory>> makeCryptoFactories();
     sp<ICryptoPlugin> makeCryptoPlugin(const sp<ICryptoFactory>& factory,
             const uint8_t uuid[16], const void *initData, size_t size);
 
-    int32_t setHeapBase(const sp<IMemoryHeap>& heap);
+    int32_t setHeapBase(const sp<HidlMemory>& heap);
     void clearHeapBase(int32_t seqNum);
 
-    status_t toSharedBuffer(const sp<IMemory>& memory, int32_t seqNum, ::SharedBuffer* buffer);
+    status_t checkSharedBuffer(const ::SharedBuffer& buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(CryptoHal);
 };
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index bdf1b30..f261d89 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -26,8 +26,8 @@
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
 #include <android/hardware/drm/1.2/IDrmPluginListener.h>
 
-#include <media/MediaAnalyticsItem.h>
 #include <mediadrm/DrmMetrics.h>
+#include <mediadrm/DrmSessionManager.h>
 #include <mediadrm/IDrm.h>
 #include <mediadrm/IDrmClient.h>
 #include <utils/threads.h>
@@ -56,9 +56,11 @@
     return memcmp(l.array(), r.array(), l.size()) == 0;
 }
 
-struct DrmHal : public BnDrm,
-                public IBinder::DeathRecipient,
+struct DrmHal : public IDrm,
                 public IDrmPluginListener_V1_2 {
+
+    struct DrmSessionClient;
+
     DrmHal();
     virtual ~DrmHal();
 
@@ -188,13 +190,9 @@
 
     Return<void> sendSessionLostState(const hidl_vec<uint8_t>& sessionId);
 
-    virtual void binderDied(const wp<IBinder> &the_late_who);
-
 private:
     static Mutex mLock;
 
-    sp<DrmSessionClientInterface> mDrmSessionClient;
-
     sp<IDrmClient> mListener;
     mutable Mutex mEventLock;
     mutable Mutex mNotifyLock;
@@ -208,7 +206,7 @@
     // Mutable to allow modification within GetPropertyByteArray.
     mutable MediaDrmMetrics mMetrics;
 
-    Vector<Vector<uint8_t>> mOpenSessions;
+    std::vector<std::shared_ptr<DrmSessionClient>> mOpenSessions;
     void closeOpenSessions();
     void cleanup();
 
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetrics.h b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
index 6f132bf..833ffa4 100644
--- a/drm/libmediadrm/include/mediadrm/DrmMetrics.h
+++ b/drm/libmediadrm/include/mediadrm/DrmMetrics.h
@@ -25,6 +25,7 @@
 #include <binder/PersistableBundle.h>
 #include <media/CounterMetric.h>
 #include <media/EventMetric.h>
+#include <sys/types.h>
 
 namespace android {
 
@@ -71,6 +72,9 @@
   void SetAppPackageName(const String8& appPackageName) { mAppPackageName = appPackageName; }
   const String8& GetAppPackageName() { return mAppPackageName; }
 
+  void SetAppUid(uid_t appUid) { mAppUid = appUid; }
+  uid_t GetAppUid() const { return mAppUid; }
+
   // Export the metrics to a PersistableBundle.
   void Export(os::PersistableBundle* metricsBundle);
 
@@ -131,6 +135,7 @@
   std::map<std::string, std::pair<int64_t, int64_t>> mSessionLifespans;
 
   String8 mAppPackageName;
+  uid_t mAppUid{~0u};
 };
 
 }  // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index ba27199..9e43504 100644
--- a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -18,56 +18,68 @@
 
 #define DRM_SESSION_MANAGER_H_
 
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/IResourceManagerService.h>
+#include <android/binder_auto_utils.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
 #include <utils/Vector.h>
 
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
 namespace android {
 
 class DrmSessionManagerTest;
-struct DrmSessionClientInterface;
-struct ProcessInfoInterface;
+
+using aidl::android::media::IResourceManagerClient;
+using aidl::android::media::IResourceManagerService;
 
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
 
 struct SessionInfo {
-    sp<DrmSessionClientInterface> drm;
-    Vector<uint8_t> sessionId;
-    int64_t timeStamp;
+    pid_t pid;
+    uid_t uid;
+    int64_t clientId;
 };
 
-typedef Vector<SessionInfo > SessionInfos;
-typedef KeyedVector<int, SessionInfos > PidSessionInfosMap;
+typedef std::map<std::vector<uint8_t>, SessionInfo> SessionInfoMap;
 
 struct DrmSessionManager : public RefBase {
     static sp<DrmSessionManager> Instance();
 
     DrmSessionManager();
-    explicit DrmSessionManager(sp<ProcessInfoInterface> processInfo);
+    explicit DrmSessionManager(const std::shared_ptr<IResourceManagerService> &service);
 
-    void addSession(int pid, const sp<DrmSessionClientInterface>& drm, const Vector<uint8_t>& sessionId);
+    void addSession(int pid,
+            const std::shared_ptr<IResourceManagerClient>& drm,
+            const Vector<uint8_t>& sessionId);
     void useSession(const Vector<uint8_t>& sessionId);
     void removeSession(const Vector<uint8_t>& sessionId);
-    void removeDrm(const sp<DrmSessionClientInterface>& drm);
     bool reclaimSession(int callingPid);
 
+    // sanity check APIs
+    size_t getSessionCount() const;
+    bool containsSession(const Vector<uint8_t>& sessionId) const;
+
+    // implements DeathRecipient
+    void binderDied();
+
 protected:
     virtual ~DrmSessionManager();
 
 private:
-    friend class DrmSessionManagerTest;
+    void init();
 
-    int64_t getTime_l();
-    bool getLowestPriority_l(int* lowestPriorityPid, int* lowestPriority);
-    bool getLeastUsedSession_l(
-            int pid, sp<DrmSessionClientInterface>* drm, Vector<uint8_t>* sessionId);
-
-    sp<ProcessInfoInterface> mProcessInfo;
+    std::shared_ptr<IResourceManagerService> mService;
     mutable Mutex mLock;
-    PidSessionInfosMap mSessionMap;
-    int64_t mTime;
+    SessionInfoMap mSessionMap;
+    bool mInitialized;
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
 
     DISALLOW_EVIL_CONSTRUCTORS(DrmSessionManager);
 };
diff --git a/drm/libmediadrm/include/mediadrm/IDrm.h b/drm/libmediadrm/include/mediadrm/IDrm.h
index fbe80c6..4103d5d 100644
--- a/drm/libmediadrm/include/mediadrm/IDrm.h
+++ b/drm/libmediadrm/include/mediadrm/IDrm.h
@@ -18,7 +18,6 @@
 #include <binder/PersistableBundle.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/drm/DrmAPI.h>
-#include <media/MediaAnalyticsItem.h>
 #include <mediadrm/IDrmClient.h>
 
 #ifndef ANDROID_IDRM_H_
@@ -29,8 +28,9 @@
 
 struct AString;
 
-struct IDrm : public IInterface {
-    DECLARE_META_INTERFACE(Drm);
+struct IDrm : public virtual RefBase {
+
+    virtual ~IDrm() {}
 
     virtual status_t initCheck() const = 0;
 
@@ -146,19 +146,13 @@
 
     virtual status_t setListener(const sp<IDrmClient>& listener) = 0;
 
+protected:
+    IDrm() {}
+
 private:
     DISALLOW_EVIL_CONSTRUCTORS(IDrm);
 };
 
-struct BnDrm : public BnInterface<IDrm> {
-    virtual status_t onTransact(
-            uint32_t code, const Parcel &data, Parcel *reply,
-            uint32_t flags = 0);
-private:
-    void readVector(const Parcel &data, Vector<uint8_t> &vector) const;
-    void writeVector(Parcel *reply, Vector<uint8_t> const &vector) const;
-};
-
 }  // namespace android
 
 #endif // ANDROID_IDRM_H_
diff --git a/drm/libmediadrm/include/mediadrm/IDrmClient.h b/drm/libmediadrm/include/mediadrm/IDrmClient.h
index 3b2fc7c..fe25ae1 100644
--- a/drm/libmediadrm/include/mediadrm/IDrmClient.h
+++ b/drm/libmediadrm/include/mediadrm/IDrmClient.h
@@ -18,29 +18,46 @@
 #define ANDROID_IDRMCLIENT_H
 
 #include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
+#include <hidl/HidlSupport.h>
 #include <media/drm/DrmAPI.h>
 
+#include <cstdint>
+#include <vector>
+
 namespace android {
 
-class IDrmClient: public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(DrmClient);
-
-    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) = 0;
+struct DrmKeyStatus {
+    const uint32_t type;
+    const hardware::hidl_vec<uint8_t> keyId;
 };
 
-// ----------------------------------------------------------------------------
-
-class BnDrmClient: public BnInterface<IDrmClient>
+class IDrmClient: public virtual RefBase
 {
 public:
-    virtual status_t onTransact(uint32_t code,
-                                const Parcel& data,
-                                Parcel* reply,
-                                uint32_t flags = 0);
+    ~IDrmClient() {}
+
+    virtual void sendEvent(
+            DrmPlugin::EventType eventType,
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const hardware::hidl_vec<uint8_t> &data) = 0;
+
+    virtual void sendExpirationUpdate(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            int64_t expiryTimeInMS) = 0;
+
+    virtual void sendKeysChange(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const std::vector<DrmKeyStatus> &keyStatusList,
+            bool hasNewUsableKey) = 0;
+
+    virtual void sendSessionLostState(
+            const hardware::hidl_vec<uint8_t> &sessionId) = 0;
+
+protected:
+    IDrmClient() {}
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(IDrmClient);
 };
 
 }; // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h b/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h
new file mode 100644
index 0000000..efa61d8
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/IDrmMetricsConsumer.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/drm/1.1/types.h>
+#include <hidl/HidlSupport.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#ifndef ANDROID_IDRMMETRICSCONSUMER_H_
+
+#define ANDROID_IDRMMETRICSCONSUMER_H_
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+
+namespace android {
+
+class MediaDrmMetrics;
+class String8;
+
+/**
+ * Interface to consume metrics produced by the IDrm/ICrypto
+ *
+ * To use with IDrm:
+ *   drm->exportMetrics(&consumer);
+ *
+ * IDrmMetricsConsumer::consumeFrameworkMetrics &
+ * IDrmMetricsConsumer::consumeHidlMetrics implementations
+ * would each be invoked once per call to IDrm::exportMetrics.
+ * |consumeFrameworkMetrics| would be called for plugin-agnostic
+ * framework metrics; |consumeHidlMetrics| would be called for
+ * plugin specific metrics.
+ *
+ * ----------------------------------------
+ *
+ * To use with ICrypto:
+ *   crypto->exportMetrics(&consumer);
+ *
+ * IDrmMetricsConsumer::consumeHidlMetrics implementation
+ * would each be invoked once per call to ICrypto::exportMetrics.
+ * ICrypto metrics are plugin agnostic.
+ *
+ * ----------------------------------------
+ *
+ * For an example implementation of IDrmMetricsConsumer, please
+ * see BundleDrmMetricsConsumer. BundleDrmMetricsConsumer consumes
+ * IDrm/ICrypto metrics and saves the metrics to a PersistableBundle.
+ *
+ */
+struct IDrmMetricsConsumer : public RefBase {
+
+    virtual ~IDrmMetricsConsumer() {}
+
+    /**
+     * Consume framework (plugin agnostic) MediaDrmMetrics
+     */
+    virtual status_t consumeFrameworkMetrics(const MediaDrmMetrics &) = 0;
+
+    /**
+     * Consume list of DrmMetricGroup with optional Drm vendor name
+     */
+    virtual status_t consumeHidlMetrics(
+            const String8 &vendor,
+            const hidl_vec<DrmMetricGroup> &pluginMetrics) = 0;
+
+protected:
+    IDrmMetricsConsumer() {}
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(IDrmMetricsConsumer);
+};
+
+}  // namespace android
+
+#endif // ANDROID_IDRMMETRICSCONSUMER_H_
diff --git a/drm/libmediadrm/include/mediadrm/IMediaDrmService.h b/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
deleted file mode 100644
index 323fae5..0000000
--- a/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IMEDIADRMSERVICE_H
-#define ANDROID_IMEDIADRMSERVICE_H
-
-#include <utils/Errors.h>  // for status_t
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-struct ICrypto;
-struct IDrm;
-
-class IMediaDrmService: public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(MediaDrmService);
-
-    virtual sp<ICrypto>         makeCrypto() = 0;
-    virtual sp<IDrm>            makeDrm() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnMediaDrmService: public BnInterface<IMediaDrmService>
-{
-public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IMEDIADRMSERVICE_H
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
new file mode 100644
index 0000000..3017274
--- /dev/null
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DRMUTILS_H
+#define ANDROID_DRMUTILS_H
+
+#include <android/hardware/drm/1.0/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/IDrmFactory.h>
+#include <utils/Errors.h>  // for status_t
+#include <utils/StrongPointer.h>
+#include <binder/Parcel.h>
+#include <vector>
+
+using namespace ::android::hardware::drm;
+
+namespace android {
+
+struct ICrypto;
+struct IDrm;
+
+namespace DrmUtils {
+
+bool UseDrmService();
+
+sp<IDrm> MakeDrm(status_t *pstatus = nullptr);
+
+sp<ICrypto> MakeCrypto(status_t *pstatus = nullptr);
+
+template<typename BA>
+void WriteByteArray(Parcel &obj, const BA &vec) {
+    obj.writeInt32(vec.size());
+    if (vec.size()) {
+        obj.write(vec.data(), vec.size());
+    }
+}
+
+template<typename ET, typename BA>
+void WriteEventToParcel(
+        Parcel &obj,
+        ET eventType,
+        const BA &sessionId,
+        const BA &data) {
+    WriteByteArray(obj, sessionId);
+    WriteByteArray(obj, data);
+    obj.writeInt32(eventType);
+}
+
+template<typename BA>
+void WriteExpirationUpdateToParcel(
+        Parcel &obj,
+        const BA &sessionId,
+        int64_t expiryTimeInMS) {
+    WriteByteArray(obj, sessionId);
+    obj.writeInt64(expiryTimeInMS);
+}
+
+template<typename BA, typename KSL>
+void WriteKeysChange(
+        Parcel &obj,
+        const BA &sessionId,
+        const KSL &keyStatusList,
+        bool hasNewUsableKey) {
+    WriteByteArray(obj, sessionId);
+    obj.writeInt32(keyStatusList.size());
+    for (const auto &keyStatus : keyStatusList) {
+        WriteByteArray(obj, keyStatus.keyId);
+        obj.writeInt32(keyStatus.type);
+    }
+    obj.writeInt32(hasNewUsableKey);
+}
+
+std::vector<sp<::V1_0::IDrmFactory>> MakeDrmFactories(const uint8_t uuid[16]);
+
+std::vector<sp<::V1_0::IDrmPlugin>> MakeDrmPlugins(const uint8_t uuid[16],
+                                                   const char *appPackageName);
+
+std::vector<sp<::V1_0::ICryptoFactory>> MakeCryptoFactories(const uint8_t uuid[16]);
+
+std::vector<sp<::V1_0::ICryptoPlugin>> MakeCryptoPlugins(const uint8_t uuid[16],
+                                                         const void *initData, size_t initDataSize);
+
+} // namespace DrmUtils
+
+} // namespace android
+
+#endif // ANDROID_DRMUTILS_H
diff --git a/drm/libmediadrm/interface/mediadrm/ICrypto.h b/drm/libmediadrm/interface/mediadrm/ICrypto.h
index 6d896b8..df980ae 100644
--- a/drm/libmediadrm/interface/mediadrm/ICrypto.h
+++ b/drm/libmediadrm/interface/mediadrm/ICrypto.h
@@ -14,23 +14,38 @@
  * limitations under the License.
  */
 
-#include <binder/IInterface.h>
 #include <cutils/native_handle.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
 
 #ifndef ANDROID_ICRYPTO_H_
 
 #define ANDROID_ICRYPTO_H_
 
 namespace android {
+namespace hardware {
+class HidlMemory;
+namespace drm {
+namespace V1_0 {
+struct SharedBuffer;
+struct DestinationBuffer;
+}  // namespace V1_0
+}  // namespace drm
+}  // namespace hardware
+}  // namespace android
+
+namespace drm = ::android::hardware::drm;
+using drm::V1_0::SharedBuffer;
+
+namespace android {
 
 struct AString;
-class IMemory;
-class IMemoryHeap;
 
-struct ICrypto : public IInterface {
-    DECLARE_META_INTERFACE(Crypto);
+struct ICrypto : public RefBase {
+
+    virtual ~ICrypto() {}
 
     virtual status_t initCheck() const = 0;
 
@@ -48,27 +63,16 @@
 
     virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
 
-    struct SourceBuffer {
-        sp<IMemory> mSharedMemory;
-        int32_t mHeapSeqNum;
-    };
-
     enum DestinationType {
         kDestinationTypeSharedMemory, // non-secure
         kDestinationTypeNativeHandle  // secure
     };
 
-    struct DestinationBuffer {
-        DestinationType mType;
-        native_handle_t *mHandle;
-        sp<IMemory> mSharedMemory;
-    };
-
-    virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
-            CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
-            const SourceBuffer &source, size_t offset,
-            const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
-            const DestinationBuffer &destination, AString *errorDetailMsg) = 0;
+    virtual ssize_t decrypt(const uint8_t /*key*/[16], const uint8_t /*iv*/[16],
+            CryptoPlugin::Mode /*mode*/, const CryptoPlugin::Pattern &/*pattern*/,
+            const drm::V1_0::SharedBuffer &/*source*/, size_t /*offset*/,
+            const CryptoPlugin::SubSample * /*subSamples*/, size_t /*numSubSamples*/,
+            const drm::V1_0::DestinationBuffer &/*destination*/, AString * /*errorDetailMsg*/) = 0;
 
     /**
      * Declare the heap that the shared memory source buffers passed
@@ -76,22 +80,16 @@
      * that subsequent decrypt calls can use to refer to the heap,
      * with -1 indicating failure.
      */
-    virtual int32_t setHeap(const sp<IMemoryHeap>& heap) = 0;
+    virtual int32_t setHeap(const sp<hardware::HidlMemory>& heap) = 0;
     virtual void unsetHeap(int32_t seqNum) = 0;
 
+protected:
+    ICrypto() {}
+
 private:
     DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
 };
 
-struct BnCrypto : public BnInterface<ICrypto> {
-    virtual status_t onTransact(
-            uint32_t code, const Parcel &data, Parcel *reply,
-            uint32_t flags = 0);
-private:
-    void readVector(const Parcel &data, Vector<uint8_t> &vector) const;
-    void writeVector(Parcel *reply, Vector<uint8_t> const &vector) const;
-};
-
 }  // namespace android
 
 #endif // ANDROID_ICRYPTO_H_
diff --git a/drm/mediadrm/plugins/TEST_MAPPING b/drm/mediadrm/plugins/TEST_MAPPING
new file mode 100644
index 0000000..7bd1568
--- /dev/null
+++ b/drm/mediadrm/plugins/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsMediaTestCases",
+      "options" : [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "include-filter": "android.media.cts.MediaDrmClearkeyTest"
+        },
+        {
+          "include-filter": "android.media.cts.MediaDrmMetricsTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
index caff393..121a4e2 100644
--- a/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/default/InitDataParser.cpp
@@ -76,10 +76,21 @@
 
 android::status_t InitDataParser::parsePssh(const Vector<uint8_t>& initData,
         Vector<const uint8_t*>* keyIds) {
+    // Description of PSSH format:
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
     size_t readPosition = 0;
 
-    // Validate size field
     uint32_t expectedSize = initData.size();
+    const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+    const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+    uint32_t keyIdCount = 0;
+    size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) +
+                        sizeof(psshVersion1) + kSystemIdSize + sizeof(keyIdCount);
+    if (initData.size() < headerSize) {
+        return android::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    // Validate size field
     expectedSize = htonl(expectedSize);
     if (memcmp(&initData[readPosition], &expectedSize,
                sizeof(expectedSize)) != 0) {
@@ -88,7 +99,6 @@
     readPosition += sizeof(expectedSize);
 
     // Validate PSSH box identifier
-    const char psshIdentifier[4] = {'p', 's', 's', 'h'};
     if (memcmp(&initData[readPosition], psshIdentifier,
                sizeof(psshIdentifier)) != 0) {
         return android::ERROR_DRM_CANNOT_HANDLE;
@@ -96,7 +106,6 @@
     readPosition += sizeof(psshIdentifier);
 
     // Validate EME version number
-    const uint8_t psshVersion1[4] = {1, 0, 0, 0};
     if (memcmp(&initData[readPosition], psshVersion1,
                sizeof(psshVersion1)) != 0) {
         return android::ERROR_DRM_CANNOT_HANDLE;
@@ -110,12 +119,14 @@
     readPosition += kSystemIdSize;
 
     // Read key ID count
-    uint32_t keyIdCount;
     memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
     keyIdCount = ntohl(keyIdCount);
     readPosition += sizeof(keyIdCount);
-    if (readPosition + ((uint64_t)keyIdCount * kKeyIdSize) !=
-            initData.size() - sizeof(uint32_t)) {
+
+    uint64_t psshSize = 0;
+    if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+        __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+        psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
         return android::ERROR_DRM_CANNOT_HANDLE;
     }
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index d74bc53..942ea7d 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -111,6 +111,8 @@
 // The content in this secure stop is implementation dependent, the clearkey
 // secureStop does not serve as a reference implementation.
 void DrmPlugin::installSecureStop(const hidl_vec<uint8_t>& sessionId) {
+    Mutex::Autolock lock(mSecureStopLock);
+
     ClearkeySecureStop clearkeySecureStop;
     clearkeySecureStop.id = uint32ToVector(++mNextSecureStopId);
     clearkeySecureStop.data.assign(sessionId.begin(), sessionId.end());
@@ -744,6 +746,7 @@
 }
 
 Return<void> DrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) {
+    mSecureStopLock.lock();
     std::vector<SecureStop> stops;
     for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
         ClearkeySecureStop clearkeyStop = itr->second;
@@ -755,26 +758,32 @@
         stop.opaqueData = toHidlVec(stopVec);
         stops.push_back(stop);
     }
+    mSecureStopLock.unlock();
+
     _hidl_cb(Status::OK, stops);
     return Void();
 }
 
 Return<void> DrmPlugin::getSecureStop(const hidl_vec<uint8_t>& secureStopId,
         getSecureStop_cb _hidl_cb) {
-    SecureStop stop;
+    std::vector<uint8_t> stopVec;
+
+    mSecureStopLock.lock();
     auto itr = mSecureStops.find(toVector(secureStopId));
     if (itr != mSecureStops.end()) {
         ClearkeySecureStop clearkeyStop = itr->second;
-        std::vector<uint8_t> stopVec;
         stopVec.insert(stopVec.end(), clearkeyStop.id.begin(), clearkeyStop.id.end());
         stopVec.insert(stopVec.end(), clearkeyStop.data.begin(), clearkeyStop.data.end());
+    }
+    mSecureStopLock.unlock();
 
+    SecureStop stop;
+    if (!stopVec.empty()) {
         stop.opaqueData = toHidlVec(stopVec);
         _hidl_cb(Status::OK, stop);
     } else {
         _hidl_cb(Status::BAD_VALUE, stop);
     }
-
     return Void();
 }
 
@@ -787,51 +796,73 @@
 }
 
 Return<void> DrmPlugin::getSecureStopIds(getSecureStopIds_cb _hidl_cb) {
+    mSecureStopLock.lock();
     std::vector<SecureStopId> ids;
     for (auto itr = mSecureStops.begin(); itr != mSecureStops.end(); ++itr) {
         ids.push_back(itr->first);
     }
+    mSecureStopLock.unlock();
 
     _hidl_cb(Status::OK, toHidlVec(ids));
     return Void();
 }
 
 Return<Status> DrmPlugin::releaseSecureStops(const SecureStopRelease& ssRelease) {
-    if (ssRelease.opaqueData.size() == 0) {
+    // OpaqueData starts with 4 byte decimal integer string
+    const size_t kFourBytesOffset = 4;
+    if (ssRelease.opaqueData.size() < kFourBytesOffset) {
+        ALOGE("Invalid secureStopRelease length");
         return Status::BAD_VALUE;
     }
 
     Status status = Status::OK;
     std::vector<uint8_t> input = toVector(ssRelease.opaqueData);
 
+    if (input.size() < kSecureStopIdSize + kFourBytesOffset) {
+        // The minimum size of SecureStopRelease has to contain
+        // a 4 bytes count and one secureStop id
+        ALOGE("Total size of secureStops is too short");
+        return Status::BAD_VALUE;
+    }
+
     // The format of opaqueData is shared between the server
     // and the drm service. The clearkey implementation consists of:
     //    count - number of secure stops
     //    list of fixed length secure stops
-    size_t countBufferSize = sizeof(uint32_t);
     uint32_t count = 0;
     sscanf(reinterpret_cast<char*>(input.data()), "%04" PRIu32, &count);
 
     // Avoid divide by 0 below.
     if (count == 0) {
+        ALOGE("Invalid 0 secureStop count");
         return Status::BAD_VALUE;
     }
 
-    size_t secureStopSize = (input.size() - countBufferSize) / count;
-    uint8_t buffer[secureStopSize];
-    size_t offset = countBufferSize; // skip the count
+    // Computes the fixed length secureStop size
+    size_t secureStopSize = (input.size() - kFourBytesOffset) / count;
+    if (secureStopSize < kSecureStopIdSize) {
+        // A valid secureStop contains the id plus data
+        ALOGE("Invalid secureStop size");
+        return Status::BAD_VALUE;
+    }
+    uint8_t* buffer = new uint8_t[secureStopSize];
+    size_t offset = kFourBytesOffset; // skip the count
     for (size_t i = 0; i < count; ++i, offset += secureStopSize) {
         memcpy(buffer, input.data() + offset, secureStopSize);
-        std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
 
+        // A secureStop contains id+data, we only use the id for removal
+        std::vector<uint8_t> id(buffer, buffer + kSecureStopIdSize);
         status = removeSecureStop(toHidlVec(id));
         if (Status::OK != status) break;
     }
 
+    delete[] buffer;
     return status;
 }
 
 Return<Status> DrmPlugin::removeSecureStop(const hidl_vec<uint8_t>& secureStopId) {
+    Mutex::Autolock lock(mSecureStopLock);
+
     if (1 != mSecureStops.erase(toVector(secureStopId))) {
         return Status::BAD_VALUE;
     }
@@ -839,6 +870,8 @@
 }
 
 Return<Status> DrmPlugin::removeAllSecureStops() {
+    Mutex::Autolock lock(mSecureStopLock);
+
     mSecureStops.clear();
     mNextSecureStopId = kSecureStopIdStart;
     return Status::OK;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
index b988ce0..8513434 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/InitDataParser.cpp
@@ -85,10 +85,21 @@
 
 Status InitDataParser::parsePssh(const std::vector<uint8_t>& initData,
         std::vector<const uint8_t*>* keyIds) {
+    // Description of PSSH format:
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html
     size_t readPosition = 0;
 
-    // Validate size field
     uint32_t expectedSize = initData.size();
+    const char psshIdentifier[4] = {'p', 's', 's', 'h'};
+    const uint8_t psshVersion1[4] = {1, 0, 0, 0};
+    uint32_t keyIdCount = 0;
+    size_t headerSize = sizeof(expectedSize) + sizeof(psshIdentifier) +
+                        sizeof(psshVersion1) + kSystemIdSize + sizeof(keyIdCount);
+    if (initData.size() < headerSize) {
+        return Status::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    // Validate size field
     expectedSize = htonl(expectedSize);
     if (memcmp(&initData[readPosition], &expectedSize,
                sizeof(expectedSize)) != 0) {
@@ -97,7 +108,6 @@
     readPosition += sizeof(expectedSize);
 
     // Validate PSSH box identifier
-    const char psshIdentifier[4] = {'p', 's', 's', 'h'};
     if (memcmp(&initData[readPosition], psshIdentifier,
                sizeof(psshIdentifier)) != 0) {
         return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -105,7 +115,6 @@
     readPosition += sizeof(psshIdentifier);
 
     // Validate EME version number
-    const uint8_t psshVersion1[4] = {1, 0, 0, 0};
     if (memcmp(&initData[readPosition], psshVersion1,
                sizeof(psshVersion1)) != 0) {
         return Status::ERROR_DRM_CANNOT_HANDLE;
@@ -119,12 +128,14 @@
     readPosition += kSystemIdSize;
 
     // Read key ID count
-    uint32_t keyIdCount;
     memcpy(&keyIdCount, &initData[readPosition], sizeof(keyIdCount));
     keyIdCount = ntohl(keyIdCount);
     readPosition += sizeof(keyIdCount);
-    if (readPosition + ((uint64_t)keyIdCount * kKeyIdSize) !=
-            initData.size() - sizeof(uint32_t)) {
+
+    uint64_t psshSize = 0;
+    if (__builtin_mul_overflow(keyIdCount, kKeyIdSize, &psshSize) ||
+        __builtin_add_overflow(readPosition, psshSize, &psshSize) ||
+        psshSize != initData.size() - sizeof(uint32_t) /* DataSize(0) */) {
         return Status::ERROR_DRM_CANNOT_HANDLE;
     }
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index f294d4d..3de7589 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -416,6 +416,7 @@
     }
 
     DeviceFiles mFileHandle;
+    Mutex mSecureStopLock;
 
     CLEARKEY_DISALLOW_COPY_AND_ASSIGN_AND_NEW(DrmPlugin);
 };
diff --git a/include/media/AudioResampler.h b/include/media/AudioResampler.h
deleted file mode 120000
index 771f1b8..0000000
--- a/include/media/AudioResampler.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioprocessing/include/media/AudioResampler.h
\ No newline at end of file
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1b1f149..8aec80d 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -575,7 +575,7 @@
 class AudioTrackServerProxy : public ServerProxy {
 public:
     AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
-            size_t frameSize, bool clientInServer = false, uint32_t sampleRate = 0)
+            size_t frameSize, bool clientInServer, uint32_t sampleRate)
         : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer),
           mPlaybackRateObserver(&cblk->mPlaybackRateQueue),
           mUnderrunCount(0), mUnderrunning(false), mDrained(true) {
@@ -651,7 +651,7 @@
 class StaticAudioTrackServerProxy : public AudioTrackServerProxy {
 public:
     StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount,
-            size_t frameSize);
+            size_t frameSize, uint32_t sampleRate);
 protected:
     virtual ~StaticAudioTrackServerProxy() { }
 
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 712f118..16e794a 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -41,7 +41,7 @@
             uint32_t angle, uint32_t bpp, bool hasData, size_t iccSize):
         mWidth(width), mHeight(height),
         mDisplayWidth(displayWidth), mDisplayHeight(displayHeight),
-        mTileWidth(tileWidth), mTileHeight(tileHeight),
+        mTileWidth(tileWidth), mTileHeight(tileHeight), mDurationUs(0),
         mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width),
         mSize(hasData ? (bpp * width * height) : 0),
         mIccSize(iccSize), mReserved(0) {
@@ -78,6 +78,7 @@
     uint32_t mDisplayHeight;   // Display height before rotation
     uint32_t mTileWidth;       // Tile width (0 if image doesn't have grid)
     uint32_t mTileHeight;      // Tile height (0 if image doesn't have grid)
+    int64_t  mDurationUs;      // Frame duration in microseconds
     int32_t  mRotationAngle;   // Rotation angle, clockwise, should be multiple of 90
     uint32_t mBytesPerPixel;   // Number of bytes per pixel
     uint32_t mRowBytes;        // Number of bytes per row before rotation
diff --git a/media/bufferpool/1.0/AccessorImpl.cpp b/media/bufferpool/1.0/AccessorImpl.cpp
index a5366f6..0d7e92f 100644
--- a/media/bufferpool/1.0/AccessorImpl.cpp
+++ b/media/bufferpool/1.0/AccessorImpl.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "BufferPoolAccessor"
+#define LOG_TAG "BufferPoolAccessor1.0"
 //#define LOG_NDEBUG 0
 
 #include <sys/types.h>
+#include <stdint.h>
 #include <time.h>
 #include <unistd.h>
 #include <utils/Log.h>
@@ -127,7 +128,6 @@
     return false;
 }
 
-int32_t Accessor::Impl::sPid = getpid();
 uint32_t Accessor::Impl::sSeqId = time(nullptr);
 
 Accessor::Impl::Impl(
@@ -145,14 +145,19 @@
     {
         std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
         if (newConnection) {
-            ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+            int32_t pid = getpid();
+            ConnectionId id = (int64_t)pid << 32 | sSeqId;
             status = mBufferPool.mObserver.open(id, fmqDescPtr);
             if (status == ResultStatus::OK) {
                 newConnection->initialize(accessor, id);
                 *connection = newConnection;
                 *pConnectionId = id;
                 mBufferPool.mConnectionIds.insert(id);
-                ++sSeqId;
+                if (sSeqId == UINT32_MAX) {
+                   sSeqId = 0;
+                } else {
+                    ++sSeqId;
+                }
             }
         }
         mBufferPool.processStatusMessages();
@@ -248,7 +253,7 @@
     ALOGD("Destruction - bufferpool %p "
           "cached: %zu/%zuM, %zu/%d%% in use; "
           "allocs: %zu, %d%% recycled; "
-          "transfers: %zu, %d%% unfetced",
+          "transfers: %zu, %d%% unfetched",
           this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
           mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
           mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
diff --git a/media/bufferpool/1.0/AccessorImpl.h b/media/bufferpool/1.0/AccessorImpl.h
index 84cb685..a09cbe2 100644
--- a/media/bufferpool/1.0/AccessorImpl.h
+++ b/media/bufferpool/1.0/AccessorImpl.h
@@ -61,7 +61,6 @@
     // ConnectionId = pid : (timestamp_created + seqId)
     // in order to guarantee uniqueness for each connection
     static uint32_t sSeqId;
-    static int32_t sPid;
 
     const std::shared_ptr<BufferPoolAllocator> mAllocator;
 
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 0d591d7..1947656 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "BufferPoolAccessor"
+#define LOG_TAG "BufferPoolAccessor2.0"
 //#define LOG_NDEBUG 0
 
 #include <sys/types.h>
+#include <stdint.h>
 #include <time.h>
 #include <unistd.h>
 #include <utils/Log.h>
@@ -134,7 +135,6 @@
     return false;
 }
 
-int32_t Accessor::Impl::sPid = getpid();
 uint32_t Accessor::Impl::sSeqId = time(nullptr);
 
 Accessor::Impl::Impl(
@@ -156,7 +156,8 @@
     {
         std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
         if (newConnection) {
-            ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+            int32_t pid = getpid();
+            ConnectionId id = (int64_t)pid << 32 | sSeqId;
             status = mBufferPool.mObserver.open(id, statusDescPtr);
             if (status == ResultStatus::OK) {
                 newConnection->initialize(accessor, id);
@@ -166,7 +167,11 @@
                 mBufferPool.mConnectionIds.insert(id);
                 mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
                 mBufferPool.mInvalidation.onConnect(id, observer);
-                ++sSeqId;
+                if (sSeqId == UINT32_MAX) {
+                   sSeqId = 0;
+                } else {
+                    ++sSeqId;
+                }
             }
 
         }
@@ -304,7 +309,7 @@
     ALOGD("Destruction - bufferpool2 %p "
           "cached: %zu/%zuM, %zu/%d%% in use; "
           "allocs: %zu, %d%% recycled; "
-          "transfers: %zu, %d%% unfetced",
+          "transfers: %zu, %d%% unfetched",
           this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
           mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
           mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index 807e0f1..9888be5 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -75,7 +75,6 @@
     // ConnectionId = pid : (timestamp_created + seqId)
     // in order to guarantee uniqueness for each connection
     static uint32_t sSeqId;
-    static int32_t sPid;
 
     const std::shared_ptr<BufferPoolAllocator> mAllocator;
 
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index 2d4e126..3568f7b 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -78,7 +78,8 @@
                 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
                 .withDefault(new C2StreamSampleRateInfo::output(0u, 44100))
                 .withFields({C2F(mSampleRate, value).oneOf({
-                    7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+                    7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+                    44100, 48000, 64000, 88200, 96000
                 })})
                 .withSetter(Setter<decltype(*mSampleRate)>::NonStrictValueWithNoDeps)
                 .build());
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index 36137e6..c7046cb 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -29,6 +29,8 @@
 
 namespace android {
 
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
+
 // codecname set and passed in as a compile flag from Android.bp
 constexpr char COMPONENT_NAME[] = CODECNAME;
 
@@ -112,7 +114,7 @@
         addParameter(
             DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
                 .withDefault(
-                    new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+                    new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
                 .withFields({
                     C2F(mMaxInputSize, value).any(),
                 })
@@ -192,8 +194,8 @@
         const C2P<C2StreamMaxPictureSizeTuning::output>& maxSize) {
         (void)mayBlock;
         // assume compression ratio of 2
-        me.set().value = (((maxSize.v.width + 63) / 64) *
-                          ((maxSize.v.height + 63) / 64) * 3072);
+        me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+                * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
         return C2R::Ok();
     }
     static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index fa98178..2662f0f 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -31,7 +31,7 @@
 namespace android {
 
 namespace {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
 constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
 constexpr uint32_t kDefaultOutputDelay = 8;
 constexpr uint32_t kMaxOutputDelay = 16;
@@ -114,7 +114,7 @@
 
         addParameter(
                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
-                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
                 .withFields({
                     C2F(mMaxInputSize, value).any(),
                 })
@@ -227,7 +227,8 @@
                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
         (void)mayBlock;
         // assume compression ratio of 2
-        me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 192);
+        me.set().value = c2_max((((maxSize.v.width + 15) / 16)
+                * ((maxSize.v.height + 15) / 16) * 192), kMinInputBufferSize);
         return C2R::Ok();
     }
 
diff --git a/media/codec2/components/flac/Android.bp b/media/codec2/components/flac/Android.bp
index e5eb51d..48cc51b 100644
--- a/media/codec2/components/flac/Android.bp
+++ b/media/codec2/components/flac/Android.bp
@@ -23,8 +23,11 @@
 
     srcs: ["C2SoftFlacEnc.cpp"],
 
-    static_libs: [
+    shared_libs: [
         "libaudioutils",
+    ],
+
+    static_libs: [
         "libFLAC",
     ],
 }
diff --git a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
index df7b403..e0365fc 100644
--- a/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
+++ b/media/codec2/components/mpeg2/C2SoftMpeg2Dec.cpp
@@ -29,7 +29,7 @@
 #include "impeg2d.h"
 
 namespace android {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
 constexpr char COMPONENT_NAME[] = "c2.android.mpeg2.decoder";
 
 class C2SoftMpeg2Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -47,6 +47,12 @@
         noInputLatency();
         noTimeStretch();
 
+        // TODO: Proper support for reorder depth.
+        addParameter(
+                DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
+                .withConstValue(new C2PortActualDelayTuning::output(3u))
+                .build());
+
         // TODO: output latency and reordering
 
         addParameter(
@@ -93,7 +99,7 @@
 
         addParameter(
                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
-                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 2))
+                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
                 .withFields({
                     C2F(mMaxInputSize, value).any(),
                 })
@@ -207,7 +213,8 @@
                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
         (void)mayBlock;
         // assume compression ratio of 1
-        me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 384);
+        me.set().value = c2_max((((maxSize.v.width + 15) / 16)
+                * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
         return C2R::Ok();
     }
 
diff --git a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
index 7e6685e..61b286c 100644
--- a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
+++ b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
@@ -33,7 +33,7 @@
 #include "mp4dec_api.h"
 
 namespace android {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
 #ifdef MPEG4
 constexpr char COMPONENT_NAME[] = "c2.android.mpeg4.decoder";
 #else
@@ -149,11 +149,7 @@
 
         addParameter(
                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
-#ifdef MPEG4
-                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 1920 * 1088 * 3 / 2))
-#else
-                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 352 * 288 * 3 / 2))
-#endif
+                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
                 .withFields({
                     C2F(mMaxInputSize, value).any(),
                 })
@@ -218,7 +214,8 @@
                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
         (void)mayBlock;
         // assume compression ratio of 1
-        me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 384);
+        me.set().value = c2_max((((maxSize.v.width + 15) / 16)
+                * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
         return C2R::Ok();
     }
 
diff --git a/media/codec2/components/opus/C2SoftOpusDec.cpp b/media/codec2/components/opus/C2SoftOpusDec.cpp
index 6b6974f..b7c1556 100644
--- a/media/codec2/components/opus/C2SoftOpusDec.cpp
+++ b/media/codec2/components/opus/C2SoftOpusDec.cpp
@@ -62,7 +62,7 @@
         addParameter(
                 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
                 .withDefault(new C2StreamSampleRateInfo::output(0u, 48000))
-                .withFields({C2F(mSampleRate, value).equalTo(48000)})
+                .withFields({C2F(mSampleRate, value).inRange(8000, 48000)})
                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
                 .build());
 
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index a759e8f..c7d73f4 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -30,7 +30,7 @@
 #include "C2SoftVpxDec.h"
 
 namespace android {
-
+constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
 #ifdef VP9
 constexpr char COMPONENT_NAME[] = "c2.android.vp9.decoder";
 #else
@@ -166,7 +166,7 @@
 
         addParameter(
                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
-                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
+                .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
                 .withFields({
                     C2F(mMaxInputSize, value).any(),
                 })
@@ -244,7 +244,8 @@
                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
         (void)mayBlock;
         // assume compression ratio of 2
-        me.set().value = (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+        me.set().value = c2_max((((maxSize.v.width + 63) / 64)
+                * ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
         return C2R::Ok();
     }
 
diff --git a/media/codec2/components/xaac/C2SoftXaacDec.cpp b/media/codec2/components/xaac/C2SoftXaacDec.cpp
index a3ebadb..951d058 100644
--- a/media/codec2/components/xaac/C2SoftXaacDec.cpp
+++ b/media/codec2/components/xaac/C2SoftXaacDec.cpp
@@ -87,7 +87,8 @@
                 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
                 .withDefault(new C2StreamSampleRateInfo::output(0u, 44100))
                 .withFields({C2F(mSampleRate, value).oneOf({
-                    7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+                    7350, 8000, 11025, 12000, 16000, 22050, 24000, 32000,
+                    44100, 48000, 64000, 88200, 96000
                 })})
                 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
                 .build());
@@ -1309,69 +1310,84 @@
                                 &ui_exec_done);
     RETURN_IF_FATAL(err_code,  "IA_CMD_TYPE_DONE_QUERY");
 
-    if (ui_exec_done != 1) {
-        VOID* p_array;        // ITTIAM:buffer to handle gain payload
-        WORD32 buf_size = 0;  // ITTIAM:gain payload length
-        WORD32 bit_str_fmt = 1;
-        WORD32 gain_stream_flag = 1;
-
-        err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
-                                    IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
-        RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
-
-        err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
-                                    IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
-        RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
-
-        if (buf_size > 0) {
-            /*Set bitstream_split_format */
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
-                                      IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
-            RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
-            memcpy(mDrcInBuf, p_array, buf_size);
-            /* Set number of bytes to be processed */
-            err_code =
-                ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, 0, &buf_size);
-            RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
-                                      IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, &gain_stream_flag);
-            RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
-            /* Execute process */
-            err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                                      IA_CMD_TYPE_INIT_CPY_BSF_BUFF, nullptr);
-            RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
-
-            mMpegDDRCPresent = 1;
-        }
-    }
-
-    /* How much buffer is used in input buffers */
+    int32_t num_preroll = 0;
     err_code = ixheaacd_dec_api(mXheaacCodecHandle,
-                                IA_API_CMD_GET_CURIDX_INPUT_BUF,
-                                0,
-                                bytesConsumed);
-    RETURN_IF_FATAL(err_code,  "IA_API_CMD_GET_CURIDX_INPUT_BUF");
+                                IA_API_CMD_GET_CONFIG_PARAM,
+                                IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES,
+                                &num_preroll);
+    RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES");
 
-    /* Get the output bytes */
-    err_code = ixheaacd_dec_api(mXheaacCodecHandle,
-                                IA_API_CMD_GET_OUTPUT_BYTES,
-                                0,
-                                outBytes);
-    RETURN_IF_FATAL(err_code,  "IA_API_CMD_GET_OUTPUT_BYTES");
+    {
+      int32_t preroll_frame_offset = 0;
 
-    if (mMpegDDRCPresent == 1) {
-        memcpy(mDrcInBuf, mOutputBuffer, *outBytes);
-        err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, 0, outBytes);
-        RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
+        do {
+            if (ui_exec_done != 1) {
+                VOID* p_array;        // ITTIAM:buffer to handle gain payload
+                WORD32 buf_size = 0;  // ITTIAM:gain payload length
+                WORD32 bit_str_fmt = 1;
+                WORD32 gain_stream_flag = 1;
 
-        err_code =
-            ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, nullptr);
-        RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
+                err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+                                            IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
+                RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
 
-        memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
+                err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+                                            IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
+                RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
+
+                if (buf_size > 0) {
+                    /*Set bitstream_split_format */
+                    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+                                            IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+                    memcpy(mDrcInBuf, p_array, buf_size);
+                    /* Set number of bytes to be processed */
+                    err_code =
+                        ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, 0, &buf_size);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+                    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+                                            IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, &gain_stream_flag);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+                    /* Execute process */
+                    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
+                                            IA_CMD_TYPE_INIT_CPY_BSF_BUFF, nullptr);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+
+                    mMpegDDRCPresent = 1;
+                }
+            }
+
+            /* How much buffer is used in input buffers */
+            err_code = ixheaacd_dec_api(mXheaacCodecHandle,
+                                        IA_API_CMD_GET_CURIDX_INPUT_BUF,
+                                        0,
+                                        bytesConsumed);
+            RETURN_IF_FATAL(err_code,  "IA_API_CMD_GET_CURIDX_INPUT_BUF");
+
+            /* Get the output bytes */
+            err_code = ixheaacd_dec_api(mXheaacCodecHandle,
+                                        IA_API_CMD_GET_OUTPUT_BYTES,
+                                        0,
+                                        outBytes);
+            RETURN_IF_FATAL(err_code,  "IA_API_CMD_GET_OUTPUT_BYTES");
+
+            if (mMpegDDRCPresent == 1) {
+                memcpy(mDrcInBuf, mOutputBuffer + preroll_frame_offset, *outBytes);
+                preroll_frame_offset += *outBytes;
+                err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, 0, outBytes);
+                RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
+
+                err_code =
+                    ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, nullptr);
+                RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
+
+                memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
+            }
+            num_preroll--;
+        } while (num_preroll > 0);
     }
     return IA_NO_ERROR;
 }
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 3820f90..f9eb2fa 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -243,6 +243,9 @@
     kParamIndexTimestampGapAdjustment, // input-surface, struct
 
     kParamIndexSurfaceAllocator, // u32
+
+    // low latency mode for decoders
+    kParamIndexLowLatencyMode, // bool
 };
 
 }
@@ -521,6 +524,7 @@
     PROFILE_DV_HE_07 = _C2_PL_DV_BASE + 7,      ///< Dolby Vision dvhe.07 profile
     PROFILE_DV_HE_08 = _C2_PL_DV_BASE + 8,      ///< Dolby Vision dvhe.08 profile
     PROFILE_DV_AV_09 = _C2_PL_DV_BASE + 9,      ///< Dolby Vision dvav.09 profile
+    PROFILE_DV_AV1_10 = _C2_PL_DV_BASE + 10,    ///< Dolby Vision dav1.10 profile
 
     // AV1 profiles
     PROFILE_AV1_0 = _C2_PL_AV1_BASE,            ///< AV1 Profile 0 (4:2:0, 8 to 10 bit)
@@ -804,6 +808,15 @@
 constexpr char C2_PARAMKEY_PIPELINE_DELAY[] = "algo.delay";
 
 /**
+ * Enable/disable low latency decoding mode.
+ * If true, low latency decoding mode is enabled, and the decoder doesn't hold input and output
+ * data more than required by the codec standards.
+ */
+typedef C2GlobalParam<C2Tuning, C2EasyBoolValue, kParamIndexLowLatencyMode>
+        C2GlobalLowLatencyModeTuning;
+constexpr char C2_PARAMKEY_LOW_LATENCY_MODE[] = "algo.low-latency";
+
+/**
  * Reference characteristics.
  *
  * The component may hold onto input and output buffers even after completing the corresponding
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index bdff29a..b96d29b 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -6,7 +6,7 @@
     defaults: ["hidl_defaults"],
 
     srcs: [
-        "ClientBlockHelper.cpp",
+        "OutputBufferQueue.cpp",
         "types.cpp",
     ],
 
@@ -63,6 +63,7 @@
     ],
 
     header_libs: [
+        "libbinder_headers",
         "libsystem_headers",
         "libcodec2_internal", // private
     ],
@@ -103,7 +104,7 @@
 
 // public dependency for Codec 2.0 HAL service implementations
 cc_defaults {
-    name: "libcodec2-hidl-defaults",
+    name: "libcodec2-hidl-defaults@1.0",
     defaults: ["libcodec2-impl-defaults"],
 
     shared_libs: [
@@ -114,7 +115,7 @@
 
 // public dependency for Codec 2.0 HAL client
 cc_defaults {
-    name: "libcodec2-hidl-client-defaults",
+    name: "libcodec2-hidl-client-defaults@1.0",
     defaults: ["libcodec2-impl-defaults"],
 
     shared_libs: [
diff --git a/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp b/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
deleted file mode 100644
index 50790bc..0000000
--- a/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Codec2-block_helper"
-#include <android-base/logging.h>
-
-#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/ClientBlockHelper.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
-
-#include <C2AllocatorGralloc.h>
-#include <C2BlockInternal.h>
-#include <C2Buffer.h>
-#include <C2PlatformSupport.h>
-
-#include <iomanip>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
-
-using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
-        V2_0::IGraphicBufferProducer;
-using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
-        V2_0::utils::B2HGraphicBufferProducer;
-
-namespace /* unnamed */ {
-
-// Create a GraphicBuffer object from a graphic block.
-sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
-    uint32_t width;
-    uint32_t height;
-    uint32_t format;
-    uint64_t usage;
-    uint32_t stride;
-    uint32_t generation;
-    uint64_t bqId;
-    int32_t bqSlot;
-    _UnwrapNativeCodec2GrallocMetadata(
-            block.handle(), &width, &height, &format, &usage,
-            &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
-    native_handle_t *grallocHandle =
-            UnwrapNativeCodec2GrallocHandle(block.handle());
-    sp<GraphicBuffer> graphicBuffer =
-            new GraphicBuffer(grallocHandle,
-                              GraphicBuffer::CLONE_HANDLE,
-                              width, height, format,
-                              1, usage, stride);
-    native_handle_delete(grallocHandle);
-    return graphicBuffer;
-}
-
-template <typename BlockProcessor>
-void forEachBlock(C2FrameData& frameData,
-                  BlockProcessor process) {
-    for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
-        if (buffer) {
-            for (const C2ConstGraphicBlock& block :
-                    buffer->data().graphicBlocks()) {
-                process(block);
-            }
-        }
-    }
-}
-
-template <typename BlockProcessor>
-void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
-                  BlockProcessor process) {
-    for (const std::unique_ptr<C2Work>& work : workList) {
-        if (!work) {
-            continue;
-        }
-        for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
-            if (worklet) {
-                forEachBlock(worklet->output, process);
-            }
-        }
-    }
-}
-
-sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
-    sp<HGraphicBufferProducer> hgbp =
-            igbp->getHalInterface<HGraphicBufferProducer>();
-    return hgbp ? hgbp :
-            new B2HGraphicBufferProducer(igbp);
-}
-
-status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
-                             const sp<IGraphicBufferProducer>& igbp,
-                             uint32_t generation,
-                             int32_t* bqSlot) {
-    if (!igbp) {
-        LOG(WARNING) << "attachToBufferQueue -- null producer.";
-        return NO_INIT;
-    }
-
-    sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
-    graphicBuffer->setGenerationNumber(generation);
-
-    LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
-            << " block dimension " << block.width() << "x"
-                                   << block.height()
-            << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
-                                           << graphicBuffer->getHeight()
-            << std::hex << std::setfill('0')
-            << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
-            << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
-            << std::dec << std::setfill(' ')
-            << ", stride " << graphicBuffer->getStride()
-            << ", generation " << graphicBuffer->getGenerationNumber();
-
-    status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
-    if (result != OK) {
-        LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
-                        "status = " << result << ".";
-        return result;
-    }
-    LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
-                 << *bqSlot << ".";
-    return OK;
-}
-
-bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
-                              uint32_t* generation,
-                              uint64_t* bqId,
-                              int32_t* bqSlot) {
-    return _C2BlockFactory::GetBufferQueueData(
-            _C2BlockFactory::GetGraphicBlockPoolData(block),
-            generation, bqId, bqSlot);
-}
-} // unnamed namespace
-
-class OutputBufferQueue::Impl {
-    std::mutex mMutex;
-    sp<IGraphicBufferProducer> mIgbp;
-    uint32_t mGeneration;
-    uint64_t mBqId;
-    std::shared_ptr<int> mOwner;
-    // To migrate existing buffers
-    sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
-    std::weak_ptr<_C2BlockPoolData>
-                    mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
-
-public:
-    Impl(): mGeneration(0), mBqId(0) {}
-
-    bool configure(const sp<IGraphicBufferProducer>& igbp,
-                   uint32_t generation,
-                   uint64_t bqId) {
-        size_t tryNum = 0;
-        size_t success = 0;
-        sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
-        std::weak_ptr<_C2BlockPoolData>
-                poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
-        {
-            std::scoped_lock<std::mutex> l(mMutex);
-            if (generation == mGeneration) {
-                return false;
-            }
-            mIgbp = igbp;
-            mGeneration = generation;
-            mBqId = bqId;
-            mOwner = std::make_shared<int>(0);
-            for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
-                if (mBqId == 0 || !mBuffers[i]) {
-                    continue;
-                }
-                std::shared_ptr<_C2BlockPoolData> data = mPoolDatas[i].lock();
-                if (!data ||
-                    !_C2BlockFactory::BeginAttachBlockToBufferQueue(data)) {
-                    continue;
-                }
-                ++tryNum;
-                int bqSlot;
-                mBuffers[i]->setGenerationNumber(generation);
-                status_t result = igbp->attachBuffer(&bqSlot, mBuffers[i]);
-                if (result != OK) {
-                    continue;
-                }
-                bool attach =
-                        _C2BlockFactory::EndAttachBlockToBufferQueue(
-                                data, mOwner, getHgbp(mIgbp),
-                                generation, bqId, bqSlot);
-                if (!attach) {
-                    igbp->cancelBuffer(bqSlot, Fence::NO_FENCE);
-                    continue;
-                }
-                buffers[bqSlot] = mBuffers[i];
-                poolDatas[bqSlot] = data;
-                ++success;
-            }
-            for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
-                mBuffers[i] = buffers[i];
-                mPoolDatas[i] = poolDatas[i];
-            }
-        }
-        ALOGD("remote graphic buffer migration %zu/%zu", success, tryNum);
-        return true;
-    }
-
-    bool registerBuffer(const C2ConstGraphicBlock& block) {
-        std::shared_ptr<_C2BlockPoolData> data =
-                _C2BlockFactory::GetGraphicBlockPoolData(block);
-        if (!data) {
-            return false;
-        }
-        std::scoped_lock<std::mutex> l(mMutex);
-
-        if (!mIgbp) {
-            return false;
-        }
-
-        uint32_t oldGeneration;
-        uint64_t oldId;
-        int32_t oldSlot;
-        // If the block is not bufferqueue-based, do nothing.
-        if (!_C2BlockFactory::GetBufferQueueData(
-                data, &oldGeneration, &oldId, &oldSlot) || (oldId == 0)) {
-            return false;
-        }
-        // If the block's bqId is the same as the desired bqId, just hold.
-        if ((oldId == mBqId) && (oldGeneration == mGeneration)) {
-            LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
-                         << " bqId " << oldId
-                         << ", bqSlot " << oldSlot
-                         << ", generation " << mGeneration
-                         << ".";
-            _C2BlockFactory::HoldBlockFromBufferQueue(data, mOwner, getHgbp(mIgbp));
-            mPoolDatas[oldSlot] = data;
-            mBuffers[oldSlot] = createGraphicBuffer(block);
-            mBuffers[oldSlot]->setGenerationNumber(mGeneration);
-            return true;
-        }
-        int32_t d = (int32_t) mGeneration - (int32_t) oldGeneration;
-        LOG(WARNING) << "receiving stale buffer: generation "
-                     << mGeneration << " , diff " << d  << " : slot "
-                     << oldSlot;
-        return false;
-    }
-
-    status_t outputBuffer(
-            const C2ConstGraphicBlock& block,
-            const BnGraphicBufferProducer::QueueBufferInput& input,
-            BnGraphicBufferProducer::QueueBufferOutput* output) {
-        uint32_t generation;
-        uint64_t bqId;
-        int32_t bqSlot;
-        bool display = displayBufferQueueBlock(block);
-        if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
-            bqId == 0) {
-            // Block not from bufferqueue -- it must be attached before queuing.
-
-            mMutex.lock();
-            sp<IGraphicBufferProducer> outputIgbp = mIgbp;
-            uint32_t outputGeneration = mGeneration;
-            mMutex.unlock();
-
-            status_t status = attachToBufferQueue(
-                    block, outputIgbp, outputGeneration, &bqSlot);
-            if (status != OK) {
-                LOG(WARNING) << "outputBuffer -- attaching failed.";
-                return INVALID_OPERATION;
-            }
-
-            status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
-                                         input, output);
-            if (status != OK) {
-                LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
-                           "on non-bufferqueue-based block. "
-                           "Error = " << status << ".";
-                return status;
-            }
-            return OK;
-        }
-
-        mMutex.lock();
-        sp<IGraphicBufferProducer> outputIgbp = mIgbp;
-        uint32_t outputGeneration = mGeneration;
-        uint64_t outputBqId = mBqId;
-        mMutex.unlock();
-
-        if (!outputIgbp) {
-            LOG(VERBOSE) << "outputBuffer -- output surface is null.";
-            return NO_INIT;
-        }
-
-        if (!display) {
-            LOG(WARNING) << "outputBuffer -- cannot display "
-                         "bufferqueue-based block to the bufferqueue.";
-            return UNKNOWN_ERROR;
-        }
-        if (bqId != outputBqId || generation != outputGeneration) {
-            int32_t diff = (int32_t) outputGeneration - (int32_t) generation;
-            LOG(WARNING) << "outputBuffer -- buffers from old generation to "
-                         << outputGeneration << " , diff: " << diff
-                         << " , slot: " << bqSlot;
-            return DEAD_OBJECT;
-        }
-
-        status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
-                                              input, output);
-        if (status != OK) {
-            LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
-                       "on bufferqueue-based block. "
-                       "Error = " << status << ".";
-            return status;
-        }
-        return OK;
-    }
-
-    Impl *getPtr() {
-        return this;
-    }
-
-    ~Impl() {}
-};
-
-OutputBufferQueue::OutputBufferQueue(): mImpl(new Impl()) {}
-
-OutputBufferQueue::~OutputBufferQueue() {}
-
-bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
-                                  uint32_t generation,
-                                  uint64_t bqId) {
-    return mImpl && mImpl->configure(igbp, generation, bqId);
-}
-
-status_t OutputBufferQueue::outputBuffer(
-    const C2ConstGraphicBlock& block,
-    const BnGraphicBufferProducer::QueueBufferInput& input,
-    BnGraphicBufferProducer::QueueBufferOutput* output) {
-    if (mImpl) {
-        return mImpl->outputBuffer(block, input, output);
-    }
-    return DEAD_OBJECT;
-}
-
-void OutputBufferQueue::holdBufferQueueBlocks(
-        const std::list<std::unique_ptr<C2Work>>& workList) {
-    if (!mImpl) {
-        return;
-    }
-    forEachBlock(workList,
-                 std::bind(&OutputBufferQueue::Impl::registerBuffer,
-                           mImpl->getPtr(), std::placeholders::_1));
-}
-
-}  // namespace utils
-}  // namespace V1_0
-}  // namespace c2
-}  // namespace media
-}  // namespace hardware
-}  // namespace android
-
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index a9f20a4..8a84601 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -204,7 +204,8 @@
         const sp<::android::hardware::media::bufferpool::V2_0::
         IClientManager>& clientPoolManager)
       : mComponent{component},
-        mInterface{new ComponentInterface(component->intf(), store.get())},
+        mInterface{new ComponentInterface(component->intf(),
+                                          store->getParameterCache())},
         mListener{listener},
         mStore{store},
         mBufferPoolSender{clientPoolManager} {
diff --git a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
index 39e5357..12078e0 100644
--- a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
@@ -87,10 +87,10 @@
 // ComponentInterface
 ComponentInterface::ComponentInterface(
         const std::shared_ptr<C2ComponentInterface>& intf,
-        ComponentStore* store)
+        const std::shared_ptr<ParameterCache>& cache)
       : mInterface{intf},
         mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
-    mInit = mConfigurable->init(store);
+    mInit = mConfigurable->init(cache);
 }
 
 c2_status_t ComponentInterface::status() const {
diff --git a/media/codec2/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index 1e0a190..9b9d449 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -102,8 +102,29 @@
 
 } // unnamed namespace
 
+struct ComponentStore::StoreParameterCache : public ParameterCache {
+    std::mutex mStoreMutex;
+    ComponentStore* mStore;
+
+    StoreParameterCache(ComponentStore* store): mStore{store} {
+    }
+
+    virtual c2_status_t validate(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
+            ) override {
+        std::scoped_lock _lock(mStoreMutex);
+        return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
+    }
+
+    void onStoreDestroyed() {
+        std::scoped_lock _lock(mStoreMutex);
+        mStore = nullptr;
+    }
+};
+
 ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
       : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+        mParameterCache{std::make_shared<StoreParameterCache>(this)},
         mStore{store} {
 
     std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
@@ -113,7 +134,12 @@
     mParamReflector = mStore->getParamReflector();
 
     // Retrieve supported parameters from store
-    mInit = mConfigurable->init(this);
+    using namespace std::placeholders;
+    mInit = mConfigurable->init(mParameterCache);
+}
+
+ComponentStore::~ComponentStore() {
+    mParameterCache->onStoreDestroyed();
 }
 
 c2_status_t ComponentStore::status() const {
@@ -146,6 +172,10 @@
     return res;
 }
 
+std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
+    return mParameterCache;
+}
+
 // Methods from ::android::hardware::media::c2::V1_0::IComponentStore
 Return<void> ComponentStore::createComponent(
         const hidl_string& name,
@@ -187,7 +217,7 @@
     sp<IComponentInterface> interface;
     if (res == C2_OK) {
         onInterfaceLoaded(c2interface);
-        interface = new ComponentInterface(c2interface, this);
+        interface = new ComponentInterface(c2interface, mParameterCache);
     }
     _hidl_cb(static_cast<Status>(res), interface);
     return Void();
@@ -218,8 +248,9 @@
         _hidl_cb(Status::CORRUPTED, nullptr);
         return Void();
     }
+    using namespace std::placeholders;
     sp<InputSurface> inputSurface = new InputSurface(
-            this,
+            mParameterCache,
             std::make_shared<C2ReflectorHelper>(),
             source->getHGraphicBufferProducer(),
             source);
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index ec9c170..530576d 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -38,10 +38,11 @@
       : mIntf{std::move(intf)} {
 }
 
-c2_status_t CachedConfigurable::init(ComponentStore* store) {
+c2_status_t CachedConfigurable::init(
+        const std::shared_ptr<ParameterCache>& cache) {
     // Retrieve supported parameters from store
     c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
-    c2_status_t validate = store->validateSupportedParams(mSupportedParams);
+    c2_status_t validate = cache->validate(mSupportedParams);
     return init == C2_OK ? C2_OK : validate;
 }
 
diff --git a/media/codec2/hidl/1.0/utils/InputBufferManager.cpp b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
index a023a05..8c0d0a4 100644
--- a/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
+++ b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
@@ -70,7 +70,7 @@
                  << ".";
     std::lock_guard<std::mutex> lock(mMutex);
 
-    std::set<TrackedBuffer> &bufferIds =
+    std::set<TrackedBuffer*> &bufferIds =
             mTrackedBuffersMap[listener][frameIndex];
 
     for (size_t i = 0; i < input.buffers.size(); ++i) {
@@ -79,13 +79,14 @@
                          << "Input buffer at index " << i << " is null.";
             continue;
         }
-        const TrackedBuffer &bufferId =
-                *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
-                first;
+        TrackedBuffer *bufferId =
+            new TrackedBuffer(listener, frameIndex, i, input.buffers[i]);
+        mTrackedBufferCache.emplace(bufferId);
+        bufferIds.emplace(bufferId);
 
         c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
                 onBufferDestroyed,
-                const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
+                reinterpret_cast<void*>(bufferId));
         if (status != C2_OK) {
             LOG(DEBUG) << "InputBufferManager::_registerFrameData -- "
                        << "registerOnDestroyNotify() failed "
@@ -119,31 +120,32 @@
 
     auto findListener = mTrackedBuffersMap.find(listener);
     if (findListener != mTrackedBuffersMap.end()) {
-        std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
+        std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds
                 = findListener->second;
         auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
         if (findFrameIndex != frameIndex2BufferIds.end()) {
-            std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
-            for (const TrackedBuffer& bufferId : bufferIds) {
-                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+            std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+            for (TrackedBuffer* bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId->buffer.lock();
                 if (buffer) {
                     c2_status_t status = buffer->unregisterOnDestroyNotify(
                             onBufferDestroyed,
-                            const_cast<void*>(
-                            reinterpret_cast<const void*>(&bufferId)));
+                            reinterpret_cast<void*>(bufferId));
                     if (status != C2_OK) {
                         LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
                                    << "-- unregisterOnDestroyNotify() failed "
                                    << "(listener @ 0x"
                                         << std::hex
-                                        << bufferId.listener.unsafe_get()
+                                        << bufferId->listener.unsafe_get()
                                    << ", frameIndex = "
-                                        << std::dec << bufferId.frameIndex
-                                   << ", bufferIndex = " << bufferId.bufferIndex
+                                        << std::dec << bufferId->frameIndex
+                                   << ", bufferIndex = " << bufferId->bufferIndex
                                    << ") => status = " << status
                                    << ".";
                     }
                 }
+                mTrackedBufferCache.erase(bufferId);
+                delete bufferId;
             }
 
             frameIndex2BufferIds.erase(findFrameIndex);
@@ -179,31 +181,32 @@
 
     auto findListener = mTrackedBuffersMap.find(listener);
     if (findListener != mTrackedBuffersMap.end()) {
-        std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds =
+        std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds =
                 findListener->second;
         for (auto findFrameIndex = frameIndex2BufferIds.begin();
                 findFrameIndex != frameIndex2BufferIds.end();
                 ++findFrameIndex) {
-            std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
-            for (const TrackedBuffer& bufferId : bufferIds) {
-                std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+            std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+            for (TrackedBuffer* bufferId : bufferIds) {
+                std::shared_ptr<C2Buffer> buffer = bufferId->buffer.lock();
                 if (buffer) {
                     c2_status_t status = buffer->unregisterOnDestroyNotify(
                             onBufferDestroyed,
-                            const_cast<void*>(
-                            reinterpret_cast<const void*>(&bufferId)));
+                            reinterpret_cast<void*>(bufferId));
                     if (status != C2_OK) {
                         LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
                                    << "-- unregisterOnDestroyNotify() failed "
                                    << "(listener @ 0x"
                                         << std::hex
-                                        << bufferId.listener.unsafe_get()
+                                        << bufferId->listener.unsafe_get()
                                    << ", frameIndex = "
-                                        << std::dec << bufferId.frameIndex
-                                   << ", bufferIndex = " << bufferId.bufferIndex
+                                        << std::dec << bufferId->frameIndex
+                                   << ", bufferIndex = " << bufferId->bufferIndex
                                    << ") => status = " << status
                                    << ".";
                     }
+                    mTrackedBufferCache.erase(bufferId);
+                    delete bufferId;
                 }
             }
         }
@@ -236,50 +239,59 @@
                      << std::dec << ".";
         return;
     }
-    TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    TrackedBuffer *bufferId = reinterpret_cast<TrackedBuffer*>(arg);
+
+    if (mTrackedBufferCache.find(bufferId) == mTrackedBufferCache.end()) {
+        LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+                     << "unregistered buffer: "
+                     << "buf @ 0x" << std::hex << buf
+                     << ", arg @ 0x" << std::hex << arg
+                     << std::dec << ".";
+        return;
+    }
+
     LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
                  << "buf @ 0x" << std::hex << buf
                  << ", arg @ 0x" << std::hex << arg
                  << std::dec << " -- "
-                 << "listener @ 0x" << std::hex << id.listener.unsafe_get()
-                 << ", frameIndex = " << std::dec << id.frameIndex
-                 << ", bufferIndex = " << id.bufferIndex
+                 << "listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+                 << ", frameIndex = " << std::dec << bufferId->frameIndex
+                 << ", bufferIndex = " << bufferId->bufferIndex
                  << ".";
-
-    std::lock_guard<std::mutex> lock(mMutex);
-
-    auto findListener = mTrackedBuffersMap.find(id.listener);
+    auto findListener = mTrackedBuffersMap.find(bufferId->listener);
     if (findListener == mTrackedBuffersMap.end()) {
-        LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
-                   << "received invalid listener: "
-                   << "listener @ 0x" << std::hex << id.listener.unsafe_get()
-                   << " (frameIndex = " << std::dec << id.frameIndex
-                   << ", bufferIndex = " << id.bufferIndex
-                   << ").";
+        LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- "
+                     << "received invalid listener: "
+                     << "listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+                     << " (frameIndex = " << std::dec << bufferId->frameIndex
+                     << ", bufferIndex = " << bufferId->bufferIndex
+                     << ").";
         return;
     }
 
-    std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
+    std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds
             = findListener->second;
-    auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
+    auto findFrameIndex = frameIndex2BufferIds.find(bufferId->frameIndex);
     if (findFrameIndex == frameIndex2BufferIds.end()) {
         LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
                    << "received invalid frame index: "
-                   << "frameIndex = " << id.frameIndex
-                   << " (listener @ 0x" << std::hex << id.listener.unsafe_get()
-                   << ", bufferIndex = " << std::dec << id.bufferIndex
+                   << "frameIndex = " << bufferId->frameIndex
+                   << " (listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+                   << ", bufferIndex = " << std::dec << bufferId->bufferIndex
                    << ").";
         return;
     }
 
-    std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
-    auto findBufferId = bufferIds.find(id);
+    std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+    auto findBufferId = bufferIds.find(bufferId);
     if (findBufferId == bufferIds.end()) {
         LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
                    << "received invalid buffer index: "
-                   << "bufferIndex = " << id.bufferIndex
-                   << " (frameIndex = " << id.frameIndex
-                   << ", listener @ 0x" << std::hex << id.listener.unsafe_get()
+                   << "bufferIndex = " << bufferId->bufferIndex
+                   << " (frameIndex = " << bufferId->frameIndex
+                   << ", listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
                    << std::dec << ").";
         return;
     }
@@ -292,10 +304,13 @@
         }
     }
 
-    DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
-    deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
+    DeathNotifications &deathNotifications = mDeathNotifications[bufferId->listener];
+    deathNotifications.indices[bufferId->frameIndex].emplace_back(bufferId->bufferIndex);
     ++deathNotifications.count;
     mOnBufferDestroyed.notify_one();
+
+    mTrackedBufferCache.erase(bufferId);
+    delete bufferId;
 }
 
 // Notify the clients about buffer destructions.
diff --git a/media/codec2/hidl/1.0/utils/InputSurface.cpp b/media/codec2/hidl/1.0/utils/InputSurface.cpp
index 2b4ca85..c3c32e9 100644
--- a/media/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -137,9 +137,9 @@
     }
     std::shared_ptr<C2Component> comp = Component::findLocalComponent(sink);
     if (comp) {
-        connection = new InputSurfaceConnection(mSource, comp, mStore);
+        connection = new InputSurfaceConnection(mSource, comp, mParameterCache);
     } else {
-        connection = new InputSurfaceConnection(mSource, sink, mStore);
+        connection = new InputSurfaceConnection(mSource, sink, mParameterCache);
     }
     if (!connection->init()) {
         connection = nullptr;
@@ -153,11 +153,11 @@
 
 // Constructor is exclusive to ComponentStore.
 InputSurface::InputSurface(
-        const sp<ComponentStore>& store,
+        const std::shared_ptr<ParameterCache>& cache,
         const std::shared_ptr<C2ReflectorHelper>& reflector,
         const sp<HGraphicBufferProducer>& producer,
         const sp<GraphicBufferSource>& source)
-      : mStore{store},
+      : mParameterCache{cache},
         mProducer{producer},
         mSource{source},
         mIntf{std::make_shared<Interface>(reflector)},
@@ -165,7 +165,7 @@
                 std::make_unique<ConfigurableIntf>(
                     mIntf, source))} {
 
-    mConfigurable->init(store.get());
+    mConfigurable->init(mParameterCache);
 }
 
 }  // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
index c9932ef..5cc0d53 100644
--- a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
@@ -445,21 +445,21 @@
 InputSurfaceConnection::InputSurfaceConnection(
         const sp<GraphicBufferSource>& source,
         const std::shared_ptr<C2Component>& comp,
-        const sp<ComponentStore>& store)
+        const std::shared_ptr<ParameterCache>& cache)
       : mImpl{new Impl(source, comp)},
         mConfigurable{new CachedConfigurable(
             std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
-    mConfigurable->init(store.get());
+    mConfigurable->init(cache);
 }
 
 InputSurfaceConnection::InputSurfaceConnection(
         const sp<GraphicBufferSource>& source,
         const sp<IInputSink>& sink,
-        const sp<ComponentStore>& store)
+        const std::shared_ptr<ParameterCache>& cache)
       : mImpl{new Impl(source, sink)},
         mConfigurable{new CachedConfigurable(
             std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
-    mConfigurable->init(store.get());
+    mConfigurable->init(cache);
 }
 
 Return<Status> InputSurfaceConnection::disconnect() {
diff --git a/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp b/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
new file mode 100644
index 0000000..c4a72ef
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/OutputBufferQueue.cpp
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-OutputBufferQueue"
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <codec2/hidl/1.0/OutputBufferQueue.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+        V2_0::IGraphicBufferProducer;
+using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+        V2_0::utils::B2HGraphicBufferProducer;
+
+namespace /* unnamed */ {
+
+// Create a GraphicBuffer object from a graphic block.
+sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
+    uint32_t width;
+    uint32_t height;
+    uint32_t format;
+    uint64_t usage;
+    uint32_t stride;
+    uint32_t generation;
+    uint64_t bqId;
+    int32_t bqSlot;
+    _UnwrapNativeCodec2GrallocMetadata(
+            block.handle(), &width, &height, &format, &usage,
+            &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
+    native_handle_t *grallocHandle =
+            UnwrapNativeCodec2GrallocHandle(block.handle());
+    sp<GraphicBuffer> graphicBuffer =
+            new GraphicBuffer(grallocHandle,
+                              GraphicBuffer::CLONE_HANDLE,
+                              width, height, format,
+                              1, usage, stride);
+    native_handle_delete(grallocHandle);
+    return graphicBuffer;
+}
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+                  BlockProcessor process) {
+    for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+        if (buffer) {
+            for (const C2ConstGraphicBlock& block :
+                    buffer->data().graphicBlocks()) {
+                process(block);
+            }
+        }
+    }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+                  BlockProcessor process) {
+    for (const std::unique_ptr<C2Work>& work : workList) {
+        if (!work) {
+            continue;
+        }
+        for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+            if (worklet) {
+                forEachBlock(worklet->output, process);
+            }
+        }
+    }
+}
+
+sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
+    sp<HGraphicBufferProducer> hgbp =
+            igbp->getHalInterface<HGraphicBufferProducer>();
+    return hgbp ? hgbp :
+            new B2HGraphicBufferProducer(igbp);
+}
+
+status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
+                             const sp<IGraphicBufferProducer>& igbp,
+                             uint32_t generation,
+                             int32_t* bqSlot) {
+    if (!igbp) {
+        LOG(WARNING) << "attachToBufferQueue -- null producer.";
+        return NO_INIT;
+    }
+
+    sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
+    graphicBuffer->setGenerationNumber(generation);
+
+    LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
+            << " block dimension " << block.width() << "x"
+                                   << block.height()
+            << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
+                                           << graphicBuffer->getHeight()
+            << std::hex << std::setfill('0')
+            << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
+            << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
+            << std::dec << std::setfill(' ')
+            << ", stride " << graphicBuffer->getStride()
+            << ", generation " << graphicBuffer->getGenerationNumber();
+
+    status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
+    if (result != OK) {
+        LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+                        "status = " << result << ".";
+        return result;
+    }
+    LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+                 << *bqSlot << ".";
+    return OK;
+}
+
+bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
+                              uint32_t* generation,
+                              uint64_t* bqId,
+                              int32_t* bqSlot) {
+    return _C2BlockFactory::GetBufferQueueData(
+            _C2BlockFactory::GetGraphicBlockPoolData(block),
+            generation, bqId, bqSlot);
+}
+
+} // unnamed namespace
+
+OutputBufferQueue::OutputBufferQueue()
+      : mGeneration{0}, mBqId{0} {
+}
+
+OutputBufferQueue::~OutputBufferQueue() {
+}
+
+bool OutputBufferQueue::configure(const sp<IGraphicBufferProducer>& igbp,
+                                  uint32_t generation,
+                                  uint64_t bqId) {
+    size_t tryNum = 0;
+    size_t success = 0;
+    sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
+    std::weak_ptr<_C2BlockPoolData>
+            poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
+    {
+        std::scoped_lock<std::mutex> l(mMutex);
+        if (generation == mGeneration) {
+            return false;
+        }
+        mIgbp = igbp;
+        mGeneration = generation;
+        mBqId = bqId;
+        mOwner = std::make_shared<int>(0);
+        for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
+            if (mBqId == 0 || !mBuffers[i]) {
+                continue;
+            }
+            std::shared_ptr<_C2BlockPoolData> data = mPoolDatas[i].lock();
+            if (!data ||
+                !_C2BlockFactory::BeginAttachBlockToBufferQueue(data)) {
+                continue;
+            }
+            ++tryNum;
+            int bqSlot;
+            mBuffers[i]->setGenerationNumber(generation);
+            status_t result = igbp->attachBuffer(&bqSlot, mBuffers[i]);
+            if (result != OK) {
+                continue;
+            }
+            bool attach =
+                    _C2BlockFactory::EndAttachBlockToBufferQueue(
+                            data, mOwner, getHgbp(mIgbp),
+                            generation, bqId, bqSlot);
+            if (!attach) {
+                igbp->cancelBuffer(bqSlot, Fence::NO_FENCE);
+                continue;
+            }
+            buffers[bqSlot] = mBuffers[i];
+            poolDatas[bqSlot] = data;
+            ++success;
+        }
+        for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; ++i) {
+            mBuffers[i] = buffers[i];
+            mPoolDatas[i] = poolDatas[i];
+        }
+    }
+    ALOGD("remote graphic buffer migration %zu/%zu", success, tryNum);
+    return true;
+}
+
+bool OutputBufferQueue::registerBuffer(const C2ConstGraphicBlock& block) {
+    std::shared_ptr<_C2BlockPoolData> data =
+            _C2BlockFactory::GetGraphicBlockPoolData(block);
+    if (!data) {
+        return false;
+    }
+    std::scoped_lock<std::mutex> l(mMutex);
+
+    if (!mIgbp) {
+        return false;
+    }
+
+    uint32_t oldGeneration;
+    uint64_t oldId;
+    int32_t oldSlot;
+    // If the block is not bufferqueue-based, do nothing.
+    if (!_C2BlockFactory::GetBufferQueueData(
+            data, &oldGeneration, &oldId, &oldSlot) || (oldId == 0)) {
+        return false;
+    }
+    // If the block's bqId is the same as the desired bqId, just hold.
+    if ((oldId == mBqId) && (oldGeneration == mGeneration)) {
+        LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
+                     << " bqId " << oldId
+                     << ", bqSlot " << oldSlot
+                     << ", generation " << mGeneration
+                     << ".";
+        _C2BlockFactory::HoldBlockFromBufferQueue(data, mOwner, getHgbp(mIgbp));
+        mPoolDatas[oldSlot] = data;
+        mBuffers[oldSlot] = createGraphicBuffer(block);
+        mBuffers[oldSlot]->setGenerationNumber(mGeneration);
+        return true;
+    }
+    int32_t d = (int32_t) mGeneration - (int32_t) oldGeneration;
+    LOG(WARNING) << "receiving stale buffer: generation "
+                 << mGeneration << " , diff " << d  << " : slot "
+                 << oldSlot;
+    return false;
+}
+
+status_t OutputBufferQueue::outputBuffer(
+        const C2ConstGraphicBlock& block,
+        const BnGraphicBufferProducer::QueueBufferInput& input,
+        BnGraphicBufferProducer::QueueBufferOutput* output) {
+    uint32_t generation;
+    uint64_t bqId;
+    int32_t bqSlot;
+    bool display = displayBufferQueueBlock(block);
+    if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot) ||
+        bqId == 0) {
+        // Block not from bufferqueue -- it must be attached before queuing.
+
+        mMutex.lock();
+        sp<IGraphicBufferProducer> outputIgbp = mIgbp;
+        uint32_t outputGeneration = mGeneration;
+        mMutex.unlock();
+
+        status_t status = attachToBufferQueue(
+                block, outputIgbp, outputGeneration, &bqSlot);
+        if (status != OK) {
+            LOG(WARNING) << "outputBuffer -- attaching failed.";
+            return INVALID_OPERATION;
+        }
+
+        status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+                                     input, output);
+        if (status != OK) {
+            LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
+                       "on non-bufferqueue-based block. "
+                       "Error = " << status << ".";
+            return status;
+        }
+        return OK;
+    }
+
+    mMutex.lock();
+    sp<IGraphicBufferProducer> outputIgbp = mIgbp;
+    uint32_t outputGeneration = mGeneration;
+    uint64_t outputBqId = mBqId;
+    mMutex.unlock();
+
+    if (!outputIgbp) {
+        LOG(VERBOSE) << "outputBuffer -- output surface is null.";
+        return NO_INIT;
+    }
+
+    if (!display) {
+        LOG(WARNING) << "outputBuffer -- cannot display "
+                     "bufferqueue-based block to the bufferqueue.";
+        return UNKNOWN_ERROR;
+    }
+    if (bqId != outputBqId || generation != outputGeneration) {
+        int32_t diff = (int32_t) outputGeneration - (int32_t) generation;
+        LOG(WARNING) << "outputBuffer -- buffers from old generation to "
+                     << outputGeneration << " , diff: " << diff
+                     << " , slot: " << bqSlot;
+        return DEAD_OBJECT;
+    }
+
+    status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
+                                          input, output);
+    if (status != OK) {
+        LOG(ERROR) << "outputBuffer -- queueBuffer() failed "
+                   "on bufferqueue-based block. "
+                   "Error = " << status << ".";
+        return status;
+    }
+    return OK;
+}
+
+void OutputBufferQueue::holdBufferQueueBlocks(
+        const std::list<std::unique_ptr<C2Work>>& workList) {
+    forEachBlock(workList,
+                 std::bind(&OutputBufferQueue::registerBuffer,
+                           this, std::placeholders::_1));
+}
+
+}  // namespace utils
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
index a5d235e..9102f92 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
@@ -45,7 +45,7 @@
 struct ComponentInterface : public IComponentInterface {
     ComponentInterface(
             const std::shared_ptr<C2ComponentInterface>& interface,
-            ComponentStore* store);
+            const std::shared_ptr<ParameterCache>& cache);
     c2_status_t status() const;
     virtual Return<sp<IConfigurable>> getConfigurable() override;
 
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index be80c62..fe7d048 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -54,7 +54,7 @@
 
 struct ComponentStore : public IComponentStore {
     ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
-    virtual ~ComponentStore() = default;
+    virtual ~ComponentStore();
 
     /**
      * Returns the status of the construction of this object.
@@ -68,6 +68,12 @@
     c2_status_t validateSupportedParams(
             const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
 
+    /**
+     * Returns the store's ParameterCache. This is used for validation by
+     * Configurable::init().
+     */
+    std::shared_ptr<ParameterCache> getParameterCache() const;
+
     // Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
     virtual Return<void> createComponent(
             const hidl_string& name,
@@ -98,6 +104,8 @@
 
 protected:
     sp<CachedConfigurable> mConfigurable;
+    struct StoreParameterCache;
+    std::shared_ptr<StoreParameterCache> mParameterCache;
 
     // Does bookkeeping for an interface that has been loaded.
     void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
index 8095185..8f49a97 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
@@ -79,6 +79,20 @@
 };
 
 /**
+ * Type for validating and caching parameters when CachedConfigurable is
+ * initialized.
+ *
+ * This is meant to be created by the ComponentStore. The purpose of abstracting
+ * this is to allow different versions of ComponentStore to work with this
+ * CachedConfigurable.
+ */
+struct ParameterCache {
+    virtual c2_status_t validate(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>&) = 0;
+    virtual ~ParameterCache() = default;
+};
+
+/**
  * Implementation of the IConfigurable interface that supports caching of
  * supported parameters from a supplied ComponentStore.
  *
@@ -91,7 +105,8 @@
 struct CachedConfigurable : public IConfigurable {
     CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
 
-    c2_status_t init(ComponentStore* store);
+    // Populates mSupportedParams.
+    c2_status_t init(const std::shared_ptr<ParameterCache> &cache);
 
     // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
 
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
index b6857d5..42fa557 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
@@ -196,13 +196,9 @@
                 frameIndex(frameIndex),
                 bufferIndex(bufferIndex),
                 buffer(buffer) {}
-        TrackedBuffer(const TrackedBuffer&) = default;
-        bool operator<(const TrackedBuffer& other) const {
-            return bufferIndex < other.bufferIndex;
-        }
     };
 
-    // Map: listener -> frameIndex -> set<TrackedBuffer>.
+    // Map: listener -> frameIndex -> set<TrackedBuffer*>.
     // Essentially, this is used to store triples (listener, frameIndex,
     // bufferIndex) that's searchable by listener and (listener, frameIndex).
     // However, the value of the innermost map is TrackedBuffer, which also
@@ -210,7 +206,7 @@
     // because onBufferDestroyed() needs to know listener and frameIndex too.
     typedef std::map<wp<IComponentListener>,
                      std::map<uint64_t,
-                              std::set<TrackedBuffer>>> TrackedBuffersMap;
+                              std::set<TrackedBuffer*>>> TrackedBuffersMap;
 
     // Storage for pending (unsent) death notifications for one listener.
     // Each pair in member named "indices" are (frameIndex, bufferIndex) from
@@ -247,6 +243,16 @@
     // Mutex for the management of all input buffers.
     std::mutex mMutex;
 
+    // Cache for all TrackedBuffers.
+    //
+    // Whenever registerOnDestroyNotify() is called, an argument of type
+    // TrackedBuffer is created and stored into this cache.
+    // Whenever unregisterOnDestroyNotify() or onBufferDestroyed() is called,
+    // the TrackedBuffer is removed from this cache.
+    //
+    // mTrackedBuffersMap stores references to TrackedBuffers inside this cache.
+    std::set<TrackedBuffer*> mTrackedBufferCache;
+
     // Tracked input buffers.
     TrackedBuffersMap mTrackedBuffersMap;
 
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
index 29ed7ff..062dcd9 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
@@ -57,30 +57,26 @@
             const sp<IInputSink>& sink,
             connect_cb _hidl_cb) override;
 
+    InputSurface(
+            const std::shared_ptr<ParameterCache>& cache,
+            const std::shared_ptr<C2ReflectorHelper>& reflector,
+            const sp<HGraphicBufferProducer>& base,
+            const sp<GraphicBufferSource>& source);
+
 protected:
 
     class Interface;
     class ConfigurableIntf;
 
-    sp<ComponentStore> mStore;
+    std::shared_ptr<ParameterCache> mParameterCache;
     sp<HGraphicBufferProducer> mProducer;
     sp<GraphicBufferSource> mSource;
     std::shared_ptr<Interface> mIntf;
     sp<CachedConfigurable> mConfigurable;
 
-    InputSurface(
-            const sp<ComponentStore>& store,
-            const std::shared_ptr<C2ReflectorHelper>& reflector,
-            const sp<HGraphicBufferProducer>& base,
-            const sp<GraphicBufferSource>& source);
-
     virtual ~InputSurface() override = default;
-
-    friend struct ComponentStore;
-
 };
 
-
 }  // namespace utils
 }  // namespace V1_0
 }  // namespace c2
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
index 758b6b2..475ce8b 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
@@ -62,12 +62,12 @@
     InputSurfaceConnection(
             const sp<GraphicBufferSource>& source,
             const std::shared_ptr<C2Component>& comp,
-            const sp<ComponentStore>& store);
+            const std::shared_ptr<ParameterCache>& cache);
 
     InputSurfaceConnection(
             const sp<GraphicBufferSource>& source,
             const sp<IInputSink>& sink,
-            const sp<ComponentStore>& store);
+            const std::shared_ptr<ParameterCache>& cache);
 
     bool init();
 
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h
similarity index 78%
rename from media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
rename to media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h
index 0a2298c..80368f7 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/OutputBufferQueue.h
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef CLIENT_BLOCK_HELPER_H
-#define CLIENT_BLOCK_HELPER_H
+#ifndef CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE
+#define CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE
 
 #include <gui/IGraphicBufferProducer.h>
 #include <codec2/hidl/1.0/types.h>
 #include <C2Work.h>
 
+struct C2_HIDE _C2BlockPoolData;
+
 namespace android {
 namespace hardware {
 namespace media {
@@ -61,8 +63,16 @@
 
 private:
 
-    class Impl;
-    std::unique_ptr<Impl> mImpl;
+    std::mutex mMutex;
+    sp<IGraphicBufferProducer> mIgbp;
+    uint32_t mGeneration;
+    uint64_t mBqId;
+    std::shared_ptr<int> mOwner;
+    // To migrate existing buffers
+    sp<GraphicBuffer> mBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS]; // find a better way
+    std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
+
+    bool registerBuffer(const C2ConstGraphicBlock& block);
 };
 
 }  // namespace utils
@@ -72,4 +82,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // CLIENT_BLOCK_HELPER_H
+#endif  // CODEC2_HIDL_V1_0_UTILS_OUTPUT_BUFFER_QUEUE
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 a8a552c..9656eb4 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
@@ -203,7 +203,7 @@
     uint32_t mFramesReceived;
     std::list<uint64_t> mFlushedIndices;
     std::list<uint64_t> mTimestampUslist;
-    ::android::List<outputMetaData> oBufferMetaData;
+    std::list<outputMetaData> oBufferMetaData;
 
     C2BlockPool::local_id_t mBlockPoolId;
     std::shared_ptr<C2BlockPool> mLinearPool;
@@ -547,10 +547,6 @@
     if (mCompName == raw) {
         bitStreamInfo[0] = 8000;
         bitStreamInfo[1] = 1;
-    } else if (mCompName == g711alaw || mCompName == g711mlaw) {
-        // g711 test data is all 1-channel and has no embedded config info.
-        bitStreamInfo[0] = 8000;
-        bitStreamInfo[1] = 1;
     } else {
         ASSERT_NO_FATAL_FAILURE(
             getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
@@ -598,7 +594,7 @@
         int nSampleRate = bitStreamInfo[0];
         int nChannels = bitStreamInfo[1];
         std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
-        android::List<outputMetaData>::iterator itOut = oBufferMetaData.begin();
+        auto itOut = oBufferMetaData.begin();
         EXPECT_EQ(*itIn, itOut->timestampUs);
         expTs = *itIn;
         while (itOut != oBufferMetaData.end()) {
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 d73b731..2f02913 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
@@ -20,6 +20,13 @@
 
 #include "media_c2_hidl_test_common.h"
 
+#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,
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 db59e54..23e332a 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
@@ -17,32 +17,23 @@
 #ifndef MEDIA_C2_HIDL_TEST_COMMON_H
 #define MEDIA_C2_HIDL_TEST_COMMON_H
 
-#include <codec2/hidl/client.h>
-
-#include <android/hardware/media/c2/1.0/types.h>
-
 #include <C2Component.h>
 #include <C2Config.h>
+
+#include <codec2/hidl/client.h>
 #include <getopt.h>
 #include <hidl/HidlSupport.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/Mutexed.h>
-
-using namespace ::android::hardware::media::c2::V1_0;
-using namespace ::android::hardware::media::c2::V1_0::utils;
-
-using ::android::Mutexed;
-using ::android::hardware::Void;
-using ::android::hardware::Return;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-
 #include <VtsHalHidlTargetTestEnvBase.h>
 
 #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;
+
 /*
  * Handle Callback functions onWorkDone(), onTripped(),
  * onError(), onDeath(), onFramesRendered()
@@ -114,9 +105,7 @@
     typedef ::testing::VtsHalHidlTargetTestEnvBase Super;
 
    public:
-    virtual void registerTestServices() override {
-        registerTestService<IComponentStore>();
-    }
+    virtual void registerTestServices() override;
 
     ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
 
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 be35b02..b737323 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
@@ -18,6 +18,14 @@
     name: "VtsHalMediaC2V1_0TargetVideoDecTest",
     defaults: ["VtsHalMediaC2V1_0Defaults"],
     srcs: ["VtsHalMediaC2V1_0TargetVideoDecTest.cpp"],
+    header_libs: [
+        "libnativewindow_headers",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libgui",
+        "libutils",
+    ],
 }
 
 cc_test {
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 5e28750..9404aa8 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
@@ -28,6 +28,10 @@
 #include <C2Debug.h>
 #include <C2Buffer.h>
 #include <C2BufferPriv.h>
+#include <gui/BufferQueue.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
+#include <system/window.h>
 
 using android::C2AllocatorIon;
 
@@ -426,6 +430,48 @@
     ASSERT_EQ(mDisableTest, false);
 }
 
+TEST_F(Codec2VideoDecHidlTest, configureTunnel) {
+    description("Attempts to configure tunneling");
+    if (mDisableTest) return;
+    ALOGV("Checks if the component can be configured for tunneling");
+    native_handle_t* sidebandStream{};
+    c2_status_t err = mComponent->configureVideoTunnel(0, &sidebandStream);
+    if (err == C2_OMITTED) {
+        return;
+    }
+
+    using namespace android;
+    sp<NativeHandle> nativeHandle = NativeHandle::create(sidebandStream, true);
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+
+    class DummyConsumerListener : public BnConsumerListener {
+    public:
+        DummyConsumerListener() : BnConsumerListener() {}
+        void onFrameAvailable(const BufferItem&) override {}
+        void onBuffersReleased() override {}
+        void onSidebandStreamChanged() override {}
+    };
+    consumer->consumerConnect(new DummyConsumerListener(), false);
+
+    class DummyProducerListener : public BnProducerListener {
+    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);
+
+    ASSERT_EQ(producer->setSidebandStream(nativeHandle), NO_ERROR);
+}
+
 class Codec2VideoDecDecodeTest
     : public Codec2VideoDecHidlTest,
       public ::testing::WithParamInterface<std::pair<int32_t, bool>> {
diff --git a/media/codec2/hidl/1.1/utils/Android.bp b/media/codec2/hidl/1.1/utils/Android.bp
new file mode 100644
index 0000000..d48197b
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/Android.bp
@@ -0,0 +1,154 @@
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-client-defaults instead
+cc_library {
+    name: "libcodec2_hidl_client@1.1",
+
+    defaults: ["hidl_defaults"],
+
+    srcs: [
+        "OutputBufferQueue.cpp",
+        "types.cpp",
+    ],
+
+    header_libs: [
+        "libcodec2_internal", // private
+    ],
+
+    shared_libs: [
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
+        "libbase",
+        "libcodec2",
+        "libcodec2_hidl_client@1.0",
+        "libcodec2_vndk",
+        "libcutils",
+        "libgui",
+        "libhidlbase",
+        "liblog",
+        "libstagefright_bufferpool@2.0.1",
+        "libui",
+        "libutils",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    export_shared_lib_headers: [
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
+        "libcodec2",
+        "libcodec2_hidl_client@1.0",
+        "libgui",
+        "libstagefright_bufferpool@2.0.1",
+        "libui",
+    ],
+}
+
+
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-defaults instead
+cc_library {
+    name: "libcodec2_hidl@1.1",
+    vendor_available: true,
+
+    defaults: ["hidl_defaults"],
+
+    srcs: [
+        "Component.cpp",
+        "ComponentInterface.cpp",
+        "ComponentStore.cpp",
+        "Configurable.cpp",
+        "InputBufferManager.cpp",
+        "InputSurface.cpp",
+        "InputSurfaceConnection.cpp",
+        "types.cpp",
+    ],
+
+    header_libs: [
+        "libbinder_headers",
+        "libsystem_headers",
+        "libcodec2_internal", // private
+    ],
+
+    shared_libs: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.media@1.0",
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
+        "android.hardware.media.omx@1.0",
+        "libbase",
+        "libcodec2",
+        "libcodec2_hidl@1.0",
+        "libcodec2_vndk",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libstagefright_bufferpool@2.0.1",
+        "libstagefright_bufferqueue_helper",
+        "libui",
+        "libutils",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    export_shared_lib_headers: [
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
+        "libcodec2",
+        "libcodec2_hidl@1.0",
+        "libcodec2_vndk",
+        "libhidlbase",
+        "libstagefright_bufferpool@2.0.1",
+        "libstagefright_bufferqueue_helper",
+        "libui",
+    ],
+}
+
+// public dependency for Codec 2.0 HAL service implementations
+cc_defaults {
+    name: "libcodec2-hidl-defaults@1.1",
+    defaults: ["libcodec2-impl-defaults"],
+
+    shared_libs: [
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
+        "libcodec2_hidl@1.0",
+        "libcodec2_hidl@1.1",
+        "libcodec2_vndk",
+        "libhidlbase",
+    ],
+}
+
+// public dependency for Codec 2.0 HAL client
+cc_defaults {
+    name: "libcodec2-hidl-client-defaults@1.1",
+    defaults: ["libcodec2-impl-defaults"],
+
+    shared_libs: [
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
+        "libcodec2_hidl_client@1.0",
+        "libcodec2_hidl_client@1.1",
+        "libcodec2_vndk",
+        "libhidlbase",
+    ],
+}
+
+// Alias to the latest "defaults" for Codec 2.0 HAL service implementations
+cc_defaults {
+    name: "libcodec2-hidl-defaults",
+    defaults: ["libcodec2-hidl-defaults@1.1"],
+}
+
+// Alias to the latest "defaults" for Codec 2.0 HAL client
+cc_defaults {
+    name: "libcodec2-hidl-client-defaults",
+    defaults: ["libcodec2-hidl-client-defaults@1.1"],
+}
diff --git a/media/codec2/hidl/1.1/utils/Component.cpp b/media/codec2/hidl/1.1/utils/Component.cpp
new file mode 100644
index 0000000..ed281e6
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/Component.cpp
@@ -0,0 +1,493 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-Component@1.1"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.1/Component.h>
+#include <codec2/hidl/1.1/ComponentStore.h>
+#include <codec2/hidl/1.1/InputBufferManager.h>
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using namespace ::android;
+
+// ComponentListener wrapper
+struct Component::Listener : public C2Component::Listener {
+
+    Listener(const sp<Component>& component) :
+        mComponent(component),
+        mListener(component->mListener) {
+    }
+
+    virtual void onError_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            uint32_t errorCode) override {
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            Return<void> transStatus = listener->onError(Status::OK, errorCode);
+            if (!transStatus.isOk()) {
+                LOG(ERROR) << "Component::Listener::onError_nb -- "
+                           << "transaction failed.";
+            }
+        }
+    }
+
+    virtual void onTripped_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+            ) override {
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            hidl_vec<SettingResult> settingResults(c2settingResult.size());
+            size_t ix = 0;
+            for (const std::shared_ptr<C2SettingResult> &c2result :
+                    c2settingResult) {
+                if (c2result) {
+                    if (!objcpy(&settingResults[ix++], *c2result)) {
+                        break;
+                    }
+                }
+            }
+            settingResults.resize(ix);
+            Return<void> transStatus = listener->onTripped(settingResults);
+            if (!transStatus.isOk()) {
+                LOG(ERROR) << "Component::Listener::onTripped_nb -- "
+                           << "transaction failed.";
+            }
+        }
+    }
+
+    virtual void onWorkDone_nb(
+            std::weak_ptr<C2Component> /* c2component */,
+            std::list<std::unique_ptr<C2Work>> c2workItems) override {
+        for (const std::unique_ptr<C2Work>& work : c2workItems) {
+            if (work) {
+                if (work->worklets.empty()
+                        || !work->worklets.back()
+                        || (work->worklets.back()->output.flags &
+                            C2FrameData::FLAG_INCOMPLETE) == 0) {
+                    InputBufferManager::
+                            unregisterFrameData(mListener, work->input);
+                }
+            }
+        }
+
+        sp<IComponentListener> listener = mListener.promote();
+        if (listener) {
+            WorkBundle workBundle;
+
+            sp<Component> strongComponent = mComponent.promote();
+            beginTransferBufferQueueBlocks(c2workItems, true);
+            if (!objcpy(&workBundle, c2workItems, strongComponent ?
+                    &strongComponent->mBufferPoolSender : nullptr)) {
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "received corrupted work items.";
+                endTransferBufferQueueBlocks(c2workItems, false, true);
+                return;
+            }
+            Return<void> transStatus = listener->onWorkDone(workBundle);
+            if (!transStatus.isOk()) {
+                LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+                           << "transaction failed.";
+                endTransferBufferQueueBlocks(c2workItems, false, true);
+                return;
+            }
+            endTransferBufferQueueBlocks(c2workItems, true, true);
+        }
+    }
+
+protected:
+    wp<Component> mComponent;
+    wp<IComponentListener> mListener;
+};
+
+// Component::Sink
+struct Component::Sink : public IInputSink {
+    std::shared_ptr<Component> mComponent;
+    sp<IConfigurable> mConfigurable;
+
+    virtual Return<Status> queue(const WorkBundle& workBundle) override {
+        return mComponent->queue(workBundle);
+    }
+
+    virtual Return<sp<IConfigurable>> getConfigurable() override {
+        return mConfigurable;
+    }
+
+    Sink(const std::shared_ptr<Component>& component);
+    virtual ~Sink() override;
+
+    // Process-wide map: Component::Sink -> C2Component.
+    static std::mutex sSink2ComponentMutex;
+    static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
+
+    static std::shared_ptr<C2Component> findLocalComponent(
+            const sp<IInputSink>& sink);
+};
+
+std::mutex
+        Component::Sink::sSink2ComponentMutex{};
+std::map<IInputSink*, std::weak_ptr<C2Component>>
+        Component::Sink::sSink2Component{};
+
+Component::Sink::Sink(const std::shared_ptr<Component>& component)
+        : mComponent{component},
+          mConfigurable{[&component]() -> sp<IConfigurable> {
+              Return<sp<IComponentInterface>> ret1 = component->getInterface();
+              if (!ret1.isOk()) {
+                  LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
+                  return nullptr;
+              }
+              Return<sp<IConfigurable>> ret2 =
+                      static_cast<sp<IComponentInterface>>(ret1)->
+                      getConfigurable();
+              if (!ret2.isOk()) {
+                  LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
+                  return nullptr;
+              }
+              return static_cast<sp<IConfigurable>>(ret2);
+          }()} {
+    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+    sSink2Component.emplace(this, component->mComponent);
+}
+
+Component::Sink::~Sink() {
+    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+    sSink2Component.erase(this);
+}
+
+std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
+        const sp<IInputSink>& sink) {
+    std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+    auto i = sSink2Component.find(sink.get());
+    if (i == sSink2Component.end()) {
+        return nullptr;
+    }
+    return i->second.lock();
+}
+
+// Component
+Component::Component(
+        const std::shared_ptr<C2Component>& component,
+        const sp<IComponentListener>& listener,
+        const sp<ComponentStore>& store,
+        const sp<::android::hardware::media::bufferpool::V2_0::
+        IClientManager>& clientPoolManager)
+      : mComponent{component},
+        mInterface{new ComponentInterface(component->intf(),
+                                          store->getParameterCache())},
+        mListener{listener},
+        mStore{store},
+        mBufferPoolSender{clientPoolManager} {
+    // Retrieve supported parameters from store
+    // TODO: We could cache this per component/interface type
+    mInit = mInterface->status();
+}
+
+c2_status_t Component::status() const {
+    return mInit;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponent
+Return<Status> Component::queue(const WorkBundle& workBundle) {
+    std::list<std::unique_ptr<C2Work>> c2works;
+
+    if (!objcpy(&c2works, workBundle)) {
+        return Status::CORRUPTED;
+    }
+
+    // Register input buffers.
+    for (const std::unique_ptr<C2Work>& work : c2works) {
+        if (work) {
+            InputBufferManager::
+                    registerFrameData(mListener, work->input);
+        }
+    }
+
+    return static_cast<Status>(mComponent->queue_nb(&c2works));
+}
+
+Return<void> Component::flush(flush_cb _hidl_cb) {
+    std::list<std::unique_ptr<C2Work>> c2flushedWorks;
+    c2_status_t c2res = mComponent->flush_sm(
+            C2Component::FLUSH_COMPONENT,
+            &c2flushedWorks);
+
+    // Unregister input buffers.
+    for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
+        if (work) {
+            if (work->worklets.empty()
+                    || !work->worklets.back()
+                    || (work->worklets.back()->output.flags &
+                        C2FrameData::FLAG_INCOMPLETE) == 0) {
+                InputBufferManager::
+                        unregisterFrameData(mListener, work->input);
+            }
+        }
+    }
+
+    WorkBundle flushedWorkBundle;
+    Status res = static_cast<Status>(c2res);
+    beginTransferBufferQueueBlocks(c2flushedWorks, true);
+    if (c2res == C2_OK) {
+        if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+            res = Status::CORRUPTED;
+        }
+    }
+    _hidl_cb(res, flushedWorkBundle);
+    endTransferBufferQueueBlocks(c2flushedWorks, true, true);
+    return Void();
+}
+
+Return<Status> Component::drain(bool withEos) {
+    return static_cast<Status>(mComponent->drain_nb(withEos ?
+            C2Component::DRAIN_COMPONENT_WITH_EOS :
+            C2Component::DRAIN_COMPONENT_NO_EOS));
+}
+
+Return<Status> Component::setOutputSurface(
+        uint64_t blockPoolId,
+        const sp<HGraphicBufferProducer2>& surface) {
+    std::shared_ptr<C2BlockPool> pool;
+    GetCodec2BlockPool(blockPoolId, mComponent, &pool);
+    if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+        std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+                std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
+        C2BufferQueueBlockPool::OnRenderCallback cb =
+            [this](uint64_t producer, int32_t slot, int64_t nsecs) {
+                // TODO: batch this
+                hidl_vec<IComponentListener::RenderedFrame> rendered;
+                rendered.resize(1);
+                rendered[0] = { producer, slot, nsecs };
+                (void)mListener->onFramesRendered(rendered).isOk();
+        };
+        if (bqPool) {
+            bqPool->setRenderCallback(cb);
+            bqPool->configureProducer(surface);
+        }
+    }
+    return Status::OK;
+}
+
+Return<void> Component::connectToInputSurface(
+        const sp<IInputSurface>& inputSurface,
+        connectToInputSurface_cb _hidl_cb) {
+    Status status;
+    sp<IInputSurfaceConnection> connection;
+    auto transStatus = inputSurface->connect(
+            asInputSink(),
+            [&status, &connection](
+                    Status s, const sp<IInputSurfaceConnection>& c) {
+                status = s;
+                connection = c;
+            }
+        );
+    _hidl_cb(status, connection);
+    return Void();
+}
+
+Return<void> Component::connectToOmxInputSurface(
+        const sp<HGraphicBufferProducer1>& producer,
+        const sp<::android::hardware::media::omx::V1_0::
+        IGraphicBufferSource>& source,
+        connectToOmxInputSurface_cb _hidl_cb) {
+    (void)producer;
+    (void)source;
+    (void)_hidl_cb;
+    return Void();
+}
+
+Return<Status> Component::disconnectFromInputSurface() {
+    // TODO implement
+    return Status::OK;
+}
+
+namespace /* unnamed */ {
+
+struct BlockPoolIntf : public ConfigurableC2Intf {
+    BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
+          : ConfigurableC2Intf{
+                "C2BlockPool:" +
+                    (pool ? std::to_string(pool->getLocalId()) : "null"),
+                0},
+            mPool{pool} {
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*>& params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        (void)params;
+        (void)mayBlock;
+        (void)failures;
+        return C2_OK;
+    }
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index>& indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>>* const params
+            ) const override {
+        (void)indices;
+        (void)mayBlock;
+        (void)params;
+        return C2_OK;
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+            ) const override {
+        (void)params;
+        return C2_OK;
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery>& fields,
+            c2_blocking_t mayBlock) const override {
+        (void)fields;
+        (void)mayBlock;
+        return C2_OK;
+    }
+
+protected:
+    std::shared_ptr<C2BlockPool> mPool;
+};
+
+} // unnamed namespace
+
+Return<void> Component::createBlockPool(
+        uint32_t allocatorId,
+        createBlockPool_cb _hidl_cb) {
+    std::shared_ptr<C2BlockPool> blockPool;
+    c2_status_t status = CreateCodec2BlockPool(
+            static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
+            mComponent,
+            &blockPool);
+    if (status != C2_OK) {
+        blockPool = nullptr;
+    }
+    if (blockPool) {
+        mBlockPoolsMutex.lock();
+        mBlockPools.emplace(blockPool->getLocalId(), blockPool);
+        mBlockPoolsMutex.unlock();
+    } else if (status == C2_OK) {
+        status = C2_CORRUPTED;
+    }
+
+    _hidl_cb(static_cast<Status>(status),
+            blockPool ? blockPool->getLocalId() : 0,
+            new CachedConfigurable(
+            std::make_unique<BlockPoolIntf>(blockPool)));
+    return Void();
+}
+
+Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
+    std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+    return mBlockPools.erase(blockPoolId) == 1 ?
+            Status::OK : Status::CORRUPTED;
+}
+
+Return<Status> Component::start() {
+    return static_cast<Status>(mComponent->start());
+}
+
+Return<Status> Component::stop() {
+    InputBufferManager::unregisterFrameData(mListener);
+    return static_cast<Status>(mComponent->stop());
+}
+
+Return<Status> Component::reset() {
+    Status status = static_cast<Status>(mComponent->reset());
+    {
+        std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+        mBlockPools.clear();
+    }
+    InputBufferManager::unregisterFrameData(mListener);
+    return status;
+}
+
+Return<Status> Component::release() {
+    Status status = static_cast<Status>(mComponent->release());
+    {
+        std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+        mBlockPools.clear();
+    }
+    InputBufferManager::unregisterFrameData(mListener);
+    return status;
+}
+
+Return<sp<IComponentInterface>> Component::getInterface() {
+    return sp<IComponentInterface>(mInterface);
+}
+
+Return<sp<IInputSink>> Component::asInputSink() {
+    std::lock_guard<std::mutex> lock(mSinkMutex);
+    if (!mSink) {
+        mSink = new Sink(shared_from_this());
+    }
+    return {mSink};
+}
+
+Return<void> Component::configureVideoTunnel(
+        uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
+    (void)avSyncHwId;
+    _hidl_cb(Status::OMITTED, hidl_handle{});
+    return Void();
+}
+
+std::shared_ptr<C2Component> Component::findLocalComponent(
+        const sp<IInputSink>& sink) {
+    return Component::Sink::findLocalComponent(sink);
+}
+
+void Component::initListener(const sp<Component>& self) {
+    std::shared_ptr<C2Component::Listener> c2listener =
+            std::make_shared<Listener>(self);
+    c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
+    if (res != C2_OK) {
+        mInit = res;
+    }
+}
+
+Component::~Component() {
+    InputBufferManager::unregisterFrameData(mListener);
+    mStore->reportComponentDeath(this);
+}
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hidl/1.1/utils/ComponentInterface.cpp b/media/codec2/hidl/1.1/utils/ComponentInterface.cpp
new file mode 100644
index 0000000..ccc30fe
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/ComponentInterface.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <codec2/hidl/1.1/ComponentInterface.h>
diff --git a/media/codec2/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hidl/1.1/utils/ComponentStore.cpp
new file mode 100644
index 0000000..225cd09
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/ComponentStore.cpp
@@ -0,0 +1,499 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-ComponentStore@1.1"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.1/ComponentStore.h>
+#include <codec2/hidl/1.1/InputSurface.h>
+#include <codec2/hidl/1.1/types.h>
+
+#include <android-base/file.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <utils/Errors.h>
+
+#include <C2PlatformSupport.h>
+#include <util/C2InterfaceHelper.h>
+
+#include <chrono>
+#include <ctime>
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using namespace ::android;
+using ::android::GraphicBufferSource;
+using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
+
+namespace /* unnamed */ {
+
+struct StoreIntf : public ConfigurableC2Intf {
+    StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
+          : ConfigurableC2Intf{store ? store->getName() : "", 0},
+            mStore{store} {
+    }
+
+    virtual c2_status_t config(
+            const std::vector<C2Param*> &params,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2SettingResult>> *const failures
+            ) override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->config_sm(params, failures);
+    }
+
+    virtual c2_status_t query(
+            const std::vector<C2Param::Index> &indices,
+            c2_blocking_t mayBlock,
+            std::vector<std::unique_ptr<C2Param>> *const params) const override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->query_sm({}, indices, params);
+    }
+
+    virtual c2_status_t querySupportedParams(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+            ) const override {
+        return mStore->querySupportedParams_nb(params);
+    }
+
+    virtual c2_status_t querySupportedValues(
+            std::vector<C2FieldSupportedValuesQuery> &fields,
+            c2_blocking_t mayBlock) const override {
+        // Assume all params are blocking
+        // TODO: Filter for supported params
+        if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
+            return C2_BLOCKING;
+        }
+        return mStore->querySupportedValues_sm(fields);
+    }
+
+protected:
+    std::shared_ptr<C2ComponentStore> mStore;
+};
+
+} // unnamed namespace
+
+struct ComponentStore::StoreParameterCache : public ParameterCache {
+    std::mutex mStoreMutex;
+    ComponentStore* mStore;
+
+    StoreParameterCache(ComponentStore* store): mStore{store} {
+    }
+
+    virtual c2_status_t validate(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
+            ) override {
+        std::scoped_lock _lock(mStoreMutex);
+        return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
+    }
+
+    void onStoreDestroyed() {
+        std::scoped_lock _lock(mStoreMutex);
+        mStore = nullptr;
+    }
+};
+
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
+      : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+        mParameterCache{std::make_shared<StoreParameterCache>(this)},
+        mStore{store} {
+
+    std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
+    SetPreferredCodec2ComponentStore(store);
+
+    // Retrieve struct descriptors
+    mParamReflector = mStore->getParamReflector();
+
+    // Retrieve supported parameters from store
+    using namespace std::placeholders;
+    mInit = mConfigurable->init(mParameterCache);
+}
+
+ComponentStore::~ComponentStore() {
+    mParameterCache->onStoreDestroyed();
+}
+
+c2_status_t ComponentStore::status() const {
+    return mInit;
+}
+
+c2_status_t ComponentStore::validateSupportedParams(
+        const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
+    c2_status_t res = C2_OK;
+
+    for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
+        if (!desc) {
+            // All descriptors should be valid
+            res = res ? res : C2_BAD_VALUE;
+            continue;
+        }
+        C2Param::CoreIndex coreIndex = desc->index().coreIndex();
+        std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+        auto it = mStructDescriptors.find(coreIndex);
+        if (it == mStructDescriptors.end()) {
+            std::shared_ptr<C2StructDescriptor> structDesc =
+                    mParamReflector->describe(coreIndex);
+            if (!structDesc) {
+                // All supported params must be described
+                res = C2_BAD_INDEX;
+            }
+            mStructDescriptors.insert({ coreIndex, structDesc });
+        }
+    }
+    return res;
+}
+
+std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
+    return mParameterCache;
+}
+
+// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
+Return<void> ComponentStore::createComponent(
+        const hidl_string& name,
+        const sp<IComponentListener>& listener,
+        const sp<IClientManager>& pool,
+        createComponent_cb _hidl_cb) {
+
+    sp<Component> component;
+    std::shared_ptr<C2Component> c2component;
+    Status status = static_cast<Status>(
+            mStore->createComponent(name, &c2component));
+
+    if (status == Status::OK) {
+        onInterfaceLoaded(c2component->intf());
+        component = new Component(c2component, listener, this, pool);
+        if (!component) {
+            status = Status::CORRUPTED;
+        } else {
+            reportComponentBirth(component.get());
+            if (component->status() != C2_OK) {
+                status = static_cast<Status>(component->status());
+            } else {
+                component->initListener(component);
+                if (component->status() != C2_OK) {
+                    status = static_cast<Status>(component->status());
+                }
+            }
+        }
+    }
+    _hidl_cb(status, component);
+    return Void();
+}
+
+Return<void> ComponentStore::createInterface(
+        const hidl_string& name,
+        createInterface_cb _hidl_cb) {
+    std::shared_ptr<C2ComponentInterface> c2interface;
+    c2_status_t res = mStore->createInterface(name, &c2interface);
+    sp<IComponentInterface> interface;
+    if (res == C2_OK) {
+        onInterfaceLoaded(c2interface);
+        interface = new ComponentInterface(c2interface, mParameterCache);
+    }
+    _hidl_cb(static_cast<Status>(res), interface);
+    return Void();
+}
+
+Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) {
+    std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
+            mStore->listComponents();
+    hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size());
+    size_t ix = 0;
+    for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
+        if (c2trait) {
+            if (objcpy(&traits[ix], *c2trait)) {
+                ++ix;
+            } else {
+                break;
+            }
+        }
+    }
+    traits.resize(ix);
+    _hidl_cb(Status::OK, traits);
+    return Void();
+}
+
+Return<void> ComponentStore::createInputSurface(createInputSurface_cb _hidl_cb) {
+    sp<GraphicBufferSource> source = new GraphicBufferSource();
+    if (source->initCheck() != OK) {
+        _hidl_cb(Status::CORRUPTED, nullptr);
+        return Void();
+    }
+    using namespace std::placeholders;
+    sp<InputSurface> inputSurface = new InputSurface(
+            mParameterCache,
+            std::make_shared<C2ReflectorHelper>(),
+            source->getHGraphicBufferProducer(),
+            source);
+    _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
+             inputSurface);
+    return Void();
+}
+
+void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
+    // invalidate unsupported struct descriptors if a new interface is loaded as it may have
+    // exposed new descriptors
+    std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+    if (!mLoadedInterfaces.count(intf->getName())) {
+        mUnsupportedStructDescriptors.clear();
+        mLoadedInterfaces.emplace(intf->getName());
+    }
+}
+
+Return<void> ComponentStore::getStructDescriptors(
+        const hidl_vec<uint32_t>& indices,
+        getStructDescriptors_cb _hidl_cb) {
+    hidl_vec<StructDescriptor> descriptors(indices.size());
+    size_t dstIx = 0;
+    Status res = Status::OK;
+    for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
+        std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+        const C2Param::CoreIndex coreIndex = C2Param::CoreIndex(indices[srcIx]).coreIndex();
+        const auto item = mStructDescriptors.find(coreIndex);
+        if (item == mStructDescriptors.end()) {
+            // not in the cache, and not known to be unsupported, query local reflector
+            if (!mUnsupportedStructDescriptors.count(coreIndex)) {
+                std::shared_ptr<C2StructDescriptor> structDesc =
+                    mParamReflector->describe(coreIndex);
+                if (!structDesc) {
+                    mUnsupportedStructDescriptors.emplace(coreIndex);
+                } else {
+                    mStructDescriptors.insert({ coreIndex, structDesc });
+                    if (objcpy(&descriptors[dstIx], *structDesc)) {
+                        ++dstIx;
+                        continue;
+                    }
+                    res = Status::CORRUPTED;
+                    break;
+                }
+            }
+            res = Status::NOT_FOUND;
+        } else if (item->second) {
+            if (objcpy(&descriptors[dstIx], *item->second)) {
+                ++dstIx;
+                continue;
+            }
+            res = Status::CORRUPTED;
+            break;
+        } else {
+            res = Status::NO_MEMORY;
+            break;
+        }
+    }
+    descriptors.resize(dstIx);
+    _hidl_cb(res, descriptors);
+    return Void();
+}
+
+Return<sp<IClientManager>> ComponentStore::getPoolClientManager() {
+    return ClientManager::getInstance();
+}
+
+Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
+    // TODO implement
+    (void)src;
+    (void)dst;
+    return Status::OMITTED;
+}
+
+Return<sp<IConfigurable>> ComponentStore::getConfigurable() {
+    return mConfigurable;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponentStore
+Return<void> ComponentStore::createComponent_1_1(
+        const hidl_string& name,
+        const sp<IComponentListener>& listener,
+        const sp<IClientManager>& pool,
+        createComponent_1_1_cb _hidl_cb) {
+
+    sp<Component> component;
+    std::shared_ptr<C2Component> c2component;
+    Status status = static_cast<Status>(
+            mStore->createComponent(name, &c2component));
+
+    if (status == Status::OK) {
+        onInterfaceLoaded(c2component->intf());
+        component = new Component(c2component, listener, this, pool);
+        if (!component) {
+            status = Status::CORRUPTED;
+        } else {
+            reportComponentBirth(component.get());
+            if (component->status() != C2_OK) {
+                status = static_cast<Status>(component->status());
+            } else {
+                component->initListener(component);
+                if (component->status() != C2_OK) {
+                    status = static_cast<Status>(component->status());
+                }
+            }
+        }
+    }
+    _hidl_cb(status, component);
+    return Void();
+}
+
+// Called from createComponent() after a successful creation of `component`.
+void ComponentStore::reportComponentBirth(Component* component) {
+    ComponentStatus componentStatus;
+    componentStatus.c2Component = component->mComponent;
+    componentStatus.birthTime = std::chrono::system_clock::now();
+
+    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+    mComponentRoster.emplace(component, componentStatus);
+}
+
+// Called from within the destructor of `component`. No virtual function calls
+// are made on `component` here.
+void ComponentStore::reportComponentDeath(Component* component) {
+    std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+    mComponentRoster.erase(component);
+}
+
+// Dumps component traits.
+std::ostream& ComponentStore::dump(
+        std::ostream& out,
+        const std::shared_ptr<const C2Component::Traits>& comp) {
+
+    constexpr const char indent[] = "    ";
+
+    out << indent << "name: " << comp->name << std::endl;
+    out << indent << "domain: " << comp->domain << std::endl;
+    out << indent << "kind: " << comp->kind << std::endl;
+    out << indent << "rank: " << comp->rank << std::endl;
+    out << indent << "mediaType: " << comp->mediaType << std::endl;
+    out << indent << "aliases:";
+    for (const auto& alias : comp->aliases) {
+        out << ' ' << alias;
+    }
+    out << std::endl;
+
+    return out;
+}
+
+// Dumps component status.
+std::ostream& ComponentStore::dump(
+        std::ostream& out,
+        ComponentStatus& compStatus) {
+
+    constexpr const char indent[] = "    ";
+
+    // Print birth time.
+    std::chrono::milliseconds ms =
+            std::chrono::duration_cast<std::chrono::milliseconds>(
+                compStatus.birthTime.time_since_epoch());
+    std::time_t birthTime = std::chrono::system_clock::to_time_t(
+            compStatus.birthTime);
+    std::tm tm = *std::localtime(&birthTime);
+    out << indent << "Creation time: "
+        << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
+        << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
+        << std::endl;
+
+    // Print name and id.
+    std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
+    if (!intf) {
+        out << indent << "Unknown component -- null interface" << std::endl;
+        return out;
+    }
+    out << indent << "Name: " << intf->getName() << std::endl;
+    out << indent << "Id: " << intf->getId() << std::endl;
+
+    return out;
+}
+
+// Dumps information when lshal is called.
+Return<void> ComponentStore::debug(
+        const hidl_handle& handle,
+        const hidl_vec<hidl_string>& /* args */) {
+    LOG(INFO) << "debug -- dumping...";
+    const native_handle_t *h = handle.getNativeHandle();
+    if (!h || h->numFds != 1) {
+       LOG(ERROR) << "debug -- dumping failed -- "
+               "invalid file descriptor to dump to";
+       return Void();
+    }
+    std::ostringstream out;
+
+    { // Populate "out".
+
+        constexpr const char indent[] = "  ";
+
+        // Show name.
+        out << "Beginning of dump -- C2ComponentStore: "
+                << mStore->getName() << std::endl << std::endl;
+
+        // Retrieve the list of supported components.
+        std::vector<std::shared_ptr<const C2Component::Traits>> traitsList =
+                mStore->listComponents();
+
+        // Dump the traits of supported components.
+        out << indent << "Supported components:" << std::endl << std::endl;
+        if (traitsList.size() == 0) {
+            out << indent << indent << "NONE" << std::endl << std::endl;
+        } else {
+            for (const auto& traits : traitsList) {
+                dump(out, traits) << std::endl;
+            }
+        }
+
+        // Dump active components.
+        {
+            out << indent << "Active components:" << std::endl << std::endl;
+            std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+            if (mComponentRoster.size() == 0) {
+                out << indent << indent << "NONE" << std::endl << std::endl;
+            } else {
+                for (auto& pair : mComponentRoster) {
+                    dump(out, pair.second) << std::endl;
+                }
+            }
+        }
+
+        out << "End of dump -- C2ComponentStore: "
+                << mStore->getName() << std::endl;
+    }
+
+    if (!android::base::WriteStringToFd(out.str(), h->data[0])) {
+        PLOG(WARNING) << "debug -- dumping failed -- write()";
+    } else {
+        LOG(INFO) << "debug -- dumping succeeded";
+    }
+    return Void();
+}
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hidl/1.1/utils/Configurable.cpp b/media/codec2/hidl/1.1/utils/Configurable.cpp
new file mode 100644
index 0000000..1f3b2c7
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/Configurable.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <codec2/hidl/1.1/Configurable.h>
diff --git a/media/codec2/hidl/1.1/utils/InputBufferManager.cpp b/media/codec2/hidl/1.1/utils/InputBufferManager.cpp
new file mode 100644
index 0000000..45bfc86
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/InputBufferManager.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <codec2/hidl/1.1/InputBufferManager.h>
diff --git a/media/codec2/hidl/1.1/utils/InputSurface.cpp b/media/codec2/hidl/1.1/utils/InputSurface.cpp
new file mode 100644
index 0000000..ce40494
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/InputSurface.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <codec2/hidl/1.1/InputSurface.h>
diff --git a/media/codec2/hidl/1.1/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.1/utils/InputSurfaceConnection.cpp
new file mode 100644
index 0000000..32154a7
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/InputSurfaceConnection.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <codec2/hidl/1.1/InputSurfaceConnection.h>
diff --git a/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp b/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
new file mode 100644
index 0000000..65756e8
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/OutputBufferQueue.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <codec2/hidl/1.1/OutputBufferQueue.h>
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h
new file mode 100644
index 0000000..16c81d4
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Component.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_COMPONENT_H
+#define CODEC2_HIDL_V1_1_UTILS_COMPONENT_H
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.1/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.1/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <codec2/hidl/1.1/ComponentInterface.h>
+#include <codec2/hidl/1.1/Configurable.h>
+#include <codec2/hidl/1.1/types.h>
+#include <hidl/Status.h>
+#include <hwbinder/IBinder.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+
+using ::android::hardware::media::c2::V1_1::IComponent;
+using ::android::hardware::media::c2::V1_0::IComponentListener;
+
+namespace utils {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::IBinder;
+using ::android::sp;
+using ::android::wp;
+
+struct ComponentStore;
+
+struct Component : public IComponent,
+                   public std::enable_shared_from_this<Component> {
+    Component(
+            const std::shared_ptr<C2Component>&,
+            const sp<IComponentListener>& listener,
+            const sp<ComponentStore>& store,
+            const sp<::android::hardware::media::bufferpool::V2_0::
+                IClientManager>& clientPoolManager);
+    c2_status_t status() const;
+
+    typedef ::android::hardware::graphics::bufferqueue::V1_0::
+            IGraphicBufferProducer HGraphicBufferProducer1;
+    typedef ::android::hardware::graphics::bufferqueue::V2_0::
+            IGraphicBufferProducer HGraphicBufferProducer2;
+
+    // Methods from IComponent follow.
+    virtual Return<Status> queue(const WorkBundle& workBundle) override;
+    virtual Return<void> flush(flush_cb _hidl_cb) override;
+    virtual Return<Status> drain(bool withEos) override;
+    virtual Return<Status> setOutputSurface(
+            uint64_t blockPoolId,
+            const sp<HGraphicBufferProducer2>& surface) override;
+    virtual Return<void> connectToInputSurface(
+            const sp<IInputSurface>& inputSurface,
+            connectToInputSurface_cb _hidl_cb) override;
+    virtual Return<void> connectToOmxInputSurface(
+            const sp<HGraphicBufferProducer1>& producer,
+            const sp<::android::hardware::media::omx::V1_0::
+            IGraphicBufferSource>& source,
+            connectToOmxInputSurface_cb _hidl_cb) override;
+    virtual Return<Status> disconnectFromInputSurface() override;
+    virtual Return<void> createBlockPool(
+            uint32_t allocatorId,
+            createBlockPool_cb _hidl_cb) override;
+    virtual Return<Status> destroyBlockPool(uint64_t blockPoolId) override;
+    virtual Return<Status> start() override;
+    virtual Return<Status> stop() override;
+    virtual Return<Status> reset() override;
+    virtual Return<Status> release() override;
+    virtual Return<sp<IComponentInterface>> getInterface() override;
+    virtual Return<sp<IInputSink>> asInputSink() override;
+    virtual Return<void> configureVideoTunnel(
+            uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) override;
+
+    // Returns a C2Component associated to the given sink if the sink is indeed
+    // a local component. Returns nullptr otherwise.
+    //
+    // This function is used by InputSurface::connect().
+    static std::shared_ptr<C2Component> findLocalComponent(
+            const sp<IInputSink>& sink);
+
+protected:
+    c2_status_t mInit;
+    std::shared_ptr<C2Component> mComponent;
+    sp<ComponentInterface> mInterface;
+    sp<IComponentListener> mListener;
+    sp<ComponentStore> mStore;
+    ::android::hardware::media::c2::V1_1::utils::DefaultBufferPoolSender
+            mBufferPoolSender;
+
+    struct Sink;
+    std::mutex mSinkMutex;
+    sp<Sink> mSink;
+
+    std::mutex mBlockPoolsMutex;
+    // This map keeps C2BlockPool objects that are created by createBlockPool()
+    // alive. These C2BlockPool objects can be deleted by calling
+    // destroyBlockPool(), reset() or release(), or by destroying the component.
+    std::map<uint64_t, std::shared_ptr<C2BlockPool>> mBlockPools;
+
+    void initListener(const sp<Component>& self);
+
+    virtual ~Component() override;
+
+    friend struct ComponentStore;
+
+    struct Listener;
+};
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_COMPONENT_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentInterface.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentInterface.h
new file mode 100644
index 0000000..723c5bd
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentInterface.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_COMPONENT_INTERFACE_H
+#define CODEC2_HIDL_V1_1_UTILS_COMPONENT_INTERFACE_H
+
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::ComponentInterface;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_COMPONENT_INTERFACE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
new file mode 100644
index 0000000..1f04391
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_COMPONENT_STORE_H
+#define CODEC2_HIDL_V1_1_UTILS_COMPONENT_STORE_H
+
+#include <codec2/hidl/1.1/Component.h>
+#include <codec2/hidl/1.1/ComponentInterface.h>
+#include <codec2/hidl/1.1/Configurable.h>
+#include <codec2/hidl/1.1/types.h>
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.1/IComponentStore.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <chrono>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::bufferpool::V2_0::IClientManager;
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore : public IComponentStore {
+    ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
+    virtual ~ComponentStore();
+
+    /**
+     * Returns the status of the construction of this object.
+     */
+    c2_status_t status() const;
+
+    /**
+     * This function is called by CachedConfigurable::init() to validate
+     * supported parameters.
+     */
+    c2_status_t validateSupportedParams(
+            const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
+
+    /**
+     * Returns the store's ParameterCache. This is used for validation by
+     * Configurable::init().
+     */
+    std::shared_ptr<ParameterCache> getParameterCache() const;
+
+    // Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
+    virtual Return<void> createComponent(
+            const hidl_string& name,
+            const sp<IComponentListener>& listener,
+            const sp<IClientManager>& pool,
+            createComponent_cb _hidl_cb) override;
+    virtual Return<void> createInterface(
+            const hidl_string& name,
+            createInterface_cb _hidl_cb) override;
+    virtual Return<void> listComponents(listComponents_cb _hidl_cb) override;
+    virtual Return<void> createInputSurface(
+            createInputSurface_cb _hidl_cb) override;
+    virtual Return<void> getStructDescriptors(
+            const hidl_vec<uint32_t>& indices,
+            getStructDescriptors_cb _hidl_cb) override;
+    virtual Return<sp<IClientManager>> getPoolClientManager() override;
+    virtual Return<Status> copyBuffer(
+            const Buffer& src,
+            const Buffer& dst) override;
+    virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+    // Methods from ::android::hardware::media::c2::V1_1::IComponentStore.
+    virtual Return<void> createComponent_1_1(
+            const hidl_string& name,
+            const sp<IComponentListener>& listener,
+            const sp<IClientManager>& pool,
+            createComponent_1_1_cb _hidl_cb) override;
+
+    /**
+     * Dumps information when lshal is called.
+     */
+    virtual Return<void> debug(
+            const hidl_handle& handle,
+            const hidl_vec<hidl_string>& args) override;
+
+protected:
+    sp<CachedConfigurable> mConfigurable;
+    struct StoreParameterCache;
+    std::shared_ptr<StoreParameterCache> mParameterCache;
+
+    // Does bookkeeping for an interface that has been loaded.
+    void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
+
+    c2_status_t mInit;
+    std::shared_ptr<C2ComponentStore> mStore;
+    std::shared_ptr<C2ParamReflector> mParamReflector;
+
+    std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
+    std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
+    std::set<C2String> mLoadedInterfaces;
+    mutable std::mutex mStructDescriptorsMutex;
+
+    // ComponentStore keeps track of live Components.
+
+    struct ComponentStatus {
+        std::shared_ptr<C2Component> c2Component;
+        std::chrono::system_clock::time_point birthTime;
+    };
+
+    mutable std::mutex mComponentRosterMutex;
+    std::map<Component*, ComponentStatus> mComponentRoster;
+
+    // Called whenever Component is created.
+    void reportComponentBirth(Component* component);
+    // Called only from the destructor of Component.
+    void reportComponentDeath(Component* component);
+
+    friend Component;
+
+    // Helper functions for dumping.
+
+    std::ostream& dump(
+            std::ostream& out,
+            const std::shared_ptr<const C2Component::Traits>& comp);
+
+    std::ostream& dump(
+            std::ostream& out,
+            ComponentStatus& compStatus);
+
+};
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_COMPONENT_STORE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Configurable.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Configurable.h
new file mode 100644
index 0000000..fd9091b
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/Configurable.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_CONFIGURABLE_H
+#define CODEC2_HIDL_V1_1_UTILS_CONFIGURABLE_H
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::ConfigurableC2Intf;
+using ::android::hardware::media::c2::V1_0::utils::ParameterCache;
+using ::android::hardware::media::c2::V1_0::utils::CachedConfigurable;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_CONFIGURABLE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputBufferManager.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputBufferManager.h
new file mode 100644
index 0000000..8e7a91b
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputBufferManager.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_INPUT_BUFFER_MANAGER_H
+#define CODEC2_HIDL_V1_1_UTILS_INPUT_BUFFER_MANAGER_H
+
+#include <codec2/hidl/1.0/InputBufferManager.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::InputBufferManager;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_INPUT_BUFFER_MANAGER_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurface.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurface.h
new file mode 100644
index 0000000..59223b7
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurface.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_H
+#define CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_H
+
+#include <codec2/hidl/1.0/InputSurface.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::InputSurface;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurfaceConnection.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurfaceConnection.h
new file mode 100644
index 0000000..7f695ef
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/InputSurfaceConnection.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_CONNECTION_H
+#define CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_CONNECTION_H
+
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::InputSurfaceConnection;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_INPUT_SURFACE_CONNECTION_H
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h
new file mode 100644
index 0000000..f77852d
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/OutputBufferQueue.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
+#define CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
+
+#include <codec2/hidl/1.0/OutputBufferQueue.h>
+#include <codec2/hidl/1.1/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::OutputBufferQueue;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_OUTPUT_BUFFER_QUEUE
diff --git a/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/types.h b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/types.h
new file mode 100644
index 0000000..d0ba93d
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/include/codec2/hidl/1.1/types.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_HIDL_V1_1_UTILS_TYPES_H
+#define CODEC2_HIDL_V1_1_UTILS_TYPES_H
+
+#include <android/hardware/media/c2/1.1/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.1/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
+#include <android/hardware/media/c2/1.0/IInputSurfaceConnection.h>
+
+#include <codec2/hidl/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_1 {
+
+using ::android::hardware::media::c2::V1_0::BaseBlock;
+using ::android::hardware::media::c2::V1_0::Block;
+using ::android::hardware::media::c2::V1_0::Buffer;
+using ::android::hardware::media::c2::V1_0::FieldDescriptor;
+using ::android::hardware::media::c2::V1_0::FieldId;
+using ::android::hardware::media::c2::V1_0::FieldSupportedValues;
+using ::android::hardware::media::c2::V1_0::FieldSupportedValuesQuery;
+using ::android::hardware::media::c2::V1_0::FieldSupportedValuesQueryResult;
+using ::android::hardware::media::c2::V1_0::FrameData;
+using ::android::hardware::media::c2::V1_0::InfoBuffer;
+using ::android::hardware::media::c2::V1_0::ParamDescriptor;
+using ::android::hardware::media::c2::V1_0::ParamField;
+using ::android::hardware::media::c2::V1_0::ParamFieldValues;
+using ::android::hardware::media::c2::V1_0::ParamIndex;
+using ::android::hardware::media::c2::V1_0::Params;
+using ::android::hardware::media::c2::V1_0::PrimitiveValue;
+using ::android::hardware::media::c2::V1_0::SettingResult;
+using ::android::hardware::media::c2::V1_0::Status;
+using ::android::hardware::media::c2::V1_0::StructDescriptor;
+using ::android::hardware::media::c2::V1_0::ValueRange;
+using ::android::hardware::media::c2::V1_0::Work;
+using ::android::hardware::media::c2::V1_0::WorkBundle;
+using ::android::hardware::media::c2::V1_0::WorkOrdinal;
+using ::android::hardware::media::c2::V1_0::Worklet;
+
+using ::android::hardware::media::c2::V1_0::IComponentInterface;
+using ::android::hardware::media::c2::V1_0::IComponentListener;
+using ::android::hardware::media::c2::V1_0::IConfigurable;
+using ::android::hardware::media::c2::V1_0::IInputSink;
+using ::android::hardware::media::c2::V1_0::IInputSurface;
+using ::android::hardware::media::c2::V1_0::IInputSurfaceConnection;
+
+namespace utils {
+
+using ::android::hardware::media::c2::V1_0::utils::toC2Status;
+
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_Range;
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_RangeInfo;
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_Rect;
+using ::android::hardware::media::c2::V1_0::utils::C2Hidl_RectInfo;
+
+using ::android::hardware::media::c2::V1_0::utils::objcpy;
+using ::android::hardware::media::c2::V1_0::utils::parseParamsBlob;
+using ::android::hardware::media::c2::V1_0::utils::createParamsBlob;
+using ::android::hardware::media::c2::V1_0::utils::copyParamsFromBlob;
+using ::android::hardware::media::c2::V1_0::utils::updateParamsFromBlob;
+
+using ::android::hardware::media::c2::V1_0::utils::BufferPoolSender;
+using ::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender;
+
+using ::android::hardware::media::c2::V1_0::utils::beginTransferBufferQueueBlock;
+using ::android::hardware::media::c2::V1_0::utils::beginTransferBufferQueueBlocks;
+using ::android::hardware::media::c2::V1_0::utils::endTransferBufferQueueBlock;
+using ::android::hardware::media::c2::V1_0::utils::endTransferBufferQueueBlocks;
+using ::android::hardware::media::c2::V1_0::utils::displayBufferQueueBlock;
+
+using ::android::hardware::media::c2::V1_0::utils::operator<<;
+
+} // namespace utils
+} // namespace V1_1
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_1_UTILS_TYPES_H
diff --git a/media/codec2/hidl/1.1/utils/types.cpp b/media/codec2/hidl/1.1/utils/types.cpp
new file mode 100644
index 0000000..8c09023
--- /dev/null
+++ b/media/codec2/hidl/1.1/utils/types.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <codec2/hidl/1.1/types.h>
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index 89c1c4a..3c37990 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -9,10 +9,12 @@
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.media.bufferpool@2.0",
         "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
         "libbase",
         "libbinder",
         "libcodec2",
         "libcodec2_hidl_client@1.0",
+        "libcodec2_hidl_client@1.1",
         "libcodec2_vndk",
         "libcutils",
         "libgui",
@@ -28,8 +30,11 @@
     ],
 
     export_shared_lib_headers: [
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
         "libcodec2",
         "libcodec2_hidl_client@1.0",
+        "libcodec2_hidl_client@1.1",
         "libcodec2_vndk",
     ],
 
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index c747190..199a99c 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -19,6 +19,29 @@
 #include <android-base/logging.h>
 
 #include <codec2/hidl/client.h>
+#include <C2Debug.h>
+#include <C2BufferPriv.h>
+#include <C2PlatformSupport.h>
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+
+#include <android-base/properties.h>
+#include <bufferpool/ClientManager.h>
+#include <codec2/hidl/1.0/OutputBufferQueue.h>
+#include <codec2/hidl/1.0/types.h>
+#include <codec2/hidl/1.1/OutputBufferQueue.h>
+#include <codec2/hidl/1.1/types.h>
+
+#include <cutils/native_handle.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
+#include <hidl/HidlSupport.h>
 
 #include <deque>
 #include <iterator>
@@ -30,25 +53,6 @@
 #include <type_traits>
 #include <vector>
 
-#include <android-base/properties.h>
-#include <bufferpool/ClientManager.h>
-#include <cutils/native_handle.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
-#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
-#include <hidl/HidlSupport.h>
-
-#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
-#include <android/hardware/media/c2/1.0/IComponent.h>
-#include <android/hardware/media/c2/1.0/IComponentInterface.h>
-#include <android/hardware/media/c2/1.0/IComponentListener.h>
-#include <android/hardware/media/c2/1.0/IComponentStore.h>
-#include <android/hardware/media/c2/1.0/IConfigurable.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-
-#include <C2Debug.h>
-#include <C2BufferPriv.h>
-#include <C2PlatformSupport.h>
-
 namespace android {
 
 using ::android::hardware::hidl_vec;
@@ -56,8 +60,8 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 
-using namespace ::android::hardware::media::c2::V1_0;
-using namespace ::android::hardware::media::c2::V1_0::utils;
+using namespace ::android::hardware::media::c2::V1_1;
+using namespace ::android::hardware::media::c2::V1_1::utils;
 using namespace ::android::hardware::media::bufferpool::V2_0;
 using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
 
@@ -514,8 +518,24 @@
 
 };
 
+// Codec2Client::Component::BufferPoolSender
+struct Codec2Client::Component::BufferPoolSender :
+        hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
+    BufferPoolSender()
+          : hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
+    }
+};
+
+// Codec2Client::Component::OutputBufferQueue
+struct Codec2Client::Component::OutputBufferQueue :
+        hardware::media::c2::V1_1::utils::OutputBufferQueue {
+    OutputBufferQueue()
+          : hardware::media::c2::V1_1::utils::OutputBufferQueue() {
+    }
+};
+
 // Codec2Client
-Codec2Client::Codec2Client(const sp<IComponentStore>& base,
+Codec2Client::Codec2Client(sp<Base> const& base,
                            size_t serviceIndex)
       : Configurable{
             [base]() -> sp<IConfigurable> {
@@ -526,7 +546,8 @@
                         nullptr;
             }()
         },
-        mBase{base},
+        mBase1_0{base},
+        mBase1_1{Base1_1::castFrom(base)},
         mServiceIndex{serviceIndex} {
     Return<sp<IClientManager>> transResult = base->getPoolClientManager();
     if (!transResult.isOk()) {
@@ -537,7 +558,15 @@
 }
 
 sp<Codec2Client::Base> const& Codec2Client::getBase() const {
-    return mBase;
+    return mBase1_0;
+}
+
+sp<Codec2Client::Base1_0> const& Codec2Client::getBase1_0() const {
+    return mBase1_0;
+}
+
+sp<Codec2Client::Base1_1> const& Codec2Client::getBase1_1() const {
+    return mBase1_1;
 }
 
 std::string const& Codec2Client::getServiceName() const {
@@ -552,7 +581,8 @@
     c2_status_t status;
     sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
     hidlListener->base = listener;
-    Return<void> transStatus = mBase->createComponent(
+    Return<void> transStatus = mBase1_1 ?
+        mBase1_1->createComponent_1_1(
             name,
             hidlListener,
             ClientManager::getInstance(),
@@ -565,6 +595,20 @@
                 }
                 *component = std::make_shared<Codec2Client::Component>(c);
                 hidlListener->component = *component;
+            }) :
+        mBase1_0->createComponent(
+            name,
+            hidlListener,
+            ClientManager::getInstance(),
+            [&status, component, hidlListener](
+                    Status s,
+                    const sp<hardware::media::c2::V1_0::IComponent>& c) {
+                status = static_cast<c2_status_t>(s);
+                if (status != C2_OK) {
+                    return;
+                }
+                *component = std::make_shared<Codec2Client::Component>(c);
+                hidlListener->component = *component;
             });
     if (!transStatus.isOk()) {
         LOG(ERROR) << "createComponent(" << name.c_str()
@@ -587,7 +631,7 @@
                    << status << ".";
     }
 
-    (*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
+    (*component)->mBufferPoolSender->setReceiver(mHostPoolManager);
     return status;
 }
 
@@ -595,7 +639,7 @@
         const C2String& name,
         std::shared_ptr<Codec2Client::Interface>* const interface) {
     c2_status_t status;
-    Return<void> transStatus = mBase->createInterface(
+    Return<void> transStatus = mBase1_0->createInterface(
             name,
             [&status, interface](
                     Status s,
@@ -622,7 +666,7 @@
 c2_status_t Codec2Client::createInputSurface(
         std::shared_ptr<InputSurface>* const inputSurface) {
     c2_status_t status;
-    Return<void> transStatus = mBase->createInputSurface(
+    Return<void> transStatus = mBase1_0->createInputSurface(
             [&status, inputSurface](
                     Status s,
                     const sp<IInputSurface>& i) {
@@ -650,7 +694,7 @@
         bool* success) const {
     std::vector<C2Component::Traits> traits;
     std::string const& serviceName = getServiceName();
-    Return<void> transStatus = mBase->listComponents(
+    Return<void> transStatus = mBase1_0->listComponents(
             [&traits, &serviceName](Status s,
                    const hidl_vec<IComponentStore::ComponentTraits>& t) {
                 if (s != Status::OK) {
@@ -734,7 +778,7 @@
         sp<Base> mBase;
     };
 
-    return std::make_shared<SimpleParamReflector>(mBase);
+    return std::make_shared<SimpleParamReflector>(mBase1_0);
 };
 
 std::vector<std::string> const& Codec2Client::GetServiceNames() {
@@ -1053,8 +1097,32 @@
                         nullptr;
             }()
         },
-        mBase{base},
-        mBufferPoolSender{nullptr} {
+        mBase1_0{base},
+        mBase1_1{Base1_1::castFrom(base)},
+        mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+        mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
+}
+
+Codec2Client::Component::Component(const sp<Base1_1>& base)
+      : Configurable{
+            [base]() -> sp<IConfigurable> {
+                Return<sp<IComponentInterface>> transResult1 =
+                        base->getInterface();
+                if (!transResult1.isOk()) {
+                    return nullptr;
+                }
+                Return<sp<IConfigurable>> transResult2 =
+                        static_cast<sp<IComponentInterface>>(transResult1)->
+                        getConfigurable();
+                return transResult2.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult2) :
+                        nullptr;
+            }()
+        },
+        mBase1_0{base},
+        mBase1_1{base},
+        mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+        mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
 }
 
 Codec2Client::Component::~Component() {
@@ -1065,7 +1133,7 @@
         C2BlockPool::local_id_t* blockPoolId,
         std::shared_ptr<Codec2Client::Configurable>* configurable) {
     c2_status_t status;
-    Return<void> transStatus = mBase->createBlockPool(
+    Return<void> transStatus = mBase1_0->createBlockPool(
             static_cast<uint32_t>(id),
             [&status, blockPoolId, configurable](
                     Status s,
@@ -1090,7 +1158,7 @@
 
 c2_status_t Codec2Client::Component::destroyBlockPool(
         C2BlockPool::local_id_t localId) {
-    Return<Status> transResult = mBase->destroyBlockPool(
+    Return<Status> transResult = mBase1_0->destroyBlockPool(
             static_cast<uint64_t>(localId));
     if (!transResult.isOk()) {
         LOG(ERROR) << "destroyBlockPool -- transaction failed.";
@@ -1102,17 +1170,17 @@
 void Codec2Client::Component::handleOnWorkDone(
         const std::list<std::unique_ptr<C2Work>> &workItems) {
     // Output bufferqueue-based blocks' lifetime management
-    mOutputBufferQueue.holdBufferQueueBlocks(workItems);
+    mOutputBufferQueue->holdBufferQueueBlocks(workItems);
 }
 
 c2_status_t Codec2Client::Component::queue(
         std::list<std::unique_ptr<C2Work>>* const items) {
     WorkBundle workBundle;
-    if (!objcpy(&workBundle, *items, &mBufferPoolSender)) {
+    if (!objcpy(&workBundle, *items, mBufferPoolSender.get())) {
         LOG(ERROR) << "queue -- bad input.";
         return C2_TRANSACTION_FAILED;
     }
-    Return<Status> transStatus = mBase->queue(workBundle);
+    Return<Status> transStatus = mBase1_0->queue(workBundle);
     if (!transStatus.isOk()) {
         LOG(ERROR) << "queue -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1130,7 +1198,7 @@
         std::list<std::unique_ptr<C2Work>>* const flushedWork) {
     (void)mode; // Flush mode isn't supported in HIDL yet.
     c2_status_t status;
-    Return<void> transStatus = mBase->flush(
+    Return<void> transStatus = mBase1_0->flush(
             [&status, flushedWork](
                     Status s, const WorkBundle& wb) {
                 status = static_cast<c2_status_t>(s);
@@ -1165,13 +1233,13 @@
     }
 
     // Output bufferqueue-based blocks' lifetime management
-    mOutputBufferQueue.holdBufferQueueBlocks(*flushedWork);
+    mOutputBufferQueue->holdBufferQueueBlocks(*flushedWork);
 
     return status;
 }
 
 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
-    Return<Status> transStatus = mBase->drain(
+    Return<Status> transStatus = mBase1_0->drain(
             mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
     if (!transStatus.isOk()) {
         LOG(ERROR) << "drain -- transaction failed.";
@@ -1186,7 +1254,7 @@
 }
 
 c2_status_t Codec2Client::Component::start() {
-    Return<Status> transStatus = mBase->start();
+    Return<Status> transStatus = mBase1_0->start();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "start -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1200,7 +1268,7 @@
 }
 
 c2_status_t Codec2Client::Component::stop() {
-    Return<Status> transStatus = mBase->stop();
+    Return<Status> transStatus = mBase1_0->stop();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "stop -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1214,7 +1282,7 @@
 }
 
 c2_status_t Codec2Client::Component::reset() {
-    Return<Status> transStatus = mBase->reset();
+    Return<Status> transStatus = mBase1_0->reset();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "reset -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1228,7 +1296,7 @@
 }
 
 c2_status_t Codec2Client::Component::release() {
-    Return<Status> transStatus = mBase->release();
+    Return<Status> transStatus = mBase1_0->release();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "release -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1241,6 +1309,29 @@
     return status;
 }
 
+c2_status_t Codec2Client::Component::configureVideoTunnel(
+        uint32_t avSyncHwId,
+        native_handle_t** sidebandHandle) {
+    *sidebandHandle = nullptr;
+    if (!mBase1_1) {
+        return C2_OMITTED;
+    }
+    c2_status_t status{};
+    Return<void> transStatus = mBase1_1->configureVideoTunnel(avSyncHwId,
+            [&status, sidebandHandle](
+                    Status s, hardware::hidl_handle const& h) {
+                status = static_cast<c2_status_t>(s);
+                if (h.getNativeHandle()) {
+                    *sidebandHandle = native_handle_clone(h.getNativeHandle());
+                }
+            });
+    if (!transStatus.isOk()) {
+        LOG(ERROR) << "configureVideoTunnel -- transaction failed.";
+        return C2_TRANSACTION_FAILED;
+    }
+    return status;
+}
+
 c2_status_t Codec2Client::Component::setOutputSurface(
         C2BlockPool::local_id_t blockPoolId,
         const sp<IGraphicBufferProducer>& surface,
@@ -1256,18 +1347,18 @@
     }
 
     if (!surface) {
-        mOutputBufferQueue.configure(nullIgbp, generation, 0);
+        mOutputBufferQueue->configure(nullIgbp, generation, 0);
     } else if (surface->getUniqueId(&bqId) != OK) {
         LOG(ERROR) << "setOutputSurface -- "
                    "cannot obtain bufferqueue id.";
         bqId = 0;
-        mOutputBufferQueue.configure(nullIgbp, generation, 0);
+        mOutputBufferQueue->configure(nullIgbp, generation, 0);
     } else {
-        mOutputBufferQueue.configure(surface, generation, bqId);
+        mOutputBufferQueue->configure(surface, generation, bqId);
     }
     ALOGD("generation remote change %u", generation);
 
-    Return<Status> transStatus = mBase->setOutputSurface(
+    Return<Status> transStatus = mBase1_0->setOutputSurface(
             static_cast<uint64_t>(blockPoolId),
             bqId == 0 ? nullHgbp : igbp);
     if (!transStatus.isOk()) {
@@ -1286,14 +1377,14 @@
         const C2ConstGraphicBlock& block,
         const QueueBufferInput& input,
         QueueBufferOutput* output) {
-    return mOutputBufferQueue.outputBuffer(block, input, output);
+    return mOutputBufferQueue->outputBuffer(block, input, output);
 }
 
 c2_status_t Codec2Client::Component::connectToInputSurface(
         const std::shared_ptr<InputSurface>& inputSurface,
         std::shared_ptr<InputSurfaceConnection>* connection) {
     c2_status_t status;
-    Return<void> transStatus = mBase->connectToInputSurface(
+    Return<void> transStatus = mBase1_0->connectToInputSurface(
             inputSurface->mBase,
             [&status, connection](
                     Status s, const sp<IInputSurfaceConnection>& c) {
@@ -1317,7 +1408,7 @@
         const sp<HGraphicBufferSource>& source,
         std::shared_ptr<InputSurfaceConnection>* connection) {
     c2_status_t status;
-    Return<void> transStatus = mBase->connectToOmxInputSurface(
+    Return<void> transStatus = mBase1_0->connectToOmxInputSurface(
             producer, source,
             [&status, connection](
                     Status s, const sp<IInputSurfaceConnection>& c) {
@@ -1337,7 +1428,7 @@
 }
 
 c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
-    Return<Status> transStatus = mBase->disconnectFromInputSurface();
+    Return<Status> transStatus = mBase1_0->disconnectFromInputSurface();
     if (!transStatus.isOk()) {
         LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
         return C2_TRANSACTION_FAILED;
@@ -1376,7 +1467,7 @@
     deathRecipient->component = component;
 
     component->mDeathRecipient = deathRecipient;
-    Return<bool> transResult = component->mBase->linkToDeath(
+    Return<bool> transResult = component->mBase1_0->linkToDeath(
             component->mDeathRecipient, 0);
     if (!transResult.isOk()) {
         LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index c37407f..649dffd 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -17,14 +17,13 @@
 #ifndef CODEC2_HIDL_CLIENT_H
 #define CODEC2_HIDL_CLIENT_H
 
-#include <gui/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/ClientBlockHelper.h>
 #include <C2PlatformSupport.h>
 #include <C2Component.h>
 #include <C2Buffer.h>
 #include <C2Param.h>
 #include <C2.h>
 
+#include <gui/IGraphicBufferProducer.h>
 #include <hidl/HidlSupport.h>
 #include <utils/StrongPointer.h>
 
@@ -74,6 +73,11 @@
 struct IInputSurfaceConnection;
 }  // namespace android::hardware::media::c2::V1_0
 
+namespace android::hardware::media::c2::V1_1 {
+struct IComponent;
+struct IComponentStore;
+}  // namespace android::hardware::media::c2::V1_1
+
 namespace android::hardware::media::bufferpool::V2_0 {
 struct IClientManager;
 }  // namespace android::hardware::media::bufferpool::V2_0
@@ -82,6 +86,10 @@
 struct IGraphicBufferProducer;
 }  // android::hardware::graphics::bufferqueue::V1_0
 
+namespace android::hardware::graphics::bufferqueue::V2_0 {
+struct IGraphicBufferProducer;
+}  // android::hardware::graphics::bufferqueue::V2_0
+
 namespace android::hardware::media::omx::V1_0 {
 struct IGraphicBufferSource;
 }  // namespace android::hardware::media::omx::V1_0
@@ -127,7 +135,9 @@
 
 struct Codec2Client : public Codec2ConfigurableClient {
 
-    typedef ::android::hardware::media::c2::V1_0::IComponentStore Base;
+    typedef ::android::hardware::media::c2::V1_0::IComponentStore Base1_0;
+    typedef ::android::hardware::media::c2::V1_1::IComponentStore Base1_1;
+    typedef Base1_0 Base;
 
     struct Listener;
 
@@ -144,6 +154,8 @@
     typedef Codec2Client Store;
 
     sp<Base> const& getBase() const;
+    sp<Base1_0> const& getBase1_0() const;
+    sp<Base1_1> const& getBase1_1() const;
 
     std::string const& getServiceName() const;
 
@@ -206,7 +218,8 @@
     Codec2Client(sp<Base> const& base, size_t serviceIndex);
 
 protected:
-    sp<Base> mBase;
+    sp<Base1_0> mBase1_0;
+    sp<Base1_1> mBase1_1;
 
     // Finds the first store where the predicate returns C2_OK and returns the
     // last predicate result. The predicate will be tried on all stores. The
@@ -295,7 +308,9 @@
 
 struct Codec2Client::Component : public Codec2Client::Configurable {
 
-    typedef ::android::hardware::media::c2::V1_0::IComponent Base;
+    typedef ::android::hardware::media::c2::V1_0::IComponent Base1_0;
+    typedef ::android::hardware::media::c2::V1_1::IComponent Base1_1;
+    typedef Base1_0 Base;
 
     c2_status_t createBlockPool(
             C2Allocator::id_t id,
@@ -322,6 +337,17 @@
 
     c2_status_t release();
 
+    /**
+     * Use tunneling.
+     *
+     * On success, @p sidebandHandle will be a newly allocated native handle.
+     * File descriptors in @p sidebandHandle must be closed and
+     * @p sidebandHandle itself must be deleted afterwards.
+     */
+    c2_status_t configureVideoTunnel(
+            uint32_t avSyncHwId,
+            native_handle_t** sidebandHandle);
+
     typedef ::android::
             IGraphicBufferProducer IGraphicBufferProducer;
     typedef IGraphicBufferProducer::
@@ -378,17 +404,19 @@
 
     // base cannot be null.
     Component(const sp<Base>& base);
+    Component(const sp<Base1_1>& base);
 
     ~Component();
 
 protected:
-    sp<Base> mBase;
+    sp<Base1_0> mBase1_0;
+    sp<Base1_1> mBase1_1;
 
-    ::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender
-            mBufferPoolSender;
+    struct BufferPoolSender;
+    std::unique_ptr<BufferPoolSender> mBufferPoolSender;
 
-    ::android::hardware::media::c2::V1_0::utils::OutputBufferQueue
-            mOutputBufferQueue;
+    struct OutputBufferQueue;
+    std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;
 
     static c2_status_t setDeathListener(
             const std::shared_ptr<Component>& component,
diff --git a/media/codec2/hidl/services/Android.bp b/media/codec2/hidl/services/Android.bp
index 0403a1f..46bea2e 100644
--- a/media/codec2/hidl/services/Android.bp
+++ b/media/codec2/hidl/services/Android.bp
@@ -1,37 +1,82 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This is an example of an empty Codec2.0 service.
+//
+// To use this, make a copy of this whole directory and rename modules
+// accordingly. The contents of "vendor.cpp" and files in the subdirectory
+// "seccomp_policy" may also need to be modified.
+
+// Binary file for the service.
+//
+// The init_rc file contains the absolute path to this binary on the device.
+// If the name of this module is modified, the content of the init_rc file has
+// to be modified accordingly.
+//
+// The seccomp_policy file name and its content can be modified, but note that
+// vendor.cpp also needs to be updated because it needs the absolute path to the
+// seccomp policy file on the device.
 cc_binary {
-    name: "android.hardware.media.c2@1.0-service",
-    defaults: ["hidl_defaults"],
-    soc_specific: true,
+    name: "android.hardware.media.c2@1.1-default-service",
+    vendor: true,
     relative_install_path: "hw",
+
+    init_rc: ["android.hardware.media.c2@1.1-default-service.rc"],
+
+    defaults: ["libcodec2-hidl-defaults"],
     srcs: [
         "vendor.cpp",
     ],
 
-    init_rc: ["android.hardware.media.c2@1.0-service.rc"],
-
+    // minijail is used to protect against unexpected system calls.
     shared_libs: [
-        "android.hardware.media.c2@1.0",
-        "android.hardware.media.omx@1.0",
         "libavservices_minijail_vendor",
         "libbinder",
-        "libcodec2_hidl@1.0",
-        "libcodec2_vndk",
-        "libhidlbase",
-        "liblog",
-        "libstagefright_omx",
-        "libstagefright_xmlparser",
-        "libutils",
     ],
+    required: ["android.hardware.media.c2@1.1-default-seccomp_policy"],
+}
 
+// seccomp policy file.
+//
+// This should be modified to suit the target device and architecture.
+//
+// Files in the "seccomp_policy" subdirectory are only provided as examples.
+// They may not work on some devices and/or architectures without modification.
+prebuilt_etc {
+    name: "android.hardware.media.c2@1.1-default-seccomp_policy",
+    vendor: true,
+    sub_dir: "seccomp_policy",
+
+    // If a specific architecture is targeted, multiple choices are not needed.
     arch: {
         arm: {
-            required: ["codec2.vendor.base.policy"],
+            src: "seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy",
+        },
+        arm64: {
+            src: "seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy",
         },
         x86: {
-            required: ["codec2.vendor.base.policy"],
+            src: "seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy",
+        },
+        x86_64: {
+            src: "seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy",
         },
     },
 
-    compile_multilib: "32",
+    // This may be removed.
+    required: ["crash_dump.policy"],
 }
 
diff --git a/media/codec2/hidl/services/Android.mk b/media/codec2/hidl/services/Android.mk
deleted file mode 100644
index d9b28e7..0000000
--- a/media/codec2/hidl/services/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# vendor service seccomp policy
-ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH), x86 x86_64 arm arm64))
-include $(CLEAR_VARS)
-LOCAL_MODULE := codec2.vendor.base.policy
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy
-ifdef TARGET_2ND_ARCH
-    ifneq ($(TARGET_TRANSLATE_2ND_ARCH),true)
-        LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_2ND_ARCH).policy
-    else
-        LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
-    endif
-else
-    LOCAL_SRC_FILES := seccomp_policy/codec2.vendor.base-$(TARGET_ARCH).policy
-endif
-include $(BUILD_PREBUILT)
-endif
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
-
diff --git a/media/codec2/hidl/services/android.hardware.media.c2@1.0-service.rc b/media/codec2/hidl/services/android.hardware.media.c2@1.0-service.rc
deleted file mode 100644
index 8806bd1f..0000000
--- a/media/codec2/hidl/services/android.hardware.media.c2@1.0-service.rc
+++ /dev/null
@@ -1,7 +0,0 @@
-service android-hardware-media-c2-hal-1-0 /vendor/bin/hw/android.hardware.media.c2@1.0-service
-    class hal
-    user mediacodec
-    group camera mediadrm drmrpc
-    ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks
-
diff --git a/media/codec2/hidl/services/android.hardware.media.c2@1.1-default-service.rc b/media/codec2/hidl/services/android.hardware.media.c2@1.1-default-service.rc
new file mode 100644
index 0000000..44f2d8e
--- /dev/null
+++ b/media/codec2/hidl/services/android.hardware.media.c2@1.1-default-service.rc
@@ -0,0 +1,7 @@
+service android-hardware-media-c2-hal-1-1 /vendor/bin/hw/android.hardware.media.c2@1.1-default-service
+    class hal
+    user mediacodec
+    group camera mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
+
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy
similarity index 70%
copy from media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
copy to media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy
index d5871d1..9042cd7 100644
--- a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm.policy
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,21 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Organized by frequency of systemcall - in descending order for
-# best performance.
 futex: 1
+# ioctl calls are filtered via the selinux policy.
 ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
+sched_yield: 1
 close: 1
-writev: 1
 dup: 1
 ppoll: 1
-mmap2: 1
-getrandom: 1
+mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+mmap2: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
@@ -36,38 +33,54 @@
 # for more details.
 mremap: arg3 == 3
 munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
+prctl: 1
+getuid32: 1
+writev: 1
 sigaltstack: 1
 clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
 exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
 lseek: 1
+rt_sigprocmask: 1
+openat: 1
+open: 1
+fstat64: 1
+write: 1
+nanosleep: 1
+setpriority: 1
+set_tid_address: 1
+getdents64: 1
+readlinkat: 1
+readlink: 1
+read: 1
+pread64: 1
+fstatfs64: 1
+gettimeofday: 1
+faccessat: 1
 _llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
 fstatat64: 1
 ugetrlimit: 1
-getdents64: 1
+exit_group: 1
+restart_syscall: 1
+rt_sigreturn: 1
 getrandom: 1
+madvise: 1
 
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
+# crash dump policy additions
+sigreturn: 1
+clock_gettime: 1
+futex: 1
+getpid: 1
+gettid: 1
+pipe2: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigaction: 1
+rt_tgsigqueueinfo: 1
+#prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+#mprotect: arg2 in 0x1|0x2
+#mmap2: arg2 in 0x1|0x2
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy
similarity index 71%
rename from media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
rename to media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy
index d5871d1..4faf8b2 100644
--- a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-arm.policy
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-arm64.policy
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# Copyright (C) 2019 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -12,21 +12,22 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Organized by frequency of systemcall - in descending order for
-# best performance.
 futex: 1
+# ioctl calls are filtered via the selinux policy.
 ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
+sched_yield: 1
 close: 1
-writev: 1
 dup: 1
 ppoll: 1
-mmap2: 1
-getrandom: 1
+mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+mmap: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+getuid: 1
+getrlimit: 1
+fstat: 1
+newfstatat: 1
+fstatfs: 1
+memfd_create: 1
+ftruncate: 1
 
 # mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
 # parser support for '<' is in this needs to be modified to also prevent
@@ -36,38 +37,45 @@
 # for more details.
 mremap: arg3 == 3
 munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
+prctl: 1
+writev: 1
 sigaltstack: 1
 clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
 exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
 lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
+rt_sigprocmask: 1
+openat: 1
+write: 1
+nanosleep: 1
+setpriority: 1
+set_tid_address: 1
 getdents64: 1
+readlinkat: 1
+read: 1
+pread64: 1
+gettimeofday: 1
+faccessat: 1
+exit_group: 1
+restart_syscall: 1
+rt_sigreturn: 1
 getrandom: 1
+madvise: 1
 
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
+# crash dump policy additions
+clock_gettime: 1
+getpid: 1
+gettid: 1
+pipe2: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigaction: 1
+rt_tgsigqueueinfo: 1
+#mprotect: arg2 in 0x1|0x2
+munmap: 1
+#mmap: arg2 in 0x1|0x2
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
 
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy
similarity index 81%
rename from media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
rename to media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy
index 20c7625..d9c4045 100644
--- a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86.policy
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# Copyright (C) 2017 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.
@@ -16,14 +16,22 @@
 mprotect: 1
 prctl: 1
 openat: 1
+open: 1
 getuid32: 1
+getuid: 1
+getrlimit: 1
 writev: 1
 ioctl: 1
 close: 1
 mmap2: 1
+mmap: 1
 fstat64: 1
+fstat: 1
+stat64: 1
+statfs64: 1
 madvise: 1
 fstatat64: 1
+newfstatat: 1
 futex: 1
 munmap: 1
 faccessat: 1
@@ -37,15 +45,22 @@
 exit_group: 1
 rt_sigreturn: 1
 ugetrlimit: 1
+readlink: 1
 readlinkat: 1
 _llseek: 1
 fstatfs64: 1
+fstatfs: 1
 pread64: 1
 mremap: 1
 dup: 1
 set_tid_address: 1
 write: 1
 nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
 
 # Required by AddressSanitizer
 gettid: 1
@@ -54,4 +69,3 @@
 gettid: 1
 
 @include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy
similarity index 81%
copy from media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
copy to media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy
index 20c7625..d9c4045 100644
--- a/media/codec2/hidl/services/seccomp_policy/codec2.software.base-x86.policy
+++ b/media/codec2/hidl/services/seccomp_policy/android.hardware.media.c2@1.1-default-x86_64.policy
@@ -1,4 +1,4 @@
-# Copyright (C) 2018 The Android Open Source Project
+# Copyright (C) 2017 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.
@@ -16,14 +16,22 @@
 mprotect: 1
 prctl: 1
 openat: 1
+open: 1
 getuid32: 1
+getuid: 1
+getrlimit: 1
 writev: 1
 ioctl: 1
 close: 1
 mmap2: 1
+mmap: 1
 fstat64: 1
+fstat: 1
+stat64: 1
+statfs64: 1
 madvise: 1
 fstatat64: 1
+newfstatat: 1
 futex: 1
 munmap: 1
 faccessat: 1
@@ -37,15 +45,22 @@
 exit_group: 1
 rt_sigreturn: 1
 ugetrlimit: 1
+readlink: 1
 readlinkat: 1
 _llseek: 1
 fstatfs64: 1
+fstatfs: 1
 pread64: 1
 mremap: 1
 dup: 1
 set_tid_address: 1
 write: 1
 nanosleep: 1
+sched_setscheduler: 1
+uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
 
 # Required by AddressSanitizer
 gettid: 1
@@ -54,4 +69,3 @@
 gettid: 1
 
 @include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy b/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy
deleted file mode 100644
index d5871d1..0000000
--- a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-arm.policy
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Organized by frequency of systemcall - in descending order for
-# best performance.
-futex: 1
-ioctl: 1
-write: 1
-prctl: 1
-clock_gettime: 1
-getpriority: 1
-read: 1
-close: 1
-writev: 1
-dup: 1
-ppoll: 1
-mmap2: 1
-getrandom: 1
-
-# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
-# parser support for '<' is in this needs to be modified to also prevent
-# |old_address| and |new_address| from touching the exception vector page, which
-# on ARM is statically loaded at 0xffff 0000. See
-# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
-# for more details.
-mremap: arg3 == 3
-munmap: 1
-mprotect: 1
-madvise: 1
-openat: 1
-sigaltstack: 1
-clone: 1
-setpriority: 1
-getuid32: 1
-fstat64: 1
-fstatfs64: 1
-pread64: 1
-faccessat: 1
-readlinkat: 1
-exit: 1
-rt_sigprocmask: 1
-set_tid_address: 1
-restart_syscall: 1
-exit_group: 1
-rt_sigreturn: 1
-pipe2: 1
-gettimeofday: 1
-sched_yield: 1
-nanosleep: 1
-lseek: 1
-_llseek: 1
-sched_get_priority_max: 1
-sched_get_priority_min: 1
-statfs64: 1
-sched_setscheduler: 1
-fstatat64: 1
-ugetrlimit: 1
-getdents64: 1
-getrandom: 1
-
-@include /system/etc/seccomp_policy/crash_dump.arm.policy
-
diff --git a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy b/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy
deleted file mode 100644
index 20c7625..0000000
--- a/media/codec2/hidl/services/seccomp_policy/codec2.vendor.base-x86.policy
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-read: 1
-mprotect: 1
-prctl: 1
-openat: 1
-getuid32: 1
-writev: 1
-ioctl: 1
-close: 1
-mmap2: 1
-fstat64: 1
-madvise: 1
-fstatat64: 1
-futex: 1
-munmap: 1
-faccessat: 1
-_llseek: 1
-lseek: 1
-clone: 1
-sigaltstack: 1
-setpriority: 1
-restart_syscall: 1
-exit: 1
-exit_group: 1
-rt_sigreturn: 1
-ugetrlimit: 1
-readlinkat: 1
-_llseek: 1
-fstatfs64: 1
-pread64: 1
-mremap: 1
-dup: 1
-set_tid_address: 1
-write: 1
-nanosleep: 1
-
-# Required by AddressSanitizer
-gettid: 1
-sched_yield: 1
-getpid: 1
-gettid: 1
-
-@include /system/etc/seccomp_policy/crash_dump.x86.policy
-
diff --git a/media/codec2/hidl/services/vendor.cpp b/media/codec2/hidl/services/vendor.cpp
index ef2f98e..65bb6f7 100644
--- a/media/codec2/hidl/services/vendor.cpp
+++ b/media/codec2/hidl/services/vendor.cpp
@@ -15,25 +15,27 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "android.hardware.media.c2@1.0-service"
+#define LOG_TAG "android.hardware.media.c2@1.1-service"
 
-#include <codec2/hidl/1.0/ComponentStore.h>
-#include <hidl/HidlTransportSupport.h>
+#include <android-base/logging.h>
 #include <binder/ProcessState.h>
+#include <codec2/hidl/1.1/ComponentStore.h>
+#include <hidl/HidlTransportSupport.h>
 #include <minijail.h>
 
 #include <C2Component.h>
 
-// OmxStore is added for visibility by dumpstate.
-#include <media/stagefright/omx/1.0/OmxStore.h>
-
-// This is created by module "codec2.vendor.base.policy". This can be modified.
+// This is the absolute on-device path of the prebuild_etc module
+// "android.hardware.media.c2@1.1-default-seccomp_policy" in Android.bp.
 static constexpr char kBaseSeccompPolicyPath[] =
-        "/vendor/etc/seccomp_policy/codec2.vendor.base.policy";
+        "/vendor/etc/seccomp_policy/"
+        "android.hardware.media.c2@1.1-default-seccomp-policy";
 
-// Additional device-specific seccomp permissions can be added in this file.
+// Additional seccomp permissions can be added in this file.
+// This file does not exist by default.
 static constexpr char kExtSeccompPolicyPath[] =
-        "/vendor/etc/seccomp_policy/codec2.vendor.ext.policy";
+        "/vendor/etc/seccomp_policy/"
+        "android.hardware.media.c2@1.1-extended-seccomp-policy";
 
 class DummyC2Store : public C2ComponentStore {
 public:
@@ -97,54 +99,48 @@
 };
 
 int main(int /* argc */, char** /* argv */) {
-    ALOGD("android.hardware.media.c2@1.0-service starting...");
+    using namespace ::android;
+    LOG(DEBUG) << "android.hardware.media.c2@1.1-service starting...";
 
+    // Set up minijail to limit system calls.
     signal(SIGPIPE, SIG_IGN);
-    android::SetUpMinijail(kBaseSeccompPolicyPath, kExtSeccompPolicyPath);
+    SetUpMinijail(kBaseSeccompPolicyPath, kExtSeccompPolicyPath);
 
-    // vndbinder is needed by BufferQueue.
-    android::ProcessState::initWithDriver("/dev/vndbinder");
-    android::ProcessState::self()->startThreadPool();
+    // Enable vndbinder to allow vendor-to-vendor binder calls.
+    ProcessState::initWithDriver("/dev/vndbinder");
 
+    ProcessState::self()->startThreadPool();
     // Extra threads may be needed to handle a stacked IPC sequence that
     // contains alternating binder and hwbinder calls. (See b/35283480.)
-    android::hardware::configureRpcThreadpool(8, true /* callerWillJoin */);
+    hardware::configureRpcThreadpool(8, true /* callerWillJoin */);
 
     // Create IComponentStore service.
     {
-        using namespace ::android::hardware::media::c2::V1_0;
-        android::sp<IComponentStore> store;
+        using namespace ::android::hardware::media::c2::V1_1;
+        sp<IComponentStore> store;
 
-        // Vendor's TODO: Replace this with
+        // TODO: Replace this with
         // store = new utils::ComponentStore(
         //         /* implementation of C2ComponentStore */);
-        ALOGD("Instantiating Codec2's dummy IComponentStore service...");
+        LOG(DEBUG) << "Instantiating Codec2's IComponentStore service...";
         store = new utils::ComponentStore(
                 std::make_shared<DummyC2Store>());
 
         if (store == nullptr) {
-            ALOGE("Cannot create Codec2's IComponentStore service.");
+            LOG(ERROR) << "Cannot create Codec2's IComponentStore service.";
         } else {
-            if (store->registerAsService("default") != android::OK) {
-                ALOGE("Cannot register Codec2's "
-                        "IComponentStore service.");
+            constexpr char const* serviceName = "default";
+            if (store->registerAsService(serviceName) != OK) {
+                LOG(ERROR) << "Cannot register Codec2's IComponentStore service"
+                              " with instance name << \""
+                           << serviceName << "\".";
             } else {
-                ALOGI("Codec2's IComponentStore service created.");
+                LOG(DEBUG) << "Codec2's IComponentStore service registered. "
+                              "Instance name: \"" << serviceName << "\".";
             }
         }
     }
 
-    // Register IOmxStore service.
-    {
-        using namespace ::android::hardware::media::omx::V1_0;
-        android::sp<IOmxStore> omxStore = new implementation::OmxStore();
-        if (omxStore == nullptr) {
-            ALOGE("Cannot create IOmxStore HAL service.");
-        } else if (omxStore->registerAsService() != android::OK) {
-            ALOGE("Cannot register IOmxStore HAL service.");
-        }
-    }
-
-    android::hardware::joinRpcThreadpool();
+    hardware::joinRpcThreadpool();
     return 0;
 }
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index ec576c9..59ac94b 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -9,7 +9,6 @@
         "CCodecConfig.cpp",
         "Codec2Buffer.cpp",
         "Codec2InfoBuilder.cpp",
-        "Omx2IGraphicBufferSource.cpp",
         "PipelineWatcher.cpp",
         "ReflectedParamUpdater.cpp",
         "SkipCutBuffer.cpp",
@@ -28,12 +27,11 @@
 
     shared_libs: [
         "android.hardware.cas.native@1.0",
-        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.drm@1.0",
         "android.hardware.media.c2@1.0",
         "android.hardware.media.omx@1.0",
         "libbase",
         "libbinder",
-        "libcodec2",
         "libcodec2_client",
         "libcodec2_vndk",
         "libcutils",
@@ -48,7 +46,6 @@
         "libstagefright_codecbase",
         "libstagefright_foundation",
         "libstagefright_omx",
-        "libstagefright_omx_utils",
         "libstagefright_xmlparser",
         "libui",
         "libutils",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 4a31953..c78cdc1 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -26,8 +26,8 @@
 #include <C2ParamInternal.h>
 #include <C2PlatformSupport.h>
 
-#include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android-base/stringprintf.h>
@@ -35,8 +35,11 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <media/omx/1.0/WGraphicBufferSource.h>
+#include <media/omx/1.0/WOmxNode.h>
+#include <media/openmax/OMX_Core.h>
 #include <media/openmax/OMX_IndexExt.h>
+#include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
+#include <media/stagefright/omx/OmxGraphicBufferSource.h>
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/PersistentSurface.h>
@@ -45,7 +48,6 @@
 #include "CCodec.h"
 #include "CCodecBufferChannel.h"
 #include "InputSurfaceWrapper.h"
-#include "Omx2IGraphicBufferSource.h"
 
 extern "C" android::PersistentSurface *CreateInputSurface();
 
@@ -54,9 +56,10 @@
 using namespace std::chrono_literals;
 using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
 using android::base::StringPrintf;
-using BGraphicBufferSource = ::android::IGraphicBufferSource;
 using ::android::hardware::media::c2::V1_0::IInputSurface;
 
+typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource;
+
 namespace {
 
 class CCodecWatchdog : public AHandler {
@@ -180,9 +183,10 @@
 
 class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
 public:
-//    explicit GraphicBufferSourceWrapper(const sp<BGraphicBufferSource> &source) : mSource(source) {}
+    typedef hardware::media::omx::V1_0::Status OmxStatus;
+
     GraphicBufferSourceWrapper(
-            const sp<BGraphicBufferSource> &source,
+            const sp<HGraphicBufferSource> &source,
             uint32_t width,
             uint32_t height,
             uint64_t usage)
@@ -194,6 +198,7 @@
 
     status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
         mNode = new C2OMXNode(comp);
+        mOmxNode = new hardware::media::omx::V1_0::utils::TWOmxNode(mNode);
         mNode->setFrameSize(mWidth, mHeight);
 
         // Usage is queried during configure(), so setting it beforehand.
@@ -204,7 +209,8 @@
 
         // NOTE: we do not use/pass through color aspects from GraphicBufferSource as we
         // communicate that directly to the component.
-        mSource->configure(mNode, mDataSpace);
+        mSource->configure(
+                mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace));
         return OK;
     }
 
@@ -220,21 +226,16 @@
         source->onOmxIdle();
         source->onOmxLoaded();
         mNode.clear();
+        mOmxNode.clear();
     }
 
-    status_t GetStatus(const binder::Status &status) {
-        status_t err = OK;
-        if (!status.isOk()) {
-            err = status.serviceSpecificErrorCode();
-            if (err == OK) {
-                err = status.transactionError();
-                if (err == OK) {
-                    // binder status failed, but there is no servie or transaction error
-                    err = UNKNOWN_ERROR;
-                }
-            }
+    status_t GetStatus(hardware::Return<OmxStatus> &&status) {
+        if (status.isOk()) {
+            return static_cast<status_t>(status.withDefault(OmxStatus::UNKNOWN_ERROR));
+        } else if (status.isDeadObject()) {
+            return DEAD_OBJECT;
         }
-        return err;
+        return UNKNOWN_ERROR;
     }
 
     status_t start() override {
@@ -359,7 +360,15 @@
                 err = res;
             } else {
                 status << " delayUs";
-                res = GetStatus(mSource->getStopTimeOffsetUs(&config.mInputDelayUs));
+                hardware::Return<void> trans = mSource->getStopTimeOffsetUs(
+                        [&res, &delayUs = config.mInputDelayUs](
+                                auto status, auto stopTimeOffsetUs) {
+                            res = static_cast<status_t>(status);
+                            delayUs = stopTimeOffsetUs;
+                        });
+                if (!trans.isOk()) {
+                    res = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR;
+                }
                 if (res != OK) {
                     status << " (=> " << asString(res) << ")";
                 } else {
@@ -388,8 +397,9 @@
     }
 
 private:
-    sp<BGraphicBufferSource> mSource;
+    sp<HGraphicBufferSource> mSource;
     sp<C2OMXNode> mNode;
+    sp<hardware::media::omx::V1_0::IOmxNode> mOmxNode;
     uint32_t mWidth;
     uint32_t mHeight;
     Config mConfig;
@@ -1092,9 +1102,7 @@
                 gbs = source;
             });
     if (transStatus.isOk() && s == OmxStatus::OK) {
-        return new PersistentSurface(
-                new H2BGraphicBufferProducer(gbp),
-                sp<::android::IGraphicBufferSource>(new LWGraphicBufferSource(gbs)));
+        return new PersistentSurface(new H2BGraphicBufferProducer(gbp), gbs);
     }
 
     return nullptr;
@@ -1125,28 +1133,28 @@
     }
 
     sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface();
+    sp<hidl::base::V1_0::IBase> hidlTarget = persistentSurface->getHidlTarget();
+    sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(hidlTarget);
+    sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
 
-    if (persistentSurface->getHidlTarget()) {
-        sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
-                persistentSurface->getHidlTarget());
-        if (!hidlInputSurface) {
-            ALOGE("Corrupted input surface");
-            mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
-            return;
-        }
+    if (hidlInputSurface) {
         std::shared_ptr<Codec2Client::InputSurface> inputSurface =
                 std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
         err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
                 inputSurface));
         bufferProducer = inputSurface->getGraphicBufferProducer();
-    } else {
+    } else if (gbs) {
         int32_t width = 0;
         (void)outputFormat->findInt32("width", &width);
         int32_t height = 0;
         (void)outputFormat->findInt32("height", &height);
         err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
-                persistentSurface->getBufferSource(), width, height, usage));
+                gbs, width, height, usage));
         bufferProducer = persistentSurface->getBufferProducer();
+    } else {
+        ALOGE("Corrupted input surface");
+        mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
+        return;
     }
 
     if (err != OK) {
@@ -1212,15 +1220,10 @@
         outputFormat = config->mOutputFormat;
         usage = config->mISConfig ? config->mISConfig->mUsage : 0;
     }
-    auto hidlTarget = surface->getHidlTarget();
-    if (hidlTarget) {
-        sp<IInputSurface> inputSurface =
-                IInputSurface::castFrom(hidlTarget);
-        if (!inputSurface) {
-            ALOGE("Failed to set input surface: Corrupted surface.");
-            mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
-            return;
-        }
+    sp<hidl::base::V1_0::IBase> hidlTarget = surface->getHidlTarget();
+    sp<IInputSurface> inputSurface = IInputSurface::castFrom(hidlTarget);
+    sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
+    if (inputSurface) {
         status_t err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
                 std::make_shared<Codec2Client::InputSurface>(inputSurface)));
         if (err != OK) {
@@ -1228,18 +1231,22 @@
             mCallback->onInputSurfaceDeclined(err);
             return;
         }
-    } else {
+    } else if (gbs) {
         int32_t width = 0;
         (void)outputFormat->findInt32("width", &width);
         int32_t height = 0;
         (void)outputFormat->findInt32("height", &height);
         status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
-                surface->getBufferSource(), width, height, usage));
+                gbs, width, height, usage));
         if (err != OK) {
             ALOGE("Failed to set up input surface: %d", err);
             mCallback->onInputSurfaceDeclined(err);
             return;
         }
+    } else {
+        ALOGE("Failed to set input surface: Corrupted surface.");
+        mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
+        return;
     }
     mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
 }
@@ -1867,6 +1874,7 @@
 // Create Codec 2.0 input surface
 extern "C" android::PersistentSurface *CreateInputSurface() {
     using namespace android;
+    using ::android::hardware::media::omx::V1_0::implementation::TWGraphicBufferSource;
     // Attempt to create a Codec2's input surface.
     std::shared_ptr<Codec2Client::InputSurface> inputSurface =
             Codec2Client::CreateInputSurface();
@@ -1880,9 +1888,7 @@
                 return nullptr;
             }
             return new PersistentSurface(
-                    gbs->getIGraphicBufferProducer(),
-                    sp<IGraphicBufferSource>(
-                        new Omx2IGraphicBufferSource(gbs)));
+                    gbs->getIGraphicBufferProducer(), new TWGraphicBufferSource(gbs));
         } else {
             return nullptr;
         }
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 2efb987..39f3f35 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -27,9 +27,12 @@
 #include <C2Debug.h>
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/drm/1.0/types.h>
 #include <android-base/stringprintf.h>
 #include <binder/MemoryDealer.h>
+#include <cutils/properties.h>
 #include <gui/Surface.h>
+#include <hidlmemory/FrameworkUtils.h>
 #include <media/openmax/OMX_Core.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ALookup.h>
@@ -51,10 +54,14 @@
 using hardware::hidl_handle;
 using hardware::hidl_string;
 using hardware::hidl_vec;
+using hardware::fromHeap;
+using hardware::HidlMemory;
+
 using namespace hardware::cas::V1_0;
 using namespace hardware::cas::native::V1_0;
 
 using CasStatus = hardware::cas::V1_0::Status;
+using DrmBufferType = hardware::drm::V1_0::BufferType;
 
 namespace {
 
@@ -430,15 +437,16 @@
     ssize_t result = -1;
     ssize_t codecDataOffset = 0;
     if (mCrypto != nullptr) {
-        ICrypto::DestinationBuffer destination;
+        hardware::drm::V1_0::DestinationBuffer destination;
         if (secure) {
-            destination.mType = ICrypto::kDestinationTypeNativeHandle;
-            destination.mHandle = encryptedBuffer->handle();
+            destination.type = DrmBufferType::NATIVE_HANDLE;
+            destination.secureMemory = hidl_handle(encryptedBuffer->handle());
         } else {
-            destination.mType = ICrypto::kDestinationTypeSharedMemory;
-            destination.mSharedMemory = mDecryptDestination;
+            destination.type = DrmBufferType::SHARED_MEMORY;
+            IMemoryToSharedBuffer(
+                    mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
         }
-        ICrypto::SourceBuffer source;
+        hardware::drm::V1_0::SharedBuffer source;
         encryptedBuffer->fillSourceBuffer(&source);
         result = mCrypto->decrypt(
                 key, iv, mode, pattern, source, buffer->offset(),
@@ -446,7 +454,7 @@
         if (result < 0) {
             return result;
         }
-        if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
+        if (destination.type == DrmBufferType::SHARED_MEMORY) {
             encryptedBuffer->copyDecryptedContent(mDecryptDestination, result);
         }
     } else {
@@ -918,7 +926,8 @@
                     mDecryptDestination = mDealer->allocate((size_t)capacity);
                 }
                 if (mCrypto != nullptr && mHeapSeqNum < 0) {
-                    mHeapSeqNum = mCrypto->setHeap(mDealer->getMemoryHeap());
+                    sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
+                    mHeapSeqNum = mCrypto->setHeap(heap);
                 } else {
                     mHeapSeqNum = -1;
                 }
@@ -1083,8 +1092,7 @@
                     outputGeneration);
         }
 
-        if (oStreamFormat.value == C2BufferData::LINEAR
-                && mComponentName.find("c2.qti.") == std::string::npos) {
+        if (oStreamFormat.value == C2BufferData::LINEAR) {
             // WORKAROUND: if we're using early CSD workaround we convert to
             //             array mode, to appease apps assuming the output
             //             buffers to be of the same size.
@@ -1136,8 +1144,9 @@
     }
 
     C2StreamBufferTypeSetting::output oStreamFormat(0u);
-    c2_status_t err = mComponent->query({ &oStreamFormat }, {}, C2_DONT_BLOCK, nullptr);
-    if (err != C2_OK) {
+    C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
+    c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
+    if (err != C2_OK && err != C2_BAD_INDEX) {
         return UNKNOWN_ERROR;
     }
     size_t numInputSlots = mInput.lock()->numSlots;
@@ -1177,7 +1186,7 @@
                             mName, buffer->capacity(), config->size());
                 }
             } else if (oStreamFormat.value == C2BufferData::LINEAR && i == 0
-                    && mComponentName.find("c2.qti.") == std::string::npos) {
+                        && (!prepend || prepend.value == PREPEND_HEADER_TO_NONE)) {
                 // WORKAROUND: Some apps expect CSD available without queueing
                 //             any input. Queue an empty buffer to get the CSD.
                 buffer->setRange(0, 0);
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 5adcd94..ee3cdf6 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -823,6 +823,14 @@
 
     add(ConfigMapper(C2_PARAMKEY_INPUT_TIME_STRETCH, C2_PARAMKEY_INPUT_TIME_STRETCH, "value"));
 
+    add(ConfigMapper(KEY_LOW_LATENCY, C2_PARAMKEY_LOW_LATENCY_MODE, "value")
+        .limitTo(D::DECODER & (D::CONFIG | D::PARAM))
+        .withMapper([](C2Value v) -> C2Value {
+            int32_t value = 0;
+            (void)v.get(&value);
+            return value == 0 ? C2_FALSE : C2_TRUE;
+        }));
+
     /* still to do
     constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
 
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 5c8ad56..b6d18e2 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -20,6 +20,7 @@
 
 #include <hidlmemory/FrameworkUtils.h>
 #include <media/hardware/HardwareAPI.h>
+#include <media/stagefright/CodecBase.h>
 #include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -764,7 +765,11 @@
         const std::shared_ptr<C2LinearBlock> &block,
         const sp<IMemory> &memory,
         int32_t heapSeqNum)
-    : Codec2Buffer(format, new ABuffer(memory->pointer(), memory->size())),
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    : Codec2Buffer(format, new ABuffer(memory->unsecurePointer(), memory->size())),
       mBlock(block),
       mMemory(memory),
       mHeapSeqNum(heapSeqNum) {
@@ -775,9 +780,8 @@
 }
 
 void EncryptedLinearBlockBuffer::fillSourceBuffer(
-        ICrypto::SourceBuffer *source) {
-    source->mSharedMemory = mMemory;
-    source->mHeapSeqNum = mHeapSeqNum;
+        hardware::drm::V1_0::SharedBuffer *source) {
+    BufferChannelBase::IMemoryToSharedBuffer(mMemory, mHeapSeqNum, source);
 }
 
 void EncryptedLinearBlockBuffer::fillSourceBuffer(
@@ -800,7 +804,7 @@
     if (view.size() < length) {
         return false;
     }
-    memcpy(view.data(), decrypted->pointer(), length);
+    memcpy(view.data(), decrypted->unsecurePointer(), length);
     return true;
 }
 
diff --git a/media/codec2/sfplugin/Codec2Buffer.h b/media/codec2/sfplugin/Codec2Buffer.h
index 6f87101..9291c52 100644
--- a/media/codec2/sfplugin/Codec2Buffer.h
+++ b/media/codec2/sfplugin/Codec2Buffer.h
@@ -21,6 +21,7 @@
 #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>
@@ -361,7 +362,8 @@
      *
      * \param source  source buffer structure to fill.
      */
-    void fillSourceBuffer(ICrypto::SourceBuffer *source);
+    void fillSourceBuffer(
+            hardware::drm::V1_0::SharedBuffer *source);
     void fillSourceBuffer(
             hardware::cas::native::V1_0::SharedBuffer *source);
 
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index 6b75eba..745d701 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -117,8 +117,9 @@
         }
     }
 
-    // For VP9, the static info is always propagated by framework.
+    // For VP9/AV1, the static info is always propagated by framework.
     supportsHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
+    supportsHdr |= (mediaType == MIMETYPE_VIDEO_AV1);
 
     for (C2Value::Primitive profile : profileQuery[0].values.values) {
         pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 40160c7..2f3d688 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -190,6 +190,7 @@
     { C2Config::PROFILE_DV_HE_07, DolbyVisionProfileDvheDtb },
     { C2Config::PROFILE_DV_HE_08, DolbyVisionProfileDvheSt },
     { C2Config::PROFILE_DV_AV_09, DolbyVisionProfileDvavSe },
+    { C2Config::PROFILE_DV_AV1_10, DolbyVisionProfileDvav110 },
 };
 
 ALookup<C2Config::level_t, int32_t> sH263Levels = {
@@ -382,10 +383,11 @@
     // TODO: will need to disambiguate between Main8 and Main10
     { C2Config::PROFILE_AV1_0, AV1ProfileMain8 },
     { C2Config::PROFILE_AV1_0, AV1ProfileMain10 },
+    { C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10 },
+    { C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10Plus },
 };
 
 ALookup<C2Config::profile_t, int32_t> sAv1HdrProfiles = {
-    { C2Config::PROFILE_AV1_0, AV1ProfileMain10 },
     { C2Config::PROFILE_AV1_0, AV1ProfileMain10HDR10 },
 };
 
@@ -629,7 +631,7 @@
 // static
 std::shared_ptr<C2Mapper::ProfileLevelMapper>
 C2Mapper::GetProfileLevelMapper(std::string mediaType) {
-    std::transform(mediaType.begin(), mediaType.begin(), mediaType.end(), ::tolower);
+    std::transform(mediaType.begin(), mediaType.end(), mediaType.begin(), ::tolower);
     if (mediaType == MIMETYPE_AUDIO_AAC) {
         return std::make_shared<AacProfileLevelMapper>();
     } else if (mediaType == MIMETYPE_VIDEO_AVC) {
@@ -657,11 +659,13 @@
 // static
 std::shared_ptr<C2Mapper::ProfileLevelMapper>
 C2Mapper::GetHdrProfileLevelMapper(std::string mediaType, bool isHdr10Plus) {
-    std::transform(mediaType.begin(), mediaType.begin(), mediaType.end(), ::tolower);
+    std::transform(mediaType.begin(), mediaType.end(), mediaType.begin(), ::tolower);
     if (mediaType == MIMETYPE_VIDEO_HEVC) {
         return std::make_shared<HevcProfileLevelMapper>(true, isHdr10Plus);
     } else if (mediaType == MIMETYPE_VIDEO_VP9) {
         return std::make_shared<Vp9ProfileLevelMapper>(true, isHdr10Plus);
+    } else if (mediaType == MIMETYPE_VIDEO_AV1) {
+        return std::make_shared<Av1ProfileLevelMapper>(true, isHdr10Plus);
     }
     return nullptr;
 }
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 52cc7ad..4c529a6 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -51,12 +51,13 @@
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.bufferqueue@2.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hardware.media.bufferpool@2.0",
         "libbase",
-        "libbinder",
         "libcutils",
         "libdl",
         "libhardware",
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index af97e61..cd179be 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -22,6 +22,8 @@
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <cutils/native_handle.h>
 #include <hardware/gralloc.h>
 
@@ -66,6 +68,7 @@
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using PixelFormat2 = ::android::hardware::graphics::common::V1_0::PixelFormat;
 using PixelFormat3 = ::android::hardware::graphics::common::V1_2::PixelFormat;
+using PixelFormat4 = ::android::hardware::graphics::common::V1_2::PixelFormat;
 
 using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
 using BufferDescriptor2 = ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
@@ -77,6 +80,11 @@
 using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
 using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
 
+using IAllocator4 = ::android::hardware::graphics::allocator::V4_0::IAllocator;
+using BufferDescriptor4 = ::android::hardware::graphics::mapper::V4_0::BufferDescriptor;
+using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
+using IMapper4 = ::android::hardware::graphics::mapper::V4_0::IMapper;
+
 namespace /* unnamed */ {
 
 struct BufferDescriptorInfo2 {
@@ -89,6 +97,11 @@
     uint32_t stride;
 };
 
+struct BufferDescriptorInfo4 {
+    IMapper4::BufferDescriptorInfo mapperInfo;
+    uint32_t stride;
+};
+
 /* ===================================== GRALLOC ALLOCATION ==================================== */
 c2_status_t maperr2error(Error2 maperr) {
     switch (maperr) {
@@ -114,6 +127,18 @@
     return C2_CORRUPTED;
 }
 
+c2_status_t maperr2error(Error4 maperr) {
+    switch (maperr) {
+        case Error4::NONE:           return C2_OK;
+        case Error4::BAD_DESCRIPTOR: return C2_BAD_VALUE;
+        case Error4::BAD_BUFFER:     return C2_BAD_VALUE;
+        case Error4::BAD_VALUE:      return C2_BAD_VALUE;
+        case Error4::NO_RESOURCES:   return C2_NO_MEMORY;
+        case Error4::UNSUPPORTED:    return C2_CANNOT_DO;
+    }
+    return C2_CORRUPTED;
+}
+
 bool native_handle_is_invalid(const native_handle_t *const handle) {
     // perform basic validation of a native handle
     if (handle == nullptr) {
@@ -321,6 +346,12 @@
               hidl_handle &hidlHandle,
               const C2HandleGralloc *const handle,
               C2Allocator::id_t allocatorId);
+    C2AllocationGralloc(
+              const BufferDescriptorInfo4 &info,
+              const sp<IMapper4> &mapper,
+              hidl_handle &hidlHandle,
+              const C2HandleGralloc *const handle,
+              C2Allocator::id_t allocatorId);
     int dup() const;
     c2_status_t status() const;
 
@@ -329,6 +360,8 @@
     const sp<IMapper2> mMapper2{nullptr};
     const BufferDescriptorInfo3 mInfo3{};
     const sp<IMapper3> mMapper3{nullptr};
+    const BufferDescriptorInfo4 mInfo4{};
+    const sp<IMapper4> mMapper4{nullptr};
     const hidl_handle mHidlHandle;
     const C2HandleGralloc *mHandle;
     buffer_handle_t mBuffer;
@@ -372,6 +405,23 @@
       mAllocatorId(allocatorId) {
 }
 
+C2AllocationGralloc::C2AllocationGralloc(
+          const BufferDescriptorInfo4 &info,
+          const sp<IMapper4> &mapper,
+          hidl_handle &hidlHandle,
+          const C2HandleGralloc *const handle,
+          C2Allocator::id_t allocatorId)
+    : C2GraphicAllocation(info.mapperInfo.width, info.mapperInfo.height),
+      mInfo4(info),
+      mMapper4(mapper),
+      mHidlHandle(std::move(hidlHandle)),
+      mHandle(handle),
+      mBuffer(nullptr),
+      mLockedHandle(nullptr),
+      mLocked(false),
+      mAllocatorId(allocatorId) {
+}
+
 C2AllocationGralloc::~C2AllocationGralloc() {
     if (mBuffer && mLocked) {
         // implementation ignores addresss and rect
@@ -384,12 +434,18 @@
                     mBuffer)).isOk()) {
                 ALOGE("failed transaction: freeBuffer");
             }
-        } else {
+        } else if (mMapper3) {
             if (!mMapper3->freeBuffer(const_cast<native_handle_t *>(
                     mBuffer)).isOk()) {
                 ALOGE("failed transaction: freeBuffer");
             }
+        } else {
+            if (!mMapper4->freeBuffer(const_cast<native_handle_t *>(
+                    mBuffer)).isOk()) {
+                ALOGE("failed transaction: freeBuffer");
+            }
         }
+
     }
     if (mHandle) {
         native_handle_delete(
@@ -435,7 +491,7 @@
                 ALOGE("failed transaction: importBuffer");
                 return C2_CORRUPTED;
             }
-        } else {
+        } else if (mMapper3) {
             if (!mMapper3->importBuffer(
                     mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
                         err = maperr2error(maperr);
@@ -446,6 +502,17 @@
                 ALOGE("failed transaction: importBuffer (@3.0)");
                 return C2_CORRUPTED;
             }
+        } else {
+            if (!mMapper4->importBuffer(
+                    mHidlHandle, [&err, this](const auto &maperr, const auto &buffer) {
+                        err = maperr2error(maperr);
+                        if (err == C2_OK) {
+                            mBuffer = static_cast<buffer_handle_t>(buffer);
+                        }
+                    }).isOk()) {
+                ALOGE("failed transaction: importBuffer (@4.0)");
+                return C2_CORRUPTED;
+            }
         }
         if (err != C2_OK) {
             ALOGD("importBuffer failed: %d", err);
@@ -466,19 +533,29 @@
                     mBuffer, mInfo2.mapperInfo.width, mInfo2.mapperInfo.height,
                     (uint32_t)mInfo2.mapperInfo.format, mInfo2.mapperInfo.usage,
                     mInfo2.stride, generation, igbp_id, igbp_slot);
-        } else {
+        } else if (mMapper3) {
             mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
                     mBuffer, mInfo3.mapperInfo.width, mInfo3.mapperInfo.height,
                     (uint32_t)mInfo3.mapperInfo.format, mInfo3.mapperInfo.usage,
                     mInfo3.stride, generation, igbp_id, igbp_slot);
+        } else {
+            mLockedHandle = C2HandleGralloc::WrapAndMoveNativeHandle(
+                    mBuffer, mInfo4.mapperInfo.width, mInfo4.mapperInfo.height,
+                    (uint32_t)mInfo4.mapperInfo.format, mInfo4.mapperInfo.usage,
+                    mInfo4.stride, generation, igbp_id, igbp_slot);
         }
     }
 
-    PixelFormat3 format = mMapper2 ?
-            PixelFormat3(mInfo2.mapperInfo.format) :
-            PixelFormat3(mInfo3.mapperInfo.format);
+    PixelFormat4 format;
+    if (mMapper2) {
+        format = PixelFormat4(mInfo2.mapperInfo.format);
+    } else if (mMapper3) {
+        format = PixelFormat4(mInfo3.mapperInfo.format);
+    } else {
+        format = PixelFormat4(mInfo4.mapperInfo.format);
+    }
     switch (format) {
-        case PixelFormat3::RGBA_1010102: {
+        case PixelFormat4::RGBA_1010102: {
             // TRICKY: this is used for media as YUV444 in the case when it is queued directly to a
             // Surface. In all other cases it is RGBA. We don't know which case it is here, so
             // default to YUV for now.
@@ -500,7 +577,7 @@
                     ALOGE("failed transaction: lock(RGBA_1010102)");
                     return C2_CORRUPTED;
                 }
-            } else {
+            } else if (mMapper3) {
                 if (!mMapper3->lock(
                         const_cast<native_handle_t *>(mBuffer),
                         grallocUsage,
@@ -520,6 +597,26 @@
                     ALOGE("failed transaction: lock(RGBA_1010102) (@3.0)");
                     return C2_CORRUPTED;
                 }
+            } else {
+                if (!mMapper4->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer,
+                                         int32_t bytesPerPixel, int32_t bytesPerStride) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                            (void)bytesPerPixel;
+                            (void)bytesPerStride;
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_1010102) (@4.0)");
+                    return C2_CORRUPTED;
+                }
             }
             if (err != C2_OK) {
                 ALOGD("lock failed: %d", err);
@@ -533,9 +630,14 @@
             layout->type = C2PlanarLayout::TYPE_YUVA;
             layout->numPlanes = 4;
             layout->rootPlanes = 1;
-            int32_t stride = mMapper2 ?
-                    int32_t(mInfo2.stride) :
-                    int32_t(mInfo3.stride);
+            int32_t stride;
+            if (mMapper2) {
+                stride = int32_t(mInfo2.stride);
+            } else if (mMapper3) {
+                stride = int32_t(mInfo3.stride);
+            } else {
+                stride = int32_t(mInfo4.stride);
+            }
             layout->planes[C2PlanarLayout::PLANE_Y] = {
                 C2PlaneInfo::CHANNEL_Y,         // channel
                 4,                              // colInc
@@ -591,10 +693,10 @@
             break;
         }
 
-        case PixelFormat3::RGBA_8888:
+        case PixelFormat4::RGBA_8888:
             // TODO: alpha channel
             // fall-through
-        case PixelFormat3::RGBX_8888: {
+        case PixelFormat4::RGBX_8888: {
             void *pointer = nullptr;
             if (mMapper2) {
                 if (!mMapper2->lock(
@@ -613,7 +715,7 @@
                     ALOGE("failed transaction: lock(RGBA_8888)");
                     return C2_CORRUPTED;
                 }
-            } else {
+            } else if (mMapper3) {
                 if (!mMapper3->lock(
                         const_cast<native_handle_t *>(mBuffer),
                         grallocUsage,
@@ -633,6 +735,26 @@
                     ALOGE("failed transaction: lock(RGBA_8888) (@3.0)");
                     return C2_CORRUPTED;
                 }
+            } else {
+                if (!mMapper4->lock(
+                        const_cast<native_handle_t *>(mBuffer),
+                        grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &pointer](const auto &maperr, const auto &mapPointer,
+                                         int32_t bytesPerPixel, int32_t bytesPerStride) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                pointer = mapPointer;
+                            }
+                            (void)bytesPerPixel;
+                            (void)bytesPerStride;
+                        }).isOk()) {
+                    ALOGE("failed transaction: lock(RGBA_8888) (@4.0)");
+                    return C2_CORRUPTED;
+                }
             }
             if (err != C2_OK) {
                 ALOGD("lock failed: %d", err);
@@ -644,9 +766,14 @@
             layout->type = C2PlanarLayout::TYPE_RGB;
             layout->numPlanes = 3;
             layout->rootPlanes = 1;
-            int32_t stride = mMapper2 ?
-                    int32_t(mInfo2.stride) :
-                    int32_t(mInfo3.stride);
+            int32_t stride;
+            if (mMapper2) {
+                stride = int32_t(mInfo2.stride);
+            } else if (mMapper3) {
+                stride = int32_t(mInfo3.stride);
+            } else {
+                stride = int32_t(mInfo4.stride);
+            }
             layout->planes[C2PlanarLayout::PLANE_R] = {
                 C2PlaneInfo::CHANNEL_R,         // channel
                 4,                              // colInc
@@ -689,9 +816,9 @@
             break;
         }
 
-        case PixelFormat3::YCBCR_420_888:
+        case PixelFormat4::YCBCR_420_888:
             // fall-through
-        case PixelFormat3::YV12:
+        case PixelFormat4::YV12:
             // fall-through
         default: {
             struct YCbCrLayout {
@@ -725,7 +852,7 @@
                     ALOGE("failed transaction: lockYCbCr");
                     return C2_CORRUPTED;
                 }
-            } else {
+            } else if (mMapper3) {
                 if (!mMapper3->lockYCbCr(
                         const_cast<native_handle_t *>(mBuffer), grallocUsage,
                         { (int32_t)rect.left, (int32_t)rect.top,
@@ -747,6 +874,28 @@
                     ALOGE("failed transaction: lockYCbCr (@3.0)");
                     return C2_CORRUPTED;
                 }
+            } else {
+                if (!mMapper4->lockYCbCr(
+                        const_cast<native_handle_t *>(mBuffer), grallocUsage,
+                        { (int32_t)rect.left, (int32_t)rect.top,
+                          (int32_t)rect.width, (int32_t)rect.height },
+                        // TODO: fence
+                        hidl_handle(),
+                        [&err, &ycbcrLayout](const auto &maperr, const auto &mapLayout) {
+                            err = maperr2error(maperr);
+                            if (err == C2_OK) {
+                                ycbcrLayout = YCbCrLayout{
+                                        mapLayout.y,
+                                        mapLayout.cb,
+                                        mapLayout.cr,
+                                        mapLayout.yStride,
+                                        mapLayout.cStride,
+                                        mapLayout.chromaStep};
+                            }
+                        }).isOk()) {
+                    ALOGE("failed transaction: lockYCbCr (@4.0)");
+                    return C2_CORRUPTED;
+                }
             }
             if (err != C2_OK) {
                 ALOGD("lockYCbCr failed: %d", err);
@@ -839,7 +988,7 @@
             ALOGE("failed transaction: unlock");
             return C2_CORRUPTED;
         }
-    } else {
+    } else if (mMapper3) {
         if (!mMapper3->unlock(
                 const_cast<native_handle_t *>(mBuffer),
                 [&err, &fence](const auto &maperr, const auto &releaseFence) {
@@ -854,6 +1003,21 @@
             ALOGE("failed transaction: unlock (@3.0)");
             return C2_CORRUPTED;
         }
+    } else {
+        if (!mMapper4->unlock(
+                const_cast<native_handle_t *>(mBuffer),
+                [&err, &fence](const auto &maperr, const auto &releaseFence) {
+                    // TODO
+                    (void) fence;
+                    (void) releaseFence;
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        // TODO: fence
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: unlock (@4.0)");
+            return C2_CORRUPTED;
+        }
     }
     if (err == C2_OK) {
         mLocked = false;
@@ -899,6 +1063,8 @@
     sp<IMapper2> mMapper2;
     sp<IAllocator3> mAllocator3;
     sp<IMapper3> mMapper3;
+    sp<IAllocator4> mAllocator4;
+    sp<IMapper4> mMapper4;
     const bool mBufferQueue;
 };
 
@@ -918,17 +1084,23 @@
     mTraits = std::make_shared<C2Allocator::Traits>(traits);
 
     // gralloc allocator is a singleton, so all objects share a global service
-    mAllocator3 = IAllocator3::getService();
-    mMapper3 = IMapper3::getService();
-    if (!mAllocator3 || !mMapper3) {
-        mAllocator3 = nullptr;
-        mMapper3 = nullptr;
-        mAllocator2 = IAllocator2::getService();
-        mMapper2 = IMapper2::getService();
-        if (!mAllocator2 || !mMapper2) {
-            mAllocator2 = nullptr;
-            mMapper2 = nullptr;
-            mInit = C2_CORRUPTED;
+    mAllocator4 = IAllocator4::getService();
+    mMapper4 = IMapper4::getService();
+    if (!mAllocator4 || !mMapper4) {
+        mAllocator4 = nullptr;
+        mMapper4 = nullptr;
+        mAllocator3 = IAllocator3::getService();
+        mMapper3 = IMapper3::getService();
+        if (!mAllocator3 || !mMapper3) {
+            mAllocator3 = nullptr;
+            mMapper3 = nullptr;
+            mAllocator2 = IAllocator2::getService();
+            mMapper2 = IMapper2::getService();
+            if (!mAllocator2 || !mMapper2) {
+                mAllocator2 = nullptr;
+                mMapper2 = nullptr;
+                mInit = C2_CORRUPTED;
+            }
         }
     }
 }
@@ -1000,13 +1172,13 @@
                         0, 0, mBufferQueue ? ~0 : 0),
                 mTraits->id));
         return C2_OK;
-    } else {
+    } else if (mMapper3) {
         BufferDescriptorInfo3 info = {
             {
                 width,
                 height,
                 1u,  // layerCount
-                PixelFormat3(format),
+                PixelFormat4(format),
                 grallocUsage,
             },
             0u,  // stride placeholder
@@ -1057,6 +1229,64 @@
                         0, 0, mBufferQueue ? ~0 : 0),
                 mTraits->id));
         return C2_OK;
+    } else {
+        BufferDescriptorInfo4 info = {
+            {
+                "C2GrallocAllocation",
+                width,
+                height,
+                1u,  // layerCount
+                PixelFormat4(format),
+                grallocUsage,
+            },
+            0u,  // stride placeholder
+        };
+        BufferDescriptor4 desc;
+        if (!mMapper4->createDescriptor(
+                info.mapperInfo, [&err, &desc](const auto &maperr, const auto &descriptor) {
+                    err = maperr2error(maperr);
+                    if (err == C2_OK) {
+                        desc = descriptor;
+                    }
+                }).isOk()) {
+            ALOGE("failed transaction: createDescriptor");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+
+        // IAllocator shares IMapper error codes.
+        if (!mAllocator4->allocate(
+                desc,
+                1u,
+                [&err, &buffer, &info](const auto &maperr, const auto &stride, auto &buffers) {
+                    err = maperr2error(maperr);
+                    if (err != C2_OK) {
+                        return;
+                    }
+                    if (buffers.size() != 1u) {
+                        err = C2_CORRUPTED;
+                        return;
+                    }
+                    info.stride = stride;
+                    buffer = buffers[0];
+                }).isOk()) {
+            ALOGE("failed transaction: allocate");
+            return C2_CORRUPTED;
+        }
+        if (err != C2_OK) {
+            return err;
+        }
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper4, buffer,
+                C2HandleGralloc::WrapAndMoveNativeHandle(
+                        buffer.getNativeHandle(),
+                        width, height,
+                        format, grallocUsage, info.stride,
+                        0, 0, mBufferQueue ? ~0 : 0),
+                mTraits->id));
+        return C2_OK;
     }
 }
 
@@ -1086,7 +1316,7 @@
         allocation->reset(new C2AllocationGralloc(
                 info, mMapper2, hidlHandle, grallocHandle, mTraits->id));
         return C2_OK;
-    } else {
+    } else if (mMapper3) {
         BufferDescriptorInfo3 info;
         info.mapperInfo.layerCount = 1u;
         uint32_t generation;
@@ -1109,6 +1339,29 @@
         allocation->reset(new C2AllocationGralloc(
                 info, mMapper3, hidlHandle, grallocHandle, mTraits->id));
         return C2_OK;
+    } else {
+        BufferDescriptorInfo4 info;
+        info.mapperInfo.layerCount = 1u;
+        uint32_t generation;
+        uint64_t igbp_id;
+        uint32_t igbp_slot;
+        const C2HandleGralloc *grallocHandle = C2HandleGralloc::Import(
+                handle,
+                &info.mapperInfo.width, &info.mapperInfo.height,
+                (uint32_t *)&info.mapperInfo.format,
+                (uint64_t *)&info.mapperInfo.usage,
+                &info.stride,
+                &generation, &igbp_id, &igbp_slot);
+        if (grallocHandle == nullptr) {
+            return C2_BAD_VALUE;
+        }
+
+        hidl_handle hidlHandle;
+        hidlHandle.setTo(C2HandleGralloc::UnwrapNativeHandle(grallocHandle), true);
+
+        allocation->reset(new C2AllocationGralloc(
+                info, mMapper4, hidlHandle, grallocHandle, mTraits->id));
+        return C2_OK;
     }
 }
 
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 1744d3d..38821fd 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -12,10 +12,10 @@
     shared_libs: [
         "liblog",
         "libmediandk",
+        "libstagefright_flacdec",
     ],
 
     static_libs: [
-        "libstagefright_flacdec",
         "libstagefright_foundation",
         "libstagefright_metadatautils",
         "libwebm",
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 12982ed..6f85960 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -133,6 +133,7 @@
 
     bool mIsAVC;
     bool mIsHEVC;
+    bool mIsDolbyVision;
     bool mIsAC4;
     bool mIsPcm;
     size_t mNALLengthSize;
@@ -337,6 +338,14 @@
         case FOURCC("hvc1"):
         case FOURCC("hev1"):
             return MEDIA_MIMETYPE_VIDEO_HEVC;
+
+        case FOURCC("dvav"):
+        case FOURCC("dva1"):
+        case FOURCC("dvhe"):
+        case FOURCC("dvh1"):
+        case FOURCC("dav1"):
+            return MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
+
         case FOURCC("ac-4"):
             return MEDIA_MIMETYPE_AUDIO_AC4;
         case FOURCC("Opus"):
@@ -1062,6 +1071,67 @@
                     mLastTrack->mTx3gBuffer = NULL;
                 }
 
+                const char *mime;
+                AMediaFormat_getString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, &mime);
+
+                if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+                    void *data;
+                    size_t size;
+
+                    if (AMediaFormat_getBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+                        const uint8_t *ptr = (const uint8_t *)data;
+                        const uint8_t profile = ptr[2] >> 1;
+                        const uint8_t bl_compatibility_id = (ptr[4]) >> 4;
+                        bool create_two_tracks = false;
+
+                        if (bl_compatibility_id && bl_compatibility_id != 15) {
+                            create_two_tracks = true;
+                        }
+
+                        if (4 == profile || 7 == profile ||
+                                (profile >= 8 && profile < 11 && create_two_tracks)) {
+                            // we need a backward compatible track
+                            ALOGV("Adding new backward compatible track");
+                            Track *track_b = new Track;
+
+                            track_b->timescale = mLastTrack->timescale;
+                            track_b->sampleTable = mLastTrack->sampleTable;
+                            track_b->includes_expensive_metadata = mLastTrack->includes_expensive_metadata;
+                            track_b->skipTrack = mLastTrack->skipTrack;
+                            track_b->has_elst = mLastTrack->has_elst;
+                            track_b->elst_media_time = mLastTrack->elst_media_time;
+                            track_b->elst_segment_duration = mLastTrack->elst_segment_duration;
+                            track_b->elstShiftStartTicks = mLastTrack->elstShiftStartTicks;
+                            track_b->subsample_encryption = mLastTrack->subsample_encryption;
+
+                            track_b->mTx3gBuffer = mLastTrack->mTx3gBuffer;
+                            track_b->mTx3gSize = mLastTrack->mTx3gSize;
+                            track_b->mTx3gFilled = mLastTrack->mTx3gFilled;
+
+                            track_b->meta = AMediaFormat_new();
+                            AMediaFormat_copy(track_b->meta, mLastTrack->meta);
+
+                            mLastTrack->next = track_b;
+                            track_b->next = NULL;
+
+                            auto id = track_b->meta->mFormat->findEntryByName(AMEDIAFORMAT_KEY_CSD_2);
+                            track_b->meta->mFormat->removeEntryAt(id);
+
+                            if (4 == profile || 7 == profile || 8 == profile ) {
+                                AMediaFormat_setString(track_b->meta,
+                                        AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_HEVC);
+                            } else if (9 == profile) {
+                                AMediaFormat_setString(track_b->meta,
+                                        AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AVC);
+                            } else if (10 == profile) {
+                                AMediaFormat_setString(track_b->meta,
+                                        AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_VIDEO_AV1);
+                            } // Should never get to else part
+
+                            mLastTrack = track_b;
+                        }
+                    }
+                }
             } else if (chunk_type == FOURCC("moov")) {
                 mInitCheck = OK;
 
@@ -1830,6 +1900,11 @@
         case FOURCC("avc1"):
         case FOURCC("hvc1"):
         case FOURCC("hev1"):
+        case FOURCC("dvav"):
+        case FOURCC("dva1"):
+        case FOURCC("dvhe"):
+        case FOURCC("dvh1"):
+        case FOURCC("dav1"):
         case FOURCC("av01"):
         {
             uint8_t buffer[78];
@@ -1984,7 +2059,8 @@
                     // for audio, use 128KB
                     max_size = 1024 * 128;
                 } else if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
-                        || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+                        || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)
+                        || !strcmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
                     // AVC & HEVC requires compression ratio of at least 2, and uses
                     // macroblocks
                     max_size = ((width + 15) / 16) * ((height + 15) / 16) * 192;
@@ -2315,6 +2391,33 @@
             *offset += chunk_size;
             break;
         }
+        case FOURCC("dvcC"):
+        case FOURCC("dvvC"): {
+
+            CHECK_EQ(chunk_data_size, 24);
+
+            auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+
+            if (buffer.get() == NULL) {
+                ALOGE("b/28471206");
+                return NO_MEMORY;
+            }
+
+            if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+                return ERROR_IO;
+            }
+
+            if (mLastTrack == NULL)
+                return ERROR_MALFORMED;
+
+            AMediaFormat_setBuffer(mLastTrack->meta, AMEDIAFORMAT_KEY_CSD_2,
+                                   buffer.get(), chunk_data_size);
+            AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME,
+                                   MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
+
+            *offset += chunk_size;
+            break;
+        }
         case FOURCC("d263"):
         {
             *offset += chunk_size;
@@ -4127,7 +4230,20 @@
         if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
             itemTable = mItemTable;
         }
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+        void *data;
+        size_t size;
+        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+            return NULL;
+        }
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        // dv_major.dv_minor Should be 1.0 or 2.1
+        if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+            return NULL;
+        }
+   } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
         void *data;
         size_t size;
         if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
@@ -4172,6 +4288,10 @@
         if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size)) {
             return ERROR_MALFORMED;
         }
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+        if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_2, &data, &size)) {
+            return ERROR_MALFORMED;
+        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
         if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
             return ERROR_MALFORMED;
@@ -4659,6 +4779,7 @@
       mCurrentSampleInfoOffsets(NULL),
       mIsAVC(false),
       mIsHEVC(false),
+      mIsDolbyVision(false),
       mIsAC4(false),
       mIsPcm(false),
       mNALLengthSize(0),
@@ -4698,6 +4819,7 @@
     mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
               !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
     mIsAC4 = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4);
+    mIsDolbyVision = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
 
     if (mIsAVC) {
         void *data;
@@ -4722,6 +4844,42 @@
         CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
 
         mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+    } else if (mIsDolbyVision) {
+        ALOGV("%s DolbyVision stream detected", __FUNCTION__);
+        void *data;
+        size_t size;
+        CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_2, &data, &size));
+
+        const uint8_t *ptr = (const uint8_t *)data;
+
+        CHECK(size == 24);
+
+        // dv_major.dv_minor Should be 1.0 or 2.1
+        CHECK(!((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1)));
+
+        const uint8_t profile = ptr[2] >> 1;
+        // profile == (unknown,1,9) --> AVC; profile = (2,3,4,5,6,7,8) --> HEVC;
+        // profile == (10) --> AV1
+        if (profile > 1 && profile < 9) {
+            CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_HEVC, &data, &size));
+
+            const uint8_t *ptr = (const uint8_t *)data;
+
+            CHECK(size >= 22);
+            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
+
+            mNALLengthSize = 1 + (ptr[14 + 7] & 3);
+        } else if (10 == profile) {
+            /* AV1 profile nothing to do */
+        } else {
+            CHECK(AMediaFormat_getBuffer(format, AMEDIAFORMAT_KEY_CSD_AVC, &data, &size));
+            const uint8_t *ptr = (const uint8_t *)data;
+
+            CHECK(size >= 7);
+            CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
+            // The number of bytes used to encode the length of a NAL unit.
+            mNALLengthSize = 1 + (ptr[4] & 3);
+        }
     }
 
     mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW);
@@ -4993,8 +5151,11 @@
 }
 
 status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(
-        off64_t offset, off64_t /* size */) {
+        off64_t offset, off64_t size) {
     ALOGV("parseSampleAuxiliaryInformationSizes");
+    if (size < 9) {
+        return -EINVAL;
+    }
     // 14496-12 8.7.12
     uint8_t version;
     if (mDataSource->readAt(
@@ -5007,25 +5168,32 @@
         return ERROR_UNSUPPORTED;
     }
     offset++;
+    size--;
 
     uint32_t flags;
     if (!mDataSource->getUInt24(offset, &flags)) {
         return ERROR_IO;
     }
     offset += 3;
+    size -= 3;
 
     if (flags & 1) {
+        if (size < 13) {
+            return -EINVAL;
+        }
         uint32_t tmp;
         if (!mDataSource->getUInt32(offset, &tmp)) {
             return ERROR_MALFORMED;
         }
         mCurrentAuxInfoType = tmp;
         offset += 4;
+        size -= 4;
         if (!mDataSource->getUInt32(offset, &tmp)) {
             return ERROR_MALFORMED;
         }
         mCurrentAuxInfoTypeParameter = tmp;
         offset += 4;
+        size -= 4;
     }
 
     uint8_t defsize;
@@ -5034,6 +5202,7 @@
     }
     mCurrentDefaultSampleInfoSize = defsize;
     offset++;
+    size--;
 
     uint32_t smplcnt;
     if (!mDataSource->getUInt32(offset, &smplcnt)) {
@@ -5041,11 +5210,16 @@
     }
     mCurrentSampleInfoCount = smplcnt;
     offset += 4;
-
+    size -= 4;
     if (mCurrentDefaultSampleInfoSize != 0) {
         ALOGV("@@@@ using default sample info size of %d", mCurrentDefaultSampleInfoSize);
         return OK;
     }
+    if(smplcnt > size) {
+        ALOGW("b/124525515 - smplcnt(%u) > size(%ld)", (unsigned int)smplcnt, (unsigned long)size);
+        android_errorWriteLog(0x534e4554, "124525515");
+        return -EINVAL;
+    }
     if (smplcnt > mCurrentSampleInfoAllocSize) {
         uint8_t * newPtr =  (uint8_t*) realloc(mCurrentSampleInfoSizes, smplcnt);
         if (newPtr == NULL) {
@@ -5061,26 +5235,32 @@
 }
 
 status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
-        off64_t offset, off64_t /* size */) {
+        off64_t offset, off64_t size) {
     ALOGV("parseSampleAuxiliaryInformationOffsets");
+    if (size < 8) {
+        return -EINVAL;
+    }
     // 14496-12 8.7.13
     uint8_t version;
     if (mDataSource->readAt(offset, &version, sizeof(version)) != 1) {
         return ERROR_IO;
     }
     offset++;
+    size--;
 
     uint32_t flags;
     if (!mDataSource->getUInt24(offset, &flags)) {
         return ERROR_IO;
     }
     offset += 3;
+    size -= 3;
 
     uint32_t entrycount;
     if (!mDataSource->getUInt32(offset, &entrycount)) {
         return ERROR_IO;
     }
     offset += 4;
+    size -= 4;
     if (entrycount == 0) {
         return OK;
     }
@@ -5106,19 +5286,31 @@
 
     for (size_t i = 0; i < entrycount; i++) {
         if (version == 0) {
+            if (size < 4) {
+                ALOGW("b/124526959");
+                android_errorWriteLog(0x534e4554, "124526959");
+                return -EINVAL;
+            }
             uint32_t tmp;
             if (!mDataSource->getUInt32(offset, &tmp)) {
                 return ERROR_IO;
             }
             mCurrentSampleInfoOffsets[i] = tmp;
             offset += 4;
+            size -= 4;
         } else {
+            if (size < 8) {
+                ALOGW("b/124526959");
+                android_errorWriteLog(0x534e4554, "124526959");
+                return -EINVAL;
+            }
             uint64_t tmp;
             if (!mDataSource->getUInt64(offset, &tmp)) {
                 return ERROR_IO;
             }
             mCurrentSampleInfoOffsets[i] = tmp;
             offset += 8;
+            size -= 8;
         }
     }
 
@@ -5405,20 +5597,30 @@
 
     if (flags & kSampleSizePresent) {
         bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) {
-        sampleSize = mTrackFragmentHeaderInfo.mDefaultSampleSize;
     } else {
         sampleSize = mTrackFragmentHeaderInfo.mDefaultSampleSize;
+#ifdef VERY_VERY_VERBOSE_LOGGING
+        // We don't expect this, but also want to avoid spamming the log if
+        // we hit this case.
+        if (!(mTrackFragmentHeaderInfo.mFlags
+              & TrackFragmentHeaderInfo::kDefaultSampleSizePresent)) {
+            ALOGW("No sample size specified");
+        }
+#endif
     }
 
     if (flags & kSampleFlagsPresent) {
         bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) {
-        sampleFlags = mTrackFragmentHeaderInfo.mDefaultSampleFlags;
     } else {
         sampleFlags = mTrackFragmentHeaderInfo.mDefaultSampleFlags;
+#ifdef VERY_VERY_VERBOSE_LOGGING
+        // We don't expect this, but also want to avoid spamming the log if
+        // we hit this case.
+        if (!(mTrackFragmentHeaderInfo.mFlags
+              & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent)) {
+            ALOGW("No sample flags specified");
+        }
+#endif
     }
 
     if (flags & kSampleCompositionTimeOffsetPresent) {
@@ -5440,16 +5642,12 @@
 
         // apply some sanity (vs strict legality) checks
         //
-        // clamp the count of entries in the trun box, to avoid spending forever parsing
-        // this box. Clamping (vs error) lets us play *something*.
-        // 1 million is about 400 msecs on a Pixel3, should be no more than a couple seconds
-        // on the slowest devices.
-        static constexpr uint32_t kMaxTrunSampleCount = 1000000;
+        static constexpr uint32_t kMaxTrunSampleCount = 10000;
         if (sampleCount > kMaxTrunSampleCount) {
-            ALOGW("b/123389881 clamp sampleCount(%u) @ kMaxTrunSampleCount(%u)",
+            ALOGW("b/123389881 sampleCount(%u) > kMaxTrunSampleCount(%u)",
                   sampleCount, kMaxTrunSampleCount);
             android_errorWriteLog(0x534e4554, "124389881 count");
-
+            return -EINVAL;
         }
     }
 
@@ -5493,7 +5691,12 @@
         tmp.duration = sampleDuration;
         tmp.compositionOffset = sampleCtsOffset;
         memset(tmp.iv, 0, sizeof(tmp.iv));
-        mCurrentSamples.add(tmp);
+        if (mCurrentSamples.add(tmp) < 0) {
+            ALOGW("b/123389881 failed saving sample(n=%zu)", mCurrentSamples.size());
+            android_errorWriteLog(0x534e4554, "124389881 allocation");
+            mCurrentSamples.clear();
+            return NO_MEMORY;
+        }
 
         dataOffset += sampleSize;
     }
@@ -5744,7 +5947,7 @@
         }
     }
 
-    if (!mIsAVC && !mIsHEVC && !mIsAC4) {
+    if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize) && !mIsAC4) {
         if (newBuffer) {
             if (mIsPcm) {
                 // The twos' PCM block reader assumes that all samples has the same size.
@@ -6134,7 +6337,7 @@
         AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_IV, iv, ivlength);
     }
 
-    if (!mIsAVC && !mIsHEVC) {
+    if (!mIsAVC && !mIsHEVC && !(mIsDolbyVision && mNALLengthSize)) {
         if (newBuffer) {
             if (!isInRange((size_t)0u, mBuffer->size(), size)) {
                 mBuffer->release();
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 9dddf2c..59c8200 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -391,20 +391,11 @@
     }
 
     mTimeToSampleCount = U32_AT(&header[4]);
-    if (mTimeToSampleCount > UINT32_MAX / (2 * sizeof(uint32_t))) {
-        // Choose this bound because
-        // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one
-        //    time-to-sample entry in the time-to-sample table.
-        // 2) mTimeToSampleCount is the number of entries of the time-to-sample
-        //    table.
-        // 3) We hope that the table size does not exceed UINT32_MAX.
+    if (mTimeToSampleCount > (data_size - 8) / (2 * sizeof(uint32_t))) {
         ALOGE("Time-to-sample table size too large.");
         return ERROR_OUT_OF_RANGE;
     }
 
-    // Note: At this point, we know that mTimeToSampleCount * 2 will not
-    // overflow because of the above condition.
-
     uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t);
     mTotalSize += allocSize;
     if (mTotalSize > kMaxTotalSize) {
@@ -540,6 +531,12 @@
     }
 
     uint64_t allocSize = (uint64_t)numSyncSamples * sizeof(uint32_t);
+    if (allocSize > data_size - 8) {
+        ALOGW("b/124771364 - allocSize(%lu) > size(%lu)",
+                (unsigned long)allocSize, (unsigned long)(data_size - 8));
+        android_errorWriteLog(0x534e4554, "124771364");
+        return ERROR_MALFORMED;
+    }
     if (allocSize > kMaxTotalSize) {
         ALOGE("Sync sample table size too large.");
         return ERROR_OUT_OF_RANGE;
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 1d9e1e6..8638cdc 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -12,15 +12,10 @@
     ],
 
     shared_libs: [
-        "android.hardware.cas@1.0",
-        "android.hardware.cas.native@1.0",
-        "android.hidl.token@1.0-utils",
-        "android.hidl.allocator@1.0",
-        "libcrypto",
-        "libhidlmemory",
-        "libhidlbase",
-        "liblog",
-        "libmediandk",
+        "libcgrouprc#29",
+        "liblog#10000",
+        "libmediandk#29",
+        "libvndksupport#29",
     ],
 
     header_libs: [
@@ -31,11 +26,24 @@
     ],
 
     static_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "android.hidl.token@1.0",
+        "android.hidl.token@1.0-utils",
+        "libbase",
+        "libbinderthreadstate",
+        "libcutils",
+        "libhidlbase",
+        "libhidlmemory",
+        "libjsoncpp",
+        "libprocessgroup",
+        "libstagefright_esds",
         "libstagefright_foundation_without_imemory",
+        "libstagefright_mpeg2extractor",
         "libstagefright_mpeg2support",
         "libutils",
-        "libstagefright_mpeg2extractor",
-        "libstagefright_esds",
     ],
 
     name: "libmpeg2extractor",
@@ -51,11 +59,16 @@
     version_script: "exports.lds",
 
     sanitize: {
-        cfi: true,
+        // STOPSHIP: turn on cfi once b/139945549 is resolved.
+        cfi: false,
         misc_undefined: [
             "unsigned-integer-overflow",
             "signed-integer-overflow",
         ],
     },
 
+    apex_available: [
+        "com.android.media",
+        "test_com.android.media",
+    ],
 }
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 72b94bb..4012ece 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -1062,8 +1062,15 @@
     size_t size = buffer->range_length();
 
     if (size < kOpusHeaderSize
-            || memcmp(data, "OpusHead", 8)
-            || /* version = */ data[8] != 1) {
+            || memcmp(data, "OpusHead", 8)) {
+        return AMEDIA_ERROR_MALFORMED;
+    }
+    // allow both version 0 and 1. Per the opus specification:
+    // An earlier draft of the specification described a version 0, but the only difference
+    // between version 1 and version 0 is that version 0 did not specify the semantics for
+    // handling the version field
+    if ( /* version = */ data[8] > 1) {
+        ALOGW("no support for opus version %d", data[8]);
         return AMEDIA_ERROR_MALFORMED;
     }
 
@@ -1384,7 +1391,7 @@
         return NULL;
     }
 
-    *confidence = 0.2f;
+    *confidence = 0.5f;
 
     return CreateExtractor;
 }
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 8173e3c..a4322a1 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -724,7 +724,7 @@
  * Available since API level 29.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param inputPreset the desired level of opt-out from being captured.
+ * @param capturePolicy the desired level of opt-out from being captured.
  */
 AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(AAudioStreamBuilder* builder,
         aaudio_allowed_capture_policy_t capturePolicy) __INTRODUCED_IN(29);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index fb276c2..7481daa 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -36,7 +36,6 @@
 #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"
@@ -233,6 +232,26 @@
         mCallbackBuffer = new uint8_t[callbackBufferSize];
     }
 
+    // For debugging and analyzing the distribution of MMAP timestamps.
+    // For OUTPUT, use a NEGATIVE offset to move the CPU writes further BEFORE the HW reads.
+    // For INPUT, use a POSITIVE offset to move the CPU reads further AFTER the HW writes.
+    // 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?
+        int32_t offsetMicros = (getDirection() == AAUDIO_DIRECTION_OUTPUT)
+                ? AAudioProperty_getOutputMMapOffsetMicros()
+                : AAudioProperty_getInputMMapOffsetMicros();
+        // This log is used to debug some tricky glitch issues. Please leave.
+        ALOGD_IF(offsetMicros, "%s() - %s mmap offset = %d micros",
+                __func__,
+                (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "output" : "input",
+                offsetMicros);
+        mTimeOffsetNanos = offsetMicros * AAUDIO_NANOS_PER_MICROSECOND;
+    }
+
+    setBufferSize(capacity / 2); // Default buffer size to match Q
+
     setState(AAUDIO_STREAM_STATE_OPEN);
 
     return result;
@@ -479,7 +498,8 @@
 #if LOG_TIMESTAMPS
     logTimestamp(*message);
 #endif
-    processTimestamp(message->timestamp.position, message->timestamp.timestamp);
+    processTimestamp(message->timestamp.position,
+            message->timestamp.timestamp + mTimeOffsetNanos);
     return AAUDIO_OK;
 }
 
@@ -635,7 +655,7 @@
         // Should we block?
         if (timeoutNanoseconds == 0) {
             break; // don't block
-        } else if (framesLeft > 0) {
+        } else if (wakeTimeNanos != 0) {
             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.
@@ -694,37 +714,39 @@
 
 aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
     int32_t adjustedFrames = requestedFrames;
-    int32_t actualFrames = 0;
-    int32_t maximumSize = getBufferCapacity();
+    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;
 
     // Clip to minimum size so that rounding up will work better.
-    if (adjustedFrames < 1) {
-        adjustedFrames = 1;
-    }
+    adjustedFrames = std::max(minimumSize, adjustedFrames);
 
-    if (adjustedFrames > maximumSize) {
-        // Clip to maximum size.
+    // Prevent arithmetic overflow by clipping before we round.
+    if (adjustedFrames >= maximumSize) {
         adjustedFrames = maximumSize;
     } else {
         // Round to the next highest burst size.
         int32_t numBursts = (adjustedFrames + mFramesPerBurst - 1) / mFramesPerBurst;
         adjustedFrames = numBursts * mFramesPerBurst;
-        // Rounding may have gone above maximum.
-        if (adjustedFrames > maximumSize) {
-            adjustedFrames = maximumSize;
-        }
     }
 
-    aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(adjustedFrames, &actualFrames);
-    if (result < 0) {
-        return result;
-    } else {
-        return (aaudio_result_t) actualFrames;
-    }
+    // 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);
+
+    mBufferSizeInFrames = adjustedFrames;
+    ALOGV("%s(%d) returns %d", __func__, requestedFrames, adjustedFrames);
+    return (aaudio_result_t) adjustedFrames;
 }
 
 int32_t AudioStreamInternal::getBufferSize() const {
-    return mAudioEndpoint.getBufferSizeInFrames();
+    return mBufferSizeInFrames;
 }
 
 int32_t AudioStreamInternal::getBufferCapacity() const {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 86c4698..596d37f 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -194,6 +194,7 @@
     // By delaying slightly we can avoid waking up before other side is ready.
     const int32_t            mWakeupDelayNanos; // delay past typical wakeup jitter
     const int32_t            mMinimumSleepNanos; // minimum sleep while polling
+    int32_t                  mTimeOffsetNanos = 0; // add to time part of an MMAP timestamp
 
     AudioEndpointParcelable  mEndPointParcelable; // description of the buffers filled by service
     EndpointDescriptor       mEndpointDescriptor; // buffer description with resolved addresses
@@ -203,6 +204,9 @@
     // Sometimes the hardware is operating with a different channel count from the app.
     // Then we require conversion in AAudio.
     int32_t                  mDeviceChannelCount = 0;
+
+    int32_t                  mBufferSizeInFrames = 0; // local threshold to control latency
+
 };
 
 } /* namespace aaudio */
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 366cc87..9684ee4 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -106,9 +106,10 @@
         mNeedCatchUp.acknowledge();
     }
 
-    // If the write index passed the read index then consider it an overrun.
+    // 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.getEmptyFramesAvailable() < 0) {
+    if (mAudioEndpoint.isFreeRunning()
+        && mAudioEndpoint.getFullFramesAvailable() > mAudioEndpoint.getBufferCapacityInFrames()) {
         mXRunCount++;
         if (ATRACE_ENABLED()) {
             ATRACE_INT("aaOverRuns", mXRunCount);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index b8ef247..dc9f48c 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -167,8 +167,10 @@
         ATRACE_INT("aaWrote", framesWritten);
     }
 
+    // Sleep if there is too much data in the buffer.
     // Calculate an ideal time to wake up.
-    if (wakeTimePtr != nullptr && framesWritten >= 0) {
+    if (wakeTimePtr != nullptr
+            && (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();
@@ -184,14 +186,10 @@
                 break;
             case AAUDIO_STREAM_STATE_STARTED:
             {
-                // When do we expect the next read burst to occur?
-
-                // Calculate frame position based off of the writeCounter because
-                // the readCounter might have just advanced in the background,
-                // causing us to sleep until a later burst.
-                int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
-                        - mAudioEndpoint.getBufferSizeInFrames();
-                wakeTime = mClockModel.convertPositionToTime(nextPosition);
+                // 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();
+                wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
             }
                 break;
             default:
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 9abdf53..bd46d05 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -18,22 +18,43 @@
 //#define LOG_NDEBUG 0
 #include <log/log.h>
 
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
 #include <stdint.h>
 #include <algorithm>
 
 #include "utility/AudioClock.h"
+#include "utility/AAudioUtilities.h"
 #include "IsochronousClockModel.h"
 
 using namespace aaudio;
 
+using namespace android::audio_utils;
+
+#ifndef ICM_LOG_DRIFT
+#define ICM_LOG_DRIFT   0
+#endif // ICM_LOG_DRIFT
+
+// To enable the timestamp histogram, enter this before opening the stream:
+//    adb root
+//    adb shell setprop aaudio.log_mask 1
+// A histogram of the lateness of the timestamps will be cleared when the stream is started.
+// It will be updated when the model is stable and receives a timestamp,
+// and dumped to the log when the stream is stopped.
+
 IsochronousClockModel::IsochronousClockModel()
         : mMarkerFramePosition(0)
         , mMarkerNanoTime(0)
         , mSampleRate(48000)
-        , mFramesPerBurst(64)
+        , mFramesPerBurst(48)
         , mMaxMeasuredLatenessNanos(0)
+        , mLatenessForDriftNanos(kInitialLatenessForDriftNanos)
         , mState(STATE_STOPPED)
 {
+    if ((AAudioProperty_getLogMask() & AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM) != 0) {
+        mHistogramMicros = std::make_unique<Histogram>(kHistogramBinCount,
+                kHistogramBinWidthMicros);
+    }
 }
 
 IsochronousClockModel::~IsochronousClockModel() {
@@ -49,6 +70,9 @@
     ALOGV("start(nanos = %lld)\n", (long long) nanoTime);
     mMarkerNanoTime = nanoTime;
     mState = STATE_STARTING;
+    if (mHistogramMicros) {
+        mHistogramMicros->clear();
+    }
 }
 
 void IsochronousClockModel::stop(int64_t nanoTime) {
@@ -58,6 +82,9 @@
     setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
     // TODO should we set position?
     mState = STATE_STOPPED;
+    if (mHistogramMicros) {
+        dumpHistogram();
+    }
 }
 
 bool IsochronousClockModel::isStarting() const {
@@ -90,6 +117,7 @@
 
 //    ALOGD("processTimestamp() - mSampleRate = %d", mSampleRate);
 //    ALOGD("processTimestamp() - mState = %d", mState);
+    int64_t latenessNanos = nanosDelta - expectedNanosDelta;
     switch (mState) {
     case STATE_STOPPED:
         break;
@@ -99,7 +127,7 @@
         break;
     case STATE_SYNCING:
         // This will handle a burst of rapid transfer at the beginning.
-        if (nanosDelta < expectedNanosDelta) {
+        if (latenessNanos < 0) {
             setPositionAndTime(framePosition, nanoTime);
         } else {
 //            ALOGD("processTimestamp() - advance to STATE_RUNNING");
@@ -107,65 +135,67 @@
         }
         break;
     case STATE_RUNNING:
-        if (nanosDelta < expectedNanosDelta) {
+        if (mHistogramMicros) {
+            mHistogramMicros->add(latenessNanos / AAUDIO_NANOS_PER_MICROSECOND);
+        }
+        // Modify estimated position based on lateness.
+        // This affects the "early" side of the window, which controls output glitches.
+        if (latenessNanos < 0) {
             // Earlier than expected timestamp.
             // This data is probably more accurate, so use it.
             // Or we may be drifting due to a fast HW clock.
-            //int microsDelta = (int) (nanosDelta / 1000);
-            //int expectedMicrosDelta = (int) (expectedNanosDelta / 1000);
-            //ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
-                //__func__, mTimestampCount, expectedMicrosDelta - microsDelta);
-
             setPositionAndTime(framePosition, nanoTime);
-        } else if (nanosDelta > (expectedNanosDelta + (2 * mBurstPeriodNanos))) {
-            // In this case we do not update mMaxMeasuredLatenessNanos because it
-            // would force it too high.
-            // mMaxMeasuredLatenessNanos should range from 1 to 2 * mBurstPeriodNanos
-            //int32_t measuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
-            //ALOGD("%s() - STATE_RUNNING - #%d, lateness %d - max %d = %4d micros VERY LATE",
-                  //__func__,
-                  //mTimestampCount,
-                  //measuredLatenessNanos / 1000,
-                  //mMaxMeasuredLatenessNanos / 1000,
-                  //(measuredLatenessNanos - mMaxMeasuredLatenessNanos) / 1000
-                  //);
-
-            // This typically happens when we are modelling a service instead of a DSP.
-            setPositionAndTime(framePosition,  nanoTime - (2 * mBurstPeriodNanos));
-        } else if (nanosDelta > (expectedNanosDelta + mMaxMeasuredLatenessNanos)) {
-            //int32_t previousLatenessNanos = mMaxMeasuredLatenessNanos;
-            mMaxMeasuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
-
-            //ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
-                  //__func__,
-                  //mTimestampCount,
-                  //mMaxMeasuredLatenessNanos / 1000,
-                  //previousLatenessNanos / 1000,
-                  //(mMaxMeasuredLatenessNanos - previousLatenessNanos) / 1000
-                  //);
-
-            // When we are late, it may be because of preemption in the kernel,
+#if ICM_LOG_DRIFT
+            int earlyDeltaMicros = (int) ((expectedNanosDelta - nanosDelta)/ 1000);
+            ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
+                __func__, mTimestampCount, earlyDeltaMicros);
+#endif
+        } else if (latenessNanos > mLatenessForDriftNanos) {
+            // When we are on the late side, it may be because of preemption in the kernel,
             // or timing jitter caused by resampling in the DSP,
             // or we may be drifting due to a slow HW clock.
             // We add slight drift value just in case there is actual long term drift
             // forward caused by a slower clock.
             // If the clock is faster than the model will get pushed earlier
-            // by the code in the preceding branch.
+            // by the code in the earlier branch.
             // The two opposing forces should allow the model to track the real clock
             // over a long time.
             int64_t driftingTime = mMarkerNanoTime + expectedNanosDelta + kDriftNanos;
             setPositionAndTime(framePosition,  driftingTime);
-            //ALOGD("%s() - #%d, max lateness = %d micros",
-                  //__func__,
-                  //mTimestampCount,
-                  //(int) (mMaxMeasuredLatenessNanos / 1000));
+#if ICM_LOG_DRIFT
+            ALOGD("%s() - STATE_RUNNING - #%d, DRIFT, lateness = %d micros",
+                  __func__,
+                  mTimestampCount,
+                  (int) (latenessNanos / 1000));
+#endif
+        }
+
+        // Modify mMaxMeasuredLatenessNanos.
+        // This affects the "late" side of the window, which controls input glitches.
+        if (latenessNanos > mMaxMeasuredLatenessNanos) { // increase
+#if ICM_LOG_DRIFT
+            ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
+                    __func__,
+                    mTimestampCount,
+                    (int) (latenessNanos / 1000),
+                    mMaxMeasuredLatenessNanos / 1000,
+                    (int) ((latenessNanos - mMaxMeasuredLatenessNanos) / 1000)
+                    );
+#endif
+            mMaxMeasuredLatenessNanos = (int32_t) latenessNanos;
+            // 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
+            // and stay there. So we slowly reduce mMaxMeasuredLatenessNanos for better
+            // long term stability. The two opposing forces will keep mMaxMeasuredLatenessNanos
+            // within a reasonable range.
+            mMaxMeasuredLatenessNanos -= kDriftNanos;
         }
         break;
     default:
         break;
     }
-
-//    ALOGD("processTimestamp() - mState = %d", mState);
 }
 
 void IsochronousClockModel::setSampleRate(int32_t sampleRate) {
@@ -181,9 +211,6 @@
 // Update expected lateness based on sampleRate and framesPerBurst
 void IsochronousClockModel::update() {
     mBurstPeriodNanos = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
-    // Timestamps may be late by up to a burst because we are randomly sampling the time period
-    // after the DSP position is actually updated.
-    mMaxMeasuredLatenessNanos = mBurstPeriodNanos;
 }
 
 int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const {
@@ -227,9 +254,7 @@
 }
 
 int32_t IsochronousClockModel::getLateTimeOffsetNanos() const {
-    // This will never be < 0 because mMaxLatenessNanos starts at
-    // mBurstPeriodNanos and only gets bigger.
-    return (mMaxMeasuredLatenessNanos - mBurstPeriodNanos) + kExtraLatenessNanos;
+    return mMaxMeasuredLatenessNanos + kExtraLatenessNanos;
 }
 
 int64_t IsochronousClockModel::convertPositionToLatestTime(int64_t framePosition) const {
@@ -241,10 +266,19 @@
 }
 
 void IsochronousClockModel::dump() const {
-    ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
-    ALOGD("mMarkerNanoTime      = %lld", (long long) mMarkerNanoTime);
+    ALOGD("mMarkerFramePosition = %" PRIu64, mMarkerFramePosition);
+    ALOGD("mMarkerNanoTime      = %" PRIu64, mMarkerNanoTime);
     ALOGD("mSampleRate          = %6d", mSampleRate);
     ALOGD("mFramesPerBurst      = %6d", mFramesPerBurst);
     ALOGD("mMaxMeasuredLatenessNanos = %6d", mMaxMeasuredLatenessNanos);
     ALOGD("mState               = %6d", mState);
 }
+
+void IsochronousClockModel::dumpHistogram() const {
+    if (!mHistogramMicros) return;
+    std::istringstream istr(mHistogramMicros->dump());
+    std::string line;
+    while (std::getline(istr, line)) {
+        ALOGD("lateness, %s", line.c_str());
+    }
+}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 582bf4e..40f066b 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -18,6 +18,9 @@
 #define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
 
 #include <stdint.h>
+
+#include <audio_utils/Histogram.h>
+
 #include "utility/AudioClock.h"
 
 namespace aaudio {
@@ -122,6 +125,8 @@
 
     void dump() const;
 
+    void dumpHistogram() const;
+
 private:
 
     int32_t getLateTimeOffsetNanos() const;
@@ -134,21 +139,30 @@
     };
 
     // Amount of time to drift forward when we get a late timestamp.
-    // This value was calculated to allow tracking of a clock with 50 ppm error.
-    static constexpr int32_t   kDriftNanos         =  10 * 1000;
-    // TODO review value of kExtraLatenessNanos
+    static constexpr int32_t   kDriftNanos         =   1 * 1000;
+    // Safety margin to add to the late edge of the timestamp window.
     static constexpr int32_t   kExtraLatenessNanos = 100 * 1000;
+    // Initial small threshold for causing a drift later in time.
+    static constexpr int32_t   kInitialLatenessForDriftNanos = 10 * 1000;
 
-    int64_t             mMarkerFramePosition;
-    int64_t             mMarkerNanoTime;
+    static constexpr int32_t   kHistogramBinWidthMicros = 50;
+    static constexpr int32_t   kHistogramBinCount = 128;
+
+    int64_t             mMarkerFramePosition; // Estimated HW position.
+    int64_t             mMarkerNanoTime;      // Estimated HW time.
     int32_t             mSampleRate;
-    int32_t             mFramesPerBurst;
-    int32_t             mBurstPeriodNanos;
+    int32_t             mFramesPerBurst;      // number of frames transferred at one time.
+    int32_t             mBurstPeriodNanos;    // Time between HW bursts.
     // Includes mBurstPeriodNanos because we sample randomly over time.
     int32_t             mMaxMeasuredLatenessNanos;
-    clock_model_state_t mState;
+    // Threshold for lateness that triggers a drift later in time.
+    int32_t             mLatenessForDriftNanos;
+    clock_model_state_t mState;               // State machine handles startup sequence.
 
-    int32_t             mTimestampCount = 0;
+    int32_t             mTimestampCount = 0;  // For logging.
+
+    // distribution of timestamps relative to earliest
+    std::unique_ptr<android::audio_utils::Histogram>   mHistogramMicros;
 
     void update();
 };
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index cdd02c0..c2f7fd0 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -335,6 +335,34 @@
     return prop;
 }
 
+static int32_t AAudioProperty_getMMapOffsetMicros(const char *functionName,
+        const char *propertyName) {
+    const int32_t minMicros = -20000; // arbitrary
+    const int32_t defaultMicros = 0;  // arbitrary
+    const int32_t maxMicros =  20000; // arbitrary
+    int32_t prop = property_get_int32(propertyName, defaultMicros);
+    if (prop < minMicros) {
+        ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+        prop = minMicros;
+    } else if (prop > maxMicros) {
+        ALOGW("%s: clipped %d to %d", functionName, prop, minMicros);
+        prop = maxMicros;
+    }
+    return prop;
+}
+
+int32_t AAudioProperty_getInputMMapOffsetMicros() {
+    return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC);
+}
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros() {
+    return AAudioProperty_getMMapOffsetMicros(__func__, AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC);
+}
+
+int32_t AAudioProperty_getLogMask() {
+    return property_get_int32(AAUDIO_PROP_LOG_MASK, 0);
+}
+
 aaudio_result_t AAudio_isFlushAllowed(aaudio_stream_state_t state) {
     aaudio_result_t result = AAUDIO_OK;
     switch (state) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 76d0457..5dcddf3 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -94,31 +94,26 @@
 
 // Note that this code may be replaced by Settings or by some other system configuration tool.
 
+/**
+ * Read system property.
+ * @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
+ */
+int32_t AAudioProperty_getMMapPolicy();
 #define AAUDIO_PROP_MMAP_POLICY           "aaudio.mmap_policy"
 
 /**
  * Read system property.
  * @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
  */
-int32_t AAudioProperty_getMMapPolicy();
-
-#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
-
-/**
- * Read system property.
- * @return AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER or AAUDIO_POLICY_AUTO or AAUDIO_POLICY_ALWAYS
- */
 int32_t AAudioProperty_getMMapExclusivePolicy();
-
-#define AAUDIO_PROP_MIXER_BURSTS           "aaudio.mixer_bursts"
+#define AAUDIO_PROP_MMAP_EXCLUSIVE_POLICY "aaudio.mmap_exclusive_policy"
 
 /**
  * Read system property.
  * @return number of bursts per AAudio service mixer cycle
  */
 int32_t AAudioProperty_getMixerBursts();
-
-#define AAUDIO_PROP_HW_BURST_MIN_USEC      "aaudio.hw_burst_min_usec"
+#define AAUDIO_PROP_MIXER_BURSTS           "aaudio.mixer_bursts"
 
 /**
  * Read a system property that specifies the number of extra microseconds that a thread
@@ -130,7 +125,6 @@
  * @return number of microseconds to delay the wakeup.
  */
 int32_t AAudioProperty_getWakeupDelayMicros();
-
 #define AAUDIO_PROP_WAKEUP_DELAY_USEC      "aaudio.wakeup_delay_usec"
 
 /**
@@ -139,7 +133,6 @@
  * @return minimum number of microseconds to sleep.
  */
 int32_t AAudioProperty_getMinimumSleepMicros();
-
 #define AAUDIO_PROP_MINIMUM_SLEEP_USEC      "aaudio.minimum_sleep_usec"
 
 /**
@@ -153,7 +146,35 @@
  * @return minimum number of microseconds for a MMAP HW burst
  */
 int32_t AAudioProperty_getHardwareBurstMinMicros();
+#define AAUDIO_PROP_HW_BURST_MIN_USEC      "aaudio.hw_burst_min_usec"
 
+/**
+ * Read a system property that specifies an offset that will be added to MMAP timestamps.
+ * This can be used to correct bias in the timestamp.
+ * It can also be used to analyze the time distribution of the timestamp
+ * by progressively modifying the offset and listening for glitches.
+ *
+ * @return number of microseconds to offset the time part of an MMAP timestamp
+ */
+int32_t AAudioProperty_getInputMMapOffsetMicros();
+#define AAUDIO_PROP_INPUT_MMAP_OFFSET_USEC    "aaudio.in_mmap_offset_usec"
+
+int32_t AAudioProperty_getOutputMMapOffsetMicros();
+#define AAUDIO_PROP_OUTPUT_MMAP_OFFSET_USEC   "aaudio.out_mmap_offset_usec"
+
+// These are powers of two that can be combined as a bit mask.
+// AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM must be enabled before the stream is opened.
+#define AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM   1
+#define AAUDIO_LOG_RESERVED_2              2
+#define AAUDIO_LOG_RESERVED_4              4
+#define AAUDIO_LOG_RESERVED_8              8
+
+/**
+ * Use a mask to enable various logs in AAudio.
+ * @return mask that enables various AAudio logs, such as AAUDIO_LOG_CLOCK_MODEL_HISTOGRAM
+ */
+int32_t AAudioProperty_getLogMask();
+#define AAUDIO_PROP_LOG_MASK   "aaudio.log_mask"
 
 /**
  * Is flush allowed for the given state?
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 19cd0a0..73fd896 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -215,3 +215,14 @@
     srcs: ["test_full_queue.cpp"],
     shared_libs: ["libaaudio"],
 }
+
+cc_test {
+    name: "test_histogram",
+    defaults: ["libaaudio_tests_defaults"],
+    srcs: ["test_histogram.cpp"],
+    shared_libs: [
+        "libaudioutils",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/media/libaaudio/tests/test_histogram.cpp b/media/libaaudio/tests/test_histogram.cpp
new file mode 100644
index 0000000..431373d
--- /dev/null
+++ b/media/libaaudio/tests/test_histogram.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Test Histogram
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include <audio_utils/Histogram.h>
+
+using namespace android::audio_utils;
+
+static constexpr int32_t kBinWidth = 10;
+static constexpr int32_t kNumBins = 20;
+
+TEST(test_histogram, module_sinki16) {
+    Histogram histogram(kNumBins, kBinWidth);
+    ASSERT_EQ(kNumBins, histogram.getNumBinsInRange());
+
+    // Is it clear initially?
+    for (int i = 0; i < kNumBins; i++) {
+        ASSERT_EQ(0, histogram.getCount(i));
+    }
+    ASSERT_EQ(0, histogram.getCountBelowRange());
+    ASSERT_EQ(0, histogram.getCountAboveRange());
+    ASSERT_EQ(0, histogram.getCount());
+
+    // Add some items.
+    histogram.add(27);
+    histogram.add(53);
+    histogram.add(171);
+    histogram.add(23);
+
+    // Did they count correctly.
+    ASSERT_EQ(2, histogram.getCount(2));          // For items 27 and 23
+    ASSERT_EQ(3, histogram.getLastItemNumber(2)); // Item 23 was the 0,1,2,3th item added.
+    ASSERT_EQ(1, histogram.getCount(5));          // For item 53
+    ASSERT_EQ(1, histogram.getLastItemNumber(5)); // item 53 was the second item added.
+    ASSERT_EQ(1, histogram.getCount(17));         // For item 171
+    ASSERT_EQ(4, histogram.getCount());           // A total of four items were added.
+
+    // Add values out of range.
+    histogram.add(-5);
+    ASSERT_EQ(1, histogram.getCountBelowRange()); // -5 is below zero.
+    ASSERT_EQ(0, histogram.getCountAboveRange());
+    ASSERT_EQ(5, histogram.getCount());
+
+    histogram.add(200);
+    ASSERT_EQ(1, histogram.getCountBelowRange());
+    ASSERT_EQ(1, histogram.getCountAboveRange()); // 200 is above top bin
+    ASSERT_EQ(6, histogram.getCount());
+
+    // Try to read values out of range. Should not crash.
+    // Legal index range is 0 to numBins-1
+    histogram.add(-1);
+    histogram.add(kNumBins);
+    ASSERT_EQ(0, histogram.getCount(-1)); // edge
+    ASSERT_EQ(0, histogram.getCount(kNumBins)); // edge
+    ASSERT_EQ(0, histogram.getCount(-1234)); // extreme
+    ASSERT_EQ(0, histogram.getCount(98765)); // extreme
+    ASSERT_EQ(0, histogram.getLastItemNumber(-1));
+    ASSERT_EQ(0, histogram.getLastItemNumber(kNumBins));
+
+    // Clear all the counts.
+    histogram.clear();
+    // Is it clear?
+    for (int i = 0; i < kNumBins; i++) {
+        ASSERT_EQ(0, histogram.getCount(i));
+    }
+    ASSERT_EQ(0, histogram.getCountBelowRange());
+    ASSERT_EQ(0, histogram.getCountAboveRange());
+    ASSERT_EQ(0, histogram.getCount());
+}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 32904bb..d1812e6 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -1,7 +1,15 @@
 cc_library_headers {
     name: "libaudioclient_headers",
     vendor_available: true,
-    export_include_dirs: ["include"],
+    header_libs: [
+        "libaudiofoundation_headers",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    export_header_lib_headers: [
+        "libaudiofoundation_headers",
+    ],
 }
 
 cc_library_shared {
@@ -13,6 +21,7 @@
         "AudioVolumeGroup.cpp",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "libaudioutils",
         "libbinder",
         "libcutils",
@@ -63,6 +72,7 @@
         "TrackPlayerBase.cpp",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "libaudioutils",
         "libaudiopolicy",
         "libaudiomanager",
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index cf11936..1cc5fe6 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -159,7 +159,11 @@
 
     mIEffect = iEffect;
     mCblkMemory = cblk;
-    mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer());
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    mCblk = static_cast<effect_param_cblk_t*>(cblk->unsecurePointer());
     int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
     mCblk->buffer = (uint8_t *)mCblk + bufOffset;
 
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 3cdf095..06fc23c 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -22,22 +22,6 @@
 namespace android {
 
 //
-//  AudioDeviceTypeAddr implementation
-//
-status_t AudioDeviceTypeAddr::readFromParcel(Parcel *parcel) {
-    mType = (audio_devices_t) parcel->readInt32();
-    mAddress = parcel->readString8();
-    return NO_ERROR;
-}
-
-status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
-    parcel->writeInt32((int32_t) mType);
-    parcel->writeString8(mAddress);
-    return NO_ERROR;
-}
-
-
-//
 //  AudioMixMatchCriterion implementation
 //
 AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
diff --git a/media/libaudioclient/AudioProductStrategy.cpp b/media/libaudioclient/AudioProductStrategy.cpp
index 0e1dfac..cff72fd 100644
--- a/media/libaudioclient/AudioProductStrategy.cpp
+++ b/media/libaudioclient/AudioProductStrategy.cpp
@@ -70,6 +70,7 @@
     return NO_ERROR;
 }
 
+// Keep in sync with android/media/audiopolicy/AudioProductStrategy#attributeMatches
 bool AudioProductStrategy::attributesMatches(const audio_attributes_t refAttributes,
                                         const audio_attributes_t clientAttritubes)
 {
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index a1b04ca..0f2d48e 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -759,7 +759,11 @@
         status = NO_INIT;
         goto exit;
     }
-    iMemPointer = output.cblk ->pointer();
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    iMemPointer = output.cblk ->unsecurePointer();
     if (iMemPointer == NULL) {
         ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
         status = NO_INIT;
@@ -774,7 +778,11 @@
     if (output.buffers == 0) {
         buffers = cblk + 1;
     } else {
-        buffers = output.buffers->pointer();
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        buffers = output.buffers->unsecurePointer();
         if (buffers == NULL) {
             ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
             status = NO_INIT;
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 02dc516..54184e0 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1392,6 +1392,12 @@
     return af->getMicrophones(microphones);
 }
 
+status_t AudioSystem::setAudioHalPids(const std::vector<pid_t>& pids) {
+  const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+  if (af == nullptr) return PERMISSION_DENIED;
+  return af->setAudioHalPids(pids);
+}
+
 status_t AudioSystem::getSurroundFormats(unsigned int *numSurroundFormats,
                                          audio_format_t *surroundFormats,
                                          bool *surroundFormatsEnabled,
@@ -1519,6 +1525,13 @@
     return aps->setRttEnabled(enabled);
 }
 
+bool AudioSystem::isCallScreenModeSupported()
+{
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) return false;
+    return aps->isCallScreenModeSupported();
+}
+
 // ---------------------------------------------------------------------------
 
 int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 4a80cd3..e8d7b60 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -406,7 +406,7 @@
     mDoNotReconnect = doNotReconnect;
 
     ALOGV_IF(sharedBuffer != 0, "%s(): sharedBuffer: %p, size: %zu",
-            __func__, sharedBuffer->pointer(), sharedBuffer->size());
+            __func__, sharedBuffer->unsecurePointer(), sharedBuffer->size());
 
     ALOGV("%s(): streamType %d frameCount %zu flags %04x",
             __func__, streamType, frameCount, flags);
@@ -1508,7 +1508,11 @@
         status = NO_INIT;
         goto exit;
     }
-    void *iMemPointer = iMem->pointer();
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    void *iMemPointer = iMem->unsecurePointer();
     if (iMemPointer == NULL) {
         ALOGE("%s(%d): Could not get control block pointer", __func__, mPortId);
         status = NO_INIT;
@@ -1563,7 +1567,11 @@
     if (mSharedBuffer == 0) {
         buffers = cblk + 1;
     } else {
-        buffers = mSharedBuffer->pointer();
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        buffers = mSharedBuffer->unsecurePointer();
         if (buffers == NULL) {
             ALOGE("%s(%d): Could not get buffer pointer", __func__, mPortId);
             status = NO_INIT;
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index ee6c335..f1f8f9c 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -984,8 +984,9 @@
 // ---------------------------------------------------------------------------
 
 StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
-        size_t frameCount, size_t frameSize)
-    : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize),
+        size_t frameCount, size_t frameSize, uint32_t sampleRate)
+    : AudioTrackServerProxy(cblk, buffers, frameCount, frameSize, false /*clientInServer*/,
+                            sampleRate),
       mObserver(&cblk->u.mStatic.mSingleStateQueue),
       mPosLoopMutator(&cblk->u.mStatic.mPosLoopQueue),
       mFramesReadySafe(frameCount), mFramesReady(frameCount),
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index e3e64af..04ef3dd 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -90,10 +90,12 @@
     SET_MASTER_BALANCE,
     GET_MASTER_BALANCE,
     SET_EFFECT_SUSPENDED,
+    SET_AUDIO_HAL_PIDS
 };
 
 #define MAX_ITEMS_PER_LIST 1024
 
+
 class BpAudioFlinger : public BpInterface<IAudioFlinger>
 {
 public:
@@ -340,11 +342,11 @@
         return reply.readInt32();
     }
 
-    virtual void setRecordSilenced(uid_t uid, bool silenced)
+    virtual void setRecordSilenced(audio_port_handle_t portId, bool silenced)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
-        data.writeInt32(uid);
+        data.writeInt32(portId);
         data.writeInt32(silenced ? 1 : 0);
         remote()->transact(SET_RECORD_SILENCED, data, &reply);
     }
@@ -392,20 +394,18 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags)
     {
-        if (output == NULL || config == NULL || devices == NULL || latencyMs == NULL) {
+        if (output == nullptr || config == nullptr || device == nullptr || latencyMs == nullptr) {
             return BAD_VALUE;
         }
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(module);
         data.write(config, sizeof(audio_config_t));
-        data.writeInt32(*devices);
-        data.writeString8(address);
+        data.writeParcelable(*device);
         data.writeInt32((int32_t) flags);
         status_t status = remote()->transact(OPEN_OUTPUT, data, &reply);
         if (status != NO_ERROR) {
@@ -420,7 +420,6 @@
         *output = (audio_io_handle_t)reply.readInt32();
         ALOGV("openOutput() returned output, %d", *output);
         reply.read(config, sizeof(audio_config_t));
-        *devices = (audio_devices_t)reply.readInt32();
         *latencyMs = reply.readInt32();
         return NO_ERROR;
     }
@@ -903,6 +902,20 @@
         status = reply.readParcelableVector(microphones);
         return status;
     }
+    virtual status_t setAudioHalPids(const std::vector<pid_t>& pids)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+        data.writeInt32(pids.size());
+        for (auto pid : pids) {
+            data.writeInt32(pid);
+        }
+        status_t status = remote()->transact(SET_AUDIO_HAL_PIDS, data, &reply);
+        if (status != NO_ERROR) {
+            return status;
+        }
+        return static_cast <status_t> (reply.readInt32());
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -958,7 +971,8 @@
         case SET_MODE:
         case SET_MIC_MUTE:
         case SET_LOW_RAM_DEVICE:
-        case SYSTEM_READY: {
+        case SYSTEM_READY:
+        case SET_AUDIO_HAL_PIDS: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -1156,11 +1170,9 @@
         } break;
         case SET_RECORD_SILENCED: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            uid_t uid = data.readInt32();
-            audio_source_t source;
-            data.read(&source, sizeof(audio_source_t));
+            audio_port_handle_t portId = data.readInt32();
             bool silenced = data.readInt32() == 1;
-            setRecordSilenced(uid, silenced);
+            setRecordSilenced(portId, silenced);
             return NO_ERROR;
         } break;
         case SET_PARAMETERS: {
@@ -1200,19 +1212,21 @@
             if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) {
                 ALOGE("b/23905951");
             }
-            audio_devices_t devices = (audio_devices_t)data.readInt32();
-            String8 address(data.readString8());
+            sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+            status_t status = NO_ERROR;
+            if ((status = data.readParcelable(device.get())) != NO_ERROR) {
+                reply->writeInt32((int32_t)status);
+                return NO_ERROR;
+            }
             audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
             uint32_t latencyMs = 0;
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
-            status_t status = openOutput(module, &output, &config,
-                                         &devices, address, &latencyMs, flags);
+            status = openOutput(module, &output, &config, device, &latencyMs, flags);
             ALOGV("OPEN_OUTPUT output, %d", output);
             reply->writeInt32((int32_t)status);
             if (status == NO_ERROR) {
                 reply->writeInt32((int32_t)output);
                 reply->write(&config, sizeof(audio_config_t));
-                reply->writeInt32(devices);
                 reply->writeInt32(latencyMs);
             }
             return NO_ERROR;
@@ -1339,10 +1353,14 @@
         }
         case GET_EFFECT_DESCRIPTOR: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
-            effect_uuid_t uuid;
-            data.read(&uuid, sizeof(effect_uuid_t));
-            effect_uuid_t type;
-            data.read(&type, sizeof(effect_uuid_t));
+            effect_uuid_t uuid = {};
+            if (data.read(&uuid, sizeof(effect_uuid_t)) != NO_ERROR) {
+                android_errorWriteLog(0x534e4554, "139417189");
+            }
+            effect_uuid_t type = {};
+            if (data.read(&type, sizeof(effect_uuid_t)) != NO_ERROR) {
+                android_errorWriteLog(0x534e4554, "139417189");
+            }
             uint32_t preferredTypeFlag = data.readUint32();
             effect_descriptor_t desc = {};
             status_t status = getEffectDescriptor(&uuid, &type, preferredTypeFlag, &desc);
@@ -1543,6 +1561,31 @@
             }
             return NO_ERROR;
         }
+        case SET_AUDIO_HAL_PIDS: {
+            CHECK_INTERFACE(IAudioFlinger, data, reply);
+            std::vector<pid_t> pids;
+            int32_t size;
+            status_t status = data.readInt32(&size);
+            if (status != NO_ERROR) {
+                return status;
+            }
+            if (size < 0) {
+                return BAD_VALUE;
+            }
+            if (size > MAX_ITEMS_PER_LIST) {
+                size = MAX_ITEMS_PER_LIST;
+            }
+            for (int32_t i = 0; i < size; i++) {
+                int32_t pid;
+                status =  data.readInt32(&pid);
+                if (status != NO_ERROR) {
+                    return status;
+                }
+                pids.push_back(pid);
+            }
+            reply->writeInt32(setAudioHalPids(pids));
+            return NO_ERROR;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 7cc95e5..f27e21a 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -104,7 +104,8 @@
     GET_VOLUME_GROUP_FOR_ATTRIBUTES,
     SET_ALLOWED_CAPTURE_POLICY,
     MOVE_EFFECTS_TO_IO,
-    SET_RTT_ENABLED
+    SET_RTT_ENABLED,
+    IS_CALL_SCREEN_MODE_SUPPORTED
 };
 
 #define MAX_ITEMS_PER_LIST 1024
@@ -1284,6 +1285,17 @@
         }
         return static_cast<status_t>(reply.readInt32());
     }
+
+    virtual bool isCallScreenModeSupported()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+        status_t status = remote()->transact(IS_CALL_SCREEN_MODE_SUPPORTED, data, &reply);
+        if (status != NO_ERROR) {
+            return false;
+        }
+        return reply.readBool();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1346,7 +1358,8 @@
         case GET_OFFLOAD_FORMATS_A2DP:
         case LIST_AUDIO_VOLUME_GROUPS:
         case GET_VOLUME_GROUP_FOR_ATTRIBUTES:
-        case SET_RTT_ENABLED: {
+        case SET_RTT_ENABLED:
+        case IS_CALL_SCREEN_MODE_SUPPORTED: {
             if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
                 ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
                       __func__, code, IPCThreadState::self()->getCallingPid(),
@@ -2237,7 +2250,6 @@
             reply->writeBool(isSupported);
             return NO_ERROR;
         }
-
         case SET_UID_DEVICE_AFFINITY: {
             CHECK_INTERFACE(IAudioPolicyService, data, reply);
             const uid_t uid = (uid_t) data.readInt32();
@@ -2369,6 +2381,13 @@
             return NO_ERROR;
         }
 
+        case IS_CALL_SCREEN_MODE_SUPPORTED: {
+            CHECK_INTERFACE(IAudioPolicyService, data, reply);
+            bool isAvailable = isCallScreenModeSupported();
+            reply->writeBool(isAvailable);
+            return NO_ERROR;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libaudioclient/IAudioTrack.cpp b/media/libaudioclient/IAudioTrack.cpp
index 83a568a..6219e7a 100644
--- a/media/libaudioclient/IAudioTrack.cpp
+++ b/media/libaudioclient/IAudioTrack.cpp
@@ -62,7 +62,7 @@
         status_t status = remote()->transact(GET_CBLK, data, &reply);
         if (status == NO_ERROR) {
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
-            if (cblk != 0 && cblk->pointer() == NULL) {
+            if (cblk != 0 && cblk->unsecurePointer() == NULL) {
                 cblk.clear();
             }
         }
diff --git a/media/libaudioclient/IEffect.cpp b/media/libaudioclient/IEffect.cpp
index ce72dae..5d47dff 100644
--- a/media/libaudioclient/IEffect.cpp
+++ b/media/libaudioclient/IEffect.cpp
@@ -122,7 +122,7 @@
         status_t status = remote()->transact(GET_CBLK, data, &reply);
         if (status == NO_ERROR) {
             cblk = interface_cast<IMemory>(reply.readStrongBinder());
-            if (cblk != 0 && cblk->pointer() == NULL) {
+            if (cblk != 0 && cblk->unsecurePointer() == NULL) {
                 cblk.clear();
             }
         }
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index ef39fd1..0ab1c9d 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -18,9 +18,10 @@
 #ifndef ANDROID_AUDIO_POLICY_H
 #define ANDROID_AUDIO_POLICY_H
 
+#include <binder/Parcel.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <system/audio.h>
 #include <system/audio_policy.h>
-#include <binder/Parcel.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
@@ -60,19 +61,6 @@
 #define MAX_MIXES_PER_POLICY 10
 #define MAX_CRITERIA_PER_MIX 20
 
-class AudioDeviceTypeAddr {
-public:
-    AudioDeviceTypeAddr() {}
-    AudioDeviceTypeAddr(audio_devices_t type, String8 address) :
-        mType(type), mAddress(address) {}
-
-    status_t readFromParcel(Parcel *parcel);
-    status_t writeToParcel(Parcel *parcel) const;
-
-    audio_devices_t mType;
-    String8 mAddress;
-};
-
 class AudioMixMatchCriterion {
 public:
     AudioMixMatchCriterion() {}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 09e80b2..d7266b4 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -19,6 +19,7 @@
 
 #include <sys/types.h>
 
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioPolicy.h>
 #include <media/AudioProductStrategy.h>
 #include <media/AudioVolumeGroup.h>
@@ -396,6 +397,14 @@
 
     static status_t setRttEnabled(bool enabled);
 
+    static bool     isCallScreenModeSupported();
+
+     /**
+     * Send audio HAL server process pids to native audioserver process for use
+     * when generating audio HAL servers tombstones
+     */
+    static status_t setAudioHalPids(const std::vector<pid_t>& pids);
+
     // ----------------------------------------------------------------------------
 
     class AudioVolumeGroupCallback : public RefBase
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 8ec8931..308e9d3 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -27,6 +27,7 @@
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 #include <media/AudioClient.h>
+#include <media/DeviceDescriptorBase.h>
 #include <media/IAudioTrack.h>
 #include <media/IAudioFlingerClient.h>
 #include <system/audio.h>
@@ -70,8 +71,12 @@
                 return DEAD_OBJECT;
             }
             if (parcel->readInt32() != 0) {
+                // TODO: Using unsecurePointer() has some associated security
+                //       pitfalls (see declaration for details).
+                //       Either document why it is safe in this case or address
+                //       the issue (e.g. by copying).
                 sharedBuffer = interface_cast<IMemory>(parcel->readStrongBinder());
-                if (sharedBuffer == 0 || sharedBuffer->pointer() == NULL) {
+                if (sharedBuffer == 0 || sharedBuffer->unsecurePointer() == NULL) {
                     return BAD_VALUE;
                 }
             }
@@ -269,13 +274,21 @@
             (void)parcel->read(&inputId, sizeof(audio_io_handle_t));
             if (parcel->readInt32() != 0) {
                 cblk = interface_cast<IMemory>(parcel->readStrongBinder());
-                if (cblk == 0 || cblk->pointer() == NULL) {
+                // TODO: Using unsecurePointer() has some associated security
+                //       pitfalls (see declaration for details).
+                //       Either document why it is safe in this case or address
+                //       the issue (e.g. by copying).
+                if (cblk == 0 || cblk->unsecurePointer() == NULL) {
                     return BAD_VALUE;
                 }
             }
             if (parcel->readInt32() != 0) {
                 buffers = interface_cast<IMemory>(parcel->readStrongBinder());
-                if (buffers == 0 || buffers->pointer() == NULL) {
+                // TODO: Using unsecurePointer() has some associated security
+                //       pitfalls (see declaration for details).
+                //       Either document why it is safe in this case or address
+                //       the issue (e.g. by copying).
+                if (buffers == 0 || buffers->unsecurePointer() == NULL) {
                     return BAD_VALUE;
                 }
             }
@@ -384,7 +397,7 @@
     // mic mute/state
     virtual     status_t    setMicMute(bool state) = 0;
     virtual     bool        getMicMute() const = 0;
-    virtual     void        setRecordSilenced(uid_t uid, bool silenced) = 0;
+    virtual     void        setRecordSilenced(audio_port_handle_t portId, bool silenced) = 0;
 
     virtual     status_t    setParameters(audio_io_handle_t ioHandle,
                                     const String8& keyValuePairs) = 0;
@@ -404,8 +417,7 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags) = 0;
     virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
@@ -511,6 +523,8 @@
 
     /* List available microphones and their characteristics */
     virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
+
+    virtual status_t setAudioHalPids(const std::vector<pid_t>& pids) = 0;
 };
 
 
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 32275cf..14c1d40 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -23,6 +23,7 @@
 #include <utils/RefBase.h>
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
 #include <media/IAudioPolicyServiceClient.h>
@@ -222,6 +223,8 @@
                                                        volume_group_t &volumeGroup) = 0;
 
     virtual status_t setRttEnabled(bool enabled) = 0;
+
+    virtual bool     isCallScreenModeSupported() = 0;
 };
 
 
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
new file mode 100644
index 0000000..93bc4d9
--- /dev/null
+++ b/media/libaudiofoundation/Android.bp
@@ -0,0 +1,50 @@
+cc_library_headers {
+    name: "libaudiofoundation_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    header_libs: [
+        "libaudio_system_headers",
+        "libmedia_helper_headers",
+    ],
+    export_header_lib_headers: [
+        "libaudio_system_headers",
+        "libmedia_helper_headers",
+    ],
+}
+
+cc_library {
+    name: "libaudiofoundation",
+    vendor_available: true,
+    double_loadable: true,
+
+    srcs: [
+        "AudioContainers.cpp",
+        "AudioDeviceTypeAddr.cpp",
+        "AudioGain.cpp",
+        "AudioPort.cpp",
+        "AudioProfile.cpp",
+        "DeviceDescriptorBase.cpp",
+    ],
+
+    shared_libs: [
+        "libaudioutils",
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+    ],
+
+    header_libs: [
+        "libaudiofoundation_headers",
+    ],
+
+    export_header_lib_headers: [
+        "libaudiofoundation_headers",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
new file mode 100644
index 0000000..1bfe3f9
--- /dev/null
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <string>
+
+#include <media/AudioContainers.h>
+
+namespace android {
+
+const DeviceTypeSet& getAudioDeviceOutAllSet() {
+    static const DeviceTypeSet audioDeviceOutAllSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_ALL_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_ALL_ARRAY));
+    return audioDeviceOutAllSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet() {
+    static const DeviceTypeSet audioDeviceOutAllA2dpSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_ALL_A2DP_ARRAY));
+    return audioDeviceOutAllA2dpSet;
+}
+
+const DeviceTypeSet& getAudioDeviceOutAllScoSet() {
+    static const DeviceTypeSet audioDeviceOutAllScoSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY),
+            std::end(AUDIO_DEVICE_OUT_ALL_SCO_ARRAY));
+    return audioDeviceOutAllScoSet;
+}
+
+const DeviceTypeSet& getAudioDeviceInAllSet() {
+    static const DeviceTypeSet audioDeviceInAllSet = DeviceTypeSet(
+            std::begin(AUDIO_DEVICE_IN_ALL_ARRAY),
+            std::end(AUDIO_DEVICE_IN_ALL_ARRAY));
+    return audioDeviceInAllSet;
+}
+
+bool deviceTypesToString(const DeviceTypeSet &deviceTypes, std::string &str) {
+    if (deviceTypes.empty()) {
+        str = "Empty device types";
+        return true;
+    }
+    bool ret = true;
+    for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+        std::string deviceTypeStr;
+        ret = audio_is_output_device(*it) ?
+              OutputDeviceConverter::toString(*it, deviceTypeStr) :
+              InputDeviceConverter::toString(*it, deviceTypeStr);
+        if (!ret) {
+            break;
+        }
+        str.append(deviceTypeStr);
+        if (++it != deviceTypes.end()) {
+            str.append(" , ");
+        }
+    }
+    if (!ret) {
+        str = "Unknown values";
+    }
+    return ret;
+}
+
+std::string dumpDeviceTypes(const DeviceTypeSet &deviceTypes) {
+    std::string ret;
+    for (auto it = deviceTypes.begin(); it != deviceTypes.end();) {
+        std::stringstream ss;
+        ss << "0x" << std::hex << (*it);
+        ret.append(ss.str());
+        if (++it != deviceTypes.end()) {
+            ret.append(" , ");
+        }
+    }
+    return ret;
+}
+
+std::string toString(const DeviceTypeSet& deviceTypes) {
+    std::string ret;
+    deviceTypesToString(deviceTypes, ret);
+    return ret;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
new file mode 100644
index 0000000..d390467
--- /dev/null
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/AudioDeviceTypeAddr.h>
+
+namespace android {
+
+const char* AudioDeviceTypeAddr::getAddress() const {
+    return mAddress.c_str();
+}
+
+bool AudioDeviceTypeAddr::equals(const AudioDeviceTypeAddr& other) const {
+    return mType == other.mType && mAddress == other.mAddress;
+}
+
+void AudioDeviceTypeAddr::reset() {
+    mType = AUDIO_DEVICE_NONE;
+    mAddress = "";
+}
+
+status_t AudioDeviceTypeAddr::readFromParcel(const Parcel *parcel) {
+    status_t status;
+    if ((status = parcel->readUint32(&mType)) != NO_ERROR) return status;
+    status = parcel->readUtf8FromUtf16(&mAddress);
+    return status;
+}
+
+status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
+    status_t status;
+    if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+    status = parcel->writeUtf8AsUtf16(mAddress);
+    return status;
+}
+
+
+DeviceTypeSet getAudioDeviceTypes(const AudioDeviceTypeAddrVector& deviceTypeAddrs) {
+    DeviceTypeSet deviceTypes;
+    for (const auto& deviceTypeAddr : deviceTypeAddrs) {
+        deviceTypes.insert(deviceTypeAddr.mType);
+    }
+    return deviceTypes;
+}
+
+}
\ No newline at end of file
diff --git a/media/libaudiofoundation/AudioGain.cpp b/media/libaudiofoundation/AudioGain.cpp
new file mode 100644
index 0000000..0d28335
--- /dev/null
+++ b/media/libaudiofoundation/AudioGain.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioGain"
+//#define LOG_NDEBUG 0
+
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+#include <algorithm>
+
+#include <android-base/stringprintf.h>
+#include <media/AudioGain.h>
+#include <utils/Log.h>
+
+#include <math.h>
+
+namespace android {
+
+AudioGain::AudioGain(int index, bool useInChannelMask)
+{
+    mIndex = index;
+    mUseInChannelMask = useInChannelMask;
+    memset(&mGain, 0, sizeof(struct audio_gain));
+}
+
+void AudioGain::getDefaultConfig(struct audio_gain_config *config)
+{
+    config->index = mIndex;
+    config->mode = mGain.mode;
+    config->channel_mask = mGain.channel_mask;
+    if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+        config->values[0] = mGain.default_value;
+    } else {
+        uint32_t numValues;
+        if (mUseInChannelMask) {
+            numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
+        } else {
+            numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
+        }
+        for (size_t i = 0; i < numValues; i++) {
+            config->values[i] = mGain.default_value;
+        }
+    }
+    if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+        config->ramp_duration_ms = mGain.min_ramp_ms;
+    }
+}
+
+status_t AudioGain::checkConfig(const struct audio_gain_config *config)
+{
+    if ((config->mode & ~mGain.mode) != 0) {
+        return BAD_VALUE;
+    }
+    if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
+        if ((config->values[0] < mGain.min_value) ||
+                    (config->values[0] > mGain.max_value)) {
+            return BAD_VALUE;
+        }
+    } else {
+        if ((config->channel_mask & ~mGain.channel_mask) != 0) {
+            return BAD_VALUE;
+        }
+        uint32_t numValues;
+        if (mUseInChannelMask) {
+            numValues = audio_channel_count_from_in_mask(config->channel_mask);
+        } else {
+            numValues = audio_channel_count_from_out_mask(config->channel_mask);
+        }
+        for (size_t i = 0; i < numValues; i++) {
+            if ((config->values[i] < mGain.min_value) ||
+                    (config->values[i] > mGain.max_value)) {
+                return BAD_VALUE;
+            }
+        }
+    }
+    if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
+        if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
+                    (config->ramp_duration_ms > mGain.max_ramp_ms)) {
+            return BAD_VALUE;
+        }
+    }
+    return NO_ERROR;
+}
+
+void AudioGain::dump(std::string *dst, int spaces, int index) const
+{
+    dst->append(base::StringPrintf("%*sGain %d:\n", spaces, "", index+1));
+    dst->append(base::StringPrintf("%*s- mode: %08x\n", spaces, "", mGain.mode));
+    dst->append(base::StringPrintf("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask));
+    dst->append(base::StringPrintf("%*s- min_value: %d mB\n", spaces, "", mGain.min_value));
+    dst->append(base::StringPrintf("%*s- max_value: %d mB\n", spaces, "", mGain.max_value));
+    dst->append(base::StringPrintf("%*s- default_value: %d mB\n", spaces, "", mGain.default_value));
+    dst->append(base::StringPrintf("%*s- step_value: %d mB\n", spaces, "", mGain.step_value));
+    dst->append(base::StringPrintf("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms));
+    dst->append(base::StringPrintf("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms));
+}
+
+bool AudioGain::equals(const sp<AudioGain>& other) const
+{
+    return other != nullptr &&
+           mUseInChannelMask == other->mUseInChannelMask &&
+           mUseForVolume == other->mUseForVolume &&
+           // Compare audio gain
+           mGain.mode == other->mGain.mode &&
+           mGain.channel_mask == other->mGain.channel_mask &&
+           mGain.min_value == other->mGain.min_value &&
+           mGain.max_value == other->mGain.max_value &&
+           mGain.default_value == other->mGain.default_value &&
+           mGain.step_value == other->mGain.step_value &&
+           mGain.min_ramp_ms == other->mGain.min_ramp_ms &&
+           mGain.max_ramp_ms == other->mGain.max_ramp_ms;
+}
+
+status_t AudioGain::writeToParcel(android::Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeInt32(mIndex)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mUseInChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mUseForVolume)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mGain.min_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mGain.max_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mGain.default_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.step_value)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.min_ramp_ms)) != NO_ERROR) return status;
+    status = parcel->writeUint32(mGain.max_ramp_ms);
+    return status;
+}
+
+status_t AudioGain::readFromParcel(const android::Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readInt32(&mIndex)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mUseInChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mUseForVolume)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mGain.min_value)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mGain.max_value)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mGain.default_value)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.step_value)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.min_ramp_ms)) != NO_ERROR) return status;
+    status = parcel->readUint32(&mGain.max_ramp_ms);
+    return status;
+}
+
+bool AudioGains::equals(const AudioGains &other) const
+{
+    return std::equal(begin(), end(), other.begin(), other.end(),
+                      [](const sp<AudioGain>& left, const sp<AudioGain>& right) {
+                          return left->equals(right);
+                      });
+}
+
+status_t AudioGains::writeToParcel(android::Parcel *parcel) const {
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
+    for (const auto &audioGain : *this) {
+        if ((status = parcel->writeParcelable(*audioGain)) != NO_ERROR) {
+            break;
+        }
+    }
+    return status;
+}
+
+status_t AudioGains::readFromParcel(const android::Parcel *parcel) {
+    status_t status = NO_ERROR;
+    this->clear();
+    if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+    for (size_t i = 0; i < this->size(); i++) {
+        this->at(i) = new AudioGain(0, false);
+        if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
+            this->clear();
+            break;
+        }
+    }
+    return status;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
new file mode 100644
index 0000000..f988690
--- /dev/null
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "AudioPort"
+
+#include <algorithm>
+
+#include <android-base/stringprintf.h>
+#include <media/AudioPort.h>
+#include <utils/Log.h>
+
+namespace android {
+
+void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
+{
+    for (const auto& profileToImport : port->mProfiles) {
+        // Import only valid port, i.e. valid format, non empty rates and channels masks
+        if (!profileToImport->isValid()) {
+            continue;
+        }
+        if (std::find_if(mProfiles.begin(), mProfiles.end(),
+                [profileToImport](const auto &profile) {
+                        return *profile == *profileToImport; }) == mProfiles.end()) {
+            addAudioProfile(profileToImport);
+        }
+    }
+}
+
+void AudioPort::toAudioPort(struct audio_port *port) const {
+    // TODO: update this function once audio_port structure reflects the new profile definition.
+    // For compatibility reason: flatening the AudioProfile into audio_port structure.
+    FormatSet flatenedFormats;
+    SampleRateSet flatenedRates;
+    ChannelMaskSet flatenedChannels;
+    for (const auto& profile : mProfiles) {
+        if (profile->isValid()) {
+            audio_format_t formatToExport = profile->getFormat();
+            const SampleRateSet &ratesToExport = profile->getSampleRates();
+            const ChannelMaskSet &channelsToExport = profile->getChannels();
+
+            flatenedFormats.insert(formatToExport);
+            flatenedRates.insert(ratesToExport.begin(), ratesToExport.end());
+            flatenedChannels.insert(channelsToExport.begin(), channelsToExport.end());
+
+            if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
+                    flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
+                    flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
+                ALOGE("%s: bailing out: cannot export profiles to port config", __func__);
+                return;
+            }
+        }
+    }
+    port->role = mRole;
+    port->type = mType;
+    strlcpy(port->name, mName.c_str(), AUDIO_PORT_MAX_NAME_LEN);
+    port->num_sample_rates = flatenedRates.size();
+    port->num_channel_masks = flatenedChannels.size();
+    port->num_formats = flatenedFormats.size();
+    std::copy(flatenedRates.begin(), flatenedRates.end(), port->sample_rates);
+    std::copy(flatenedChannels.begin(), flatenedChannels.end(), port->channel_masks);
+    std::copy(flatenedFormats.begin(), flatenedFormats.end(), port->formats);
+
+    ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
+
+    port->num_gains = std::min(mGains.size(), (size_t) AUDIO_PORT_MAX_GAINS);
+    for (size_t i = 0; i < port->num_gains; i++) {
+        port->gains[i] = mGains[i]->getGain();
+    }
+}
+
+void AudioPort::dump(std::string *dst, int spaces, bool verbose) const {
+    if (!mName.empty()) {
+        dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
+    }
+    if (verbose) {
+        std::string profilesStr;
+        mProfiles.dump(&profilesStr, spaces);
+        dst->append(profilesStr);
+
+        if (mGains.size() != 0) {
+            dst->append(base::StringPrintf("%*s- gains:\n", spaces, ""));
+            for (size_t i = 0; i < mGains.size(); i++) {
+                std::string gainStr;
+                mGains[i]->dump(&gainStr, spaces + 2, i);
+                dst->append(gainStr);
+            }
+        }
+    }
+}
+
+void AudioPort::log(const char* indent) const
+{
+    ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.c_str(), mType, mRole);
+}
+
+bool AudioPort::equals(const sp<AudioPort> &other) const
+{
+    return other != nullptr &&
+           mGains.equals(other->getGains()) &&
+           mName.compare(other->getName()) == 0 &&
+           mType == other->getType() &&
+           mRole == other->getRole() &&
+           mProfiles.equals(other->getAudioProfiles());
+}
+
+status_t AudioPort::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mRole)) != NO_ERROR) return status;
+    if ((status = parcel->writeParcelable(mProfiles)) != NO_ERROR) return status;
+    if ((status = parcel->writeParcelable(mGains)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t AudioPort::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+    static_assert(sizeof(mType) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mType))) != NO_ERROR) {
+        return status;
+    }
+    static_assert(sizeof(mRole) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mRole))) != NO_ERROR) {
+        return status;
+    }
+    mProfiles.clear();
+    if ((status = parcel->readParcelable(&mProfiles)) != NO_ERROR) return status;
+    mGains.clear();
+    if ((status = parcel->readParcelable(&mGains)) != NO_ERROR) return status;
+    return status;
+}
+
+// --- AudioPortConfig class implementation
+
+status_t AudioPortConfig::applyAudioPortConfig(
+        const struct audio_port_config *config,
+        struct audio_port_config *backupConfig __unused)
+{
+    if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+        mSamplingRate = config->sample_rate;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+        mChannelMask = config->channel_mask;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+        mFormat = config->format;
+    }
+    if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+        mGain = config->gain;
+    }
+
+    return NO_ERROR;
+}
+
+namespace {
+
+template<typename T>
+void updateField(
+        const T& portConfigField, T audio_port_config::*port_config_field,
+        struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
+        unsigned int configMask, T defaultValue)
+{
+    if (dstConfig->config_mask & configMask) {
+        if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
+            dstConfig->*port_config_field = srcConfig->*port_config_field;
+        } else {
+            dstConfig->*port_config_field = portConfigField;
+        }
+    } else {
+        dstConfig->*port_config_field = defaultValue;
+    }
+}
+
+} // namespace
+
+void AudioPortConfig::toAudioPortConfig(
+        struct audio_port_config *dstConfig,
+        const struct audio_port_config *srcConfig) const
+{
+    updateField(mSamplingRate, &audio_port_config::sample_rate,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
+    updateField(mChannelMask, &audio_port_config::channel_mask,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
+            (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
+    updateField(mFormat, &audio_port_config::format,
+            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
+    dstConfig->id = mId;
+
+    sp<AudioPort> audioport = getAudioPort();
+    if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
+        dstConfig->gain = mGain;
+        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
+                && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
+            dstConfig->gain = srcConfig->gain;
+        }
+    } else {
+        dstConfig->gain.index = -1;
+    }
+    if (dstConfig->gain.index != -1) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
+    } else {
+        dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+    }
+}
+
+bool AudioPortConfig::hasGainController(bool canUseForVolume) const
+{
+    sp<AudioPort> audioport = getAudioPort();
+    if (!audioport) {
+        return false;
+    }
+    return canUseForVolume ? audioport->getGains().canUseForVolume()
+                           : audioport->getGains().size() > 0;
+}
+
+bool AudioPortConfig::equals(const sp<AudioPortConfig> &other) const
+{
+    return other != nullptr &&
+           mSamplingRate == other->getSamplingRate() &&
+           mFormat == other->getFormat() &&
+           mChannelMask == other->getChannelMask() &&
+           // Compare audio gain config
+           mGain.index == other->mGain.index &&
+           mGain.mode == other->mGain.mode &&
+           mGain.channel_mask == other->mGain.channel_mask &&
+           std::equal(std::begin(mGain.values), std::end(mGain.values),
+                      std::begin(other->mGain.values)) &&
+           mGain.ramp_duration_ms == other->mGain.ramp_duration_ms;
+}
+
+status_t AudioPortConfig::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeUint32(mSamplingRate)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->writeInt32(mId)) != NO_ERROR) return status;
+    // Write mGain to parcel.
+    if ((status = parcel->writeInt32(mGain.index)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mGain.ramp_duration_ms)) != NO_ERROR) return status;
+    std::vector<int> values(std::begin(mGain.values), std::end(mGain.values));
+    if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t AudioPortConfig::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readUint32(&mSamplingRate)) != NO_ERROR) return status;
+    static_assert(sizeof(mFormat) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+        return status;
+    }
+    if ((status = parcel->readUint32(&mChannelMask)) != NO_ERROR) return status;
+    if ((status = parcel->readInt32(&mId)) != NO_ERROR) return status;
+    // Read mGain from parcel.
+    if ((status = parcel->readInt32(&mGain.index)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.mode)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.channel_mask)) != NO_ERROR) return status;
+    if ((status = parcel->readUint32(&mGain.ramp_duration_ms)) != NO_ERROR) return status;
+    std::vector<int> values;
+    if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+    if (values.size() != std::size(mGain.values)) {
+        return BAD_VALUE;
+    }
+    std::copy(values.begin(), values.end(), mGain.values);
+    return status;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
new file mode 100644
index 0000000..91be346
--- /dev/null
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <set>
+
+#define LOG_TAG "AudioProfile"
+//#define LOG_NDEBUG 0
+
+#include <android-base/stringprintf.h>
+#include <media/AudioContainers.h>
+#include <media/AudioProfile.h>
+#include <media/TypeConverter.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+bool operator == (const AudioProfile &left, const AudioProfile &right)
+{
+    return (left.getFormat() == right.getFormat()) &&
+            (left.getChannels() == right.getChannels()) &&
+            (left.getSampleRates() == right.getSampleRates());
+}
+
+// static
+sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
+{
+    AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
+            ChannelMaskSet(), SampleRateSet());
+    dynamicProfile->setDynamicFormat(true);
+    dynamicProfile->setDynamicChannels(true);
+    dynamicProfile->setDynamicRate(true);
+    return dynamicProfile;
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+                           audio_channel_mask_t channelMasks,
+                           uint32_t samplingRate) :
+        mName(""),
+        mFormat(format)
+{
+    mChannelMasks.insert(channelMasks);
+    mSamplingRates.insert(samplingRate);
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+                           const ChannelMaskSet &channelMasks,
+                           const SampleRateSet &samplingRateCollection) :
+        mName(""),
+        mFormat(format),
+        mChannelMasks(channelMasks),
+        mSamplingRates(samplingRateCollection) {}
+
+void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
+{
+    if (mIsDynamicChannels) {
+        mChannelMasks = channelMasks;
+    }
+}
+
+void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
+{
+    if (mIsDynamicRate) {
+        mSamplingRates = sampleRates;
+    }
+}
+
+void AudioProfile::clear()
+{
+    if (mIsDynamicChannels) {
+        mChannelMasks.clear();
+    }
+    if (mIsDynamicRate) {
+        mSamplingRates.clear();
+    }
+}
+
+void AudioProfile::dump(std::string *dst, int spaces) const
+{
+    dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+             mIsDynamicChannels ? "[dynamic channels]" : "",
+             mIsDynamicRate ? "[dynamic rates]" : ""));
+    if (mName.length() != 0) {
+        dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
+    }
+    std::string formatLiteral;
+    if (FormatConverter::toString(mFormat, formatLiteral)) {
+        dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
+    }
+    if (!mSamplingRates.empty()) {
+        dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
+        for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
+            dst->append(base::StringPrintf("%d", *it));
+            dst->append(++it == mSamplingRates.end() ? "" : ", ");
+        }
+        dst->append("\n");
+    }
+
+    if (!mChannelMasks.empty()) {
+        dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
+        for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
+            dst->append(base::StringPrintf("0x%04x", *it));
+            dst->append(++it == mChannelMasks.end() ? "" : ", ");
+        }
+        dst->append("\n");
+    }
+}
+
+bool AudioProfile::equals(const sp<AudioProfile>& other) const
+{
+    return other != nullptr &&
+           mName.compare(other->mName) == 0 &&
+           mFormat == other->getFormat() &&
+           mChannelMasks == other->getChannels() &&
+           mSamplingRates == other->getSampleRates() &&
+           mIsDynamicFormat == other->isDynamicFormat() &&
+           mIsDynamicChannels == other->isDynamicChannels() &&
+           mIsDynamicRate == other->isDynamicRate();
+}
+
+status_t AudioProfile::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeUtf8AsUtf16(mName)) != NO_ERROR) return status;
+    if ((status = parcel->writeUint32(mFormat)) != NO_ERROR) return status;
+    std::vector<int> values(mChannelMasks.begin(), mChannelMasks.end());
+    if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+    values.clear();
+    values.assign(mSamplingRates.begin(), mSamplingRates.end());
+    if ((status = parcel->writeInt32Vector(values)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mIsDynamicFormat)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mIsDynamicChannels)) != NO_ERROR) return status;
+    if ((status = parcel->writeBool(mIsDynamicRate)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t AudioProfile::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->readUtf8FromUtf16(&mName)) != NO_ERROR) return status;
+    static_assert(sizeof(mFormat) == sizeof(uint32_t));
+    if ((status = parcel->readUint32(reinterpret_cast<uint32_t*>(&mFormat))) != NO_ERROR) {
+        return status;
+    }
+    std::vector<int> values;
+    if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+    mChannelMasks.clear();
+    mChannelMasks.insert(values.begin(), values.end());
+    values.clear();
+    if ((status = parcel->readInt32Vector(&values)) != NO_ERROR) return status;
+    mSamplingRates.clear();
+    mSamplingRates.insert(values.begin(), values.end());
+    if ((status = parcel->readBool(&mIsDynamicFormat)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mIsDynamicChannels)) != NO_ERROR) return status;
+    if ((status = parcel->readBool(&mIsDynamicRate)) != NO_ERROR) return status;
+    return status;
+}
+
+ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
+{
+    ssize_t index = size();
+    push_back(profile);
+    return index;
+}
+
+void AudioProfileVector::clearProfiles()
+{
+    for (auto it = begin(); it != end();) {
+        if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
+            it = erase(it);
+        } else {
+            (*it)->clear();
+            ++it;
+        }
+    }
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
+{
+    for (const auto &profile : *this) {
+        if (profile->isValid()) {
+            return profile;
+        }
+    }
+    return nullptr;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
+{
+    for (const auto &profile : *this) {
+        if (profile->isValid() && profile->getFormat() == format) {
+            return profile;
+        }
+    }
+    return nullptr;
+}
+
+FormatVector AudioProfileVector::getSupportedFormats() const
+{
+    FormatVector supportedFormats;
+    for (const auto &profile : *this) {
+        if (profile->hasValidFormat()) {
+            supportedFormats.push_back(profile->getFormat());
+        }
+    }
+    return supportedFormats;
+}
+
+bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
+{
+    for (const auto &profile : *this) {
+        if (profile->getFormat() == format && profile->isDynamicChannels()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicFormat() const
+{
+    for (const auto &profile : *this) {
+        if (profile->isDynamicFormat()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicProfile() const
+{
+    for (const auto &profile : *this) {
+        if (profile->isDynamic()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
+{
+    for (const auto &profile : *this) {
+        if (profile->getFormat() == format && profile->isDynamicRate()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void AudioProfileVector::dump(std::string *dst, int spaces) const
+{
+    dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
+    for (size_t i = 0; i < size(); i++) {
+        dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
+        std::string profileStr;
+        at(i)->dump(&profileStr, spaces + 8);
+        dst->append(profileStr);
+    }
+}
+
+status_t AudioProfileVector::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = parcel->writeVectorSize(*this)) != NO_ERROR) return status;
+    for (const auto &audioProfile : *this) {
+        if ((status = parcel->writeParcelable(*audioProfile)) != NO_ERROR) {
+            break;
+        }
+    }
+    return status;
+}
+
+status_t AudioProfileVector::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    this->clear();
+    if ((status = parcel->resizeOutVector(this)) != NO_ERROR) return status;
+    for (size_t i = 0; i < this->size(); ++i) {
+        this->at(i) = new AudioProfile(AUDIO_FORMAT_DEFAULT, AUDIO_CHANNEL_NONE, 0 /*sampleRate*/);
+        if ((status = parcel->readParcelable(this->at(i).get())) != NO_ERROR) {
+            this->clear();
+            break;
+        }
+    }
+    return status;
+}
+
+bool AudioProfileVector::equals(const AudioProfileVector& other) const
+{
+    return std::equal(begin(), end(), other.begin(), other.end(),
+                      [](const sp<AudioProfile>& left, const sp<AudioProfile>& right) {
+                          return left->equals(right);
+                      });
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/DeviceDescriptorBase.cpp b/media/libaudiofoundation/DeviceDescriptorBase.cpp
new file mode 100644
index 0000000..ef7576e
--- /dev/null
+++ b/media/libaudiofoundation/DeviceDescriptorBase.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DeviceDescriptorBase"
+//#define LOG_NDEBUG 0
+
+#include <android-base/stringprintf.h>
+#include <audio_utils/string.h>
+#include <media/DeviceDescriptorBase.h>
+#include <media/TypeConverter.h>
+
+namespace android {
+
+DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type) :
+        DeviceDescriptorBase(type, "")
+{
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type, const std::string& address) :
+        DeviceDescriptorBase(AudioDeviceTypeAddr(type, address))
+{
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(const AudioDeviceTypeAddr &deviceTypeAddr) :
+        AudioPort("", AUDIO_PORT_TYPE_DEVICE,
+                  audio_is_output_device(deviceTypeAddr.mType) ? AUDIO_PORT_ROLE_SINK :
+                                         AUDIO_PORT_ROLE_SOURCE),
+        mDeviceTypeAddr(deviceTypeAddr)
+{
+    if (mDeviceTypeAddr.mAddress.empty() && audio_is_remote_submix_device(mDeviceTypeAddr.mType)) {
+        mDeviceTypeAddr.mAddress = "0";
+    }
+}
+
+void DeviceDescriptorBase::toAudioPortConfig(struct audio_port_config *dstConfig,
+                                             const struct audio_port_config *srcConfig) const
+{
+    dstConfig->config_mask = AUDIO_PORT_CONFIG_GAIN;
+    if (mSamplingRate != 0) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
+    }
+    if (mChannelMask != AUDIO_CHANNEL_NONE) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
+    }
+    if (mFormat != AUDIO_FORMAT_INVALID) {
+        dstConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
+    }
+
+    if (srcConfig != NULL) {
+        dstConfig->config_mask |= srcConfig->config_mask;
+    }
+
+    AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+
+    dstConfig->role = audio_is_output_device(mDeviceTypeAddr.mType) ?
+                        AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+    dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
+    dstConfig->ext.device.type = mDeviceTypeAddr.mType;
+
+    (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mDeviceTypeAddr.getAddress());
+}
+
+void DeviceDescriptorBase::toAudioPort(struct audio_port *port) const
+{
+    ALOGV("DeviceDescriptorBase::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
+    AudioPort::toAudioPort(port);
+    toAudioPortConfig(&port->active_config);
+    port->id = mId;
+    port->ext.device.type = mDeviceTypeAddr.mType;
+    (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mDeviceTypeAddr.getAddress());
+}
+
+void DeviceDescriptorBase::dump(std::string *dst, int spaces, int index,
+                                const char* extraInfo, bool verbose) const
+{
+    dst->append(base::StringPrintf("%*sDevice %d:\n", spaces, "", index + 1));
+    if (mId != 0) {
+        dst->append(base::StringPrintf("%*s- id: %2d\n", spaces, "", mId));
+    }
+
+    if (extraInfo != nullptr) {
+        dst->append(extraInfo);
+    }
+
+    dst->append(base::StringPrintf("%*s- type: %-48s\n",
+            spaces, "", ::android::toString(mDeviceTypeAddr.mType).c_str()));
+
+    if (mDeviceTypeAddr.mAddress.size() != 0) {
+        dst->append(base::StringPrintf(
+                "%*s- address: %-32s\n", spaces, "", mDeviceTypeAddr.getAddress()));
+    }
+    AudioPort::dump(dst, spaces, verbose);
+}
+
+std::string DeviceDescriptorBase::toString() const
+{
+    std::stringstream sstream;
+    sstream << "type:0x" << std::hex << type() << ",@:" << mDeviceTypeAddr.mAddress;
+    return sstream.str();
+}
+
+void DeviceDescriptorBase::log() const
+{
+    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceTypeAddr.mType,
+          ::android::toString(mDeviceTypeAddr.mType).c_str(),
+          mDeviceTypeAddr.getAddress());
+
+    AudioPort::log("  ");
+}
+
+bool DeviceDescriptorBase::equals(const sp<DeviceDescriptorBase> &other) const
+{
+    return other != nullptr &&
+           static_cast<const AudioPort*>(this)->equals(other) &&
+           static_cast<const AudioPortConfig*>(this)->equals(other) &&
+           mDeviceTypeAddr.equals(other->mDeviceTypeAddr);
+}
+
+status_t DeviceDescriptorBase::writeToParcel(Parcel *parcel) const
+{
+    status_t status = NO_ERROR;
+    if ((status = AudioPort::writeToParcel(parcel)) != NO_ERROR) return status;
+    if ((status = AudioPortConfig::writeToParcel(parcel)) != NO_ERROR) return status;
+    if ((status = parcel->writeParcelable(mDeviceTypeAddr)) != NO_ERROR) return status;
+    return status;
+}
+
+status_t DeviceDescriptorBase::readFromParcel(const Parcel *parcel)
+{
+    status_t status = NO_ERROR;
+    if ((status = AudioPort::readFromParcel(parcel)) != NO_ERROR) return status;
+    if ((status = AudioPortConfig::readFromParcel(parcel)) != NO_ERROR) return status;
+    if ((status = parcel->readParcelable(&mDeviceTypeAddr)) != NO_ERROR) return status;
+    return status;
+}
+
+std::string toString(const DeviceDescriptorBaseVector& devices)
+{
+    std::string ret;
+    for (const auto& device : devices) {
+        if (device != *devices.begin()) {
+            ret += ";";
+        }
+        ret += device->toString();
+    }
+    return ret;
+}
+
+AudioDeviceTypeAddrVector deviceTypeAddrsFromDescriptors(const DeviceDescriptorBaseVector& devices)
+{
+    AudioDeviceTypeAddrVector deviceTypeAddrs;
+    for (const auto& device : devices) {
+        deviceTypeAddrs.push_back(device->getDeviceTypeAddr());
+    }
+    return deviceTypeAddrs;
+}
+
+} // namespace android
diff --git a/media/libaudiofoundation/TEST_MAPPING b/media/libaudiofoundation/TEST_MAPPING
new file mode 100644
index 0000000..f6d249a
--- /dev/null
+++ b/media/libaudiofoundation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+       "name": "audiofoundation_parcelable_test"
+    }
+  ]
+}
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
new file mode 100644
index 0000000..2a3385b
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <set>
+#include <vector>
+
+#include <media/TypeConverter.h>
+#include <system/audio.h>
+
+namespace android {
+
+using ChannelMaskSet = std::set<audio_channel_mask_t>;
+using DeviceTypeSet = std::set<audio_devices_t>;
+using FormatSet = std::set<audio_format_t>;
+using SampleRateSet = std::set<uint32_t>;
+
+using FormatVector = std::vector<audio_format_t>;
+
+const DeviceTypeSet& getAudioDeviceOutAllSet();
+const DeviceTypeSet& getAudioDeviceOutAllA2dpSet();
+const DeviceTypeSet& getAudioDeviceOutAllScoSet();
+const DeviceTypeSet& getAudioDeviceInAllSet();
+
+template<typename T>
+static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) {
+    std::vector<T> intersection;
+    std::set_intersection(a.begin(), a.end(),
+                          b.begin(), b.end(),
+                          std::back_inserter(intersection));
+    return intersection;
+}
+
+static inline ChannelMaskSet asInMask(const ChannelMaskSet& channelMasks) {
+    ChannelMaskSet inMaskSet;
+    for (const auto &channel : channelMasks) {
+        if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
+            inMaskSet.insert(audio_channel_mask_out_to_in(channel));
+        }
+    }
+    return inMaskSet;
+}
+
+static inline ChannelMaskSet asOutMask(const ChannelMaskSet& channelMasks) {
+    ChannelMaskSet outMaskSet;
+    for (const auto &channel : channelMasks) {
+        if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
+            outMaskSet.insert(audio_channel_mask_in_to_out(channel));
+        }
+    }
+    return outMaskSet;
+}
+
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+                                      audio_devices_t deviceType) {
+    return deviceTypes.size() == 1 && *(deviceTypes.begin()) == deviceType;
+}
+
+typedef bool (*DeviceTypeUnaryPredicate)(audio_devices_t);
+static inline bool isSingleDeviceType(const DeviceTypeSet& deviceTypes,
+                                      DeviceTypeUnaryPredicate p) {
+    return deviceTypes.size() == 1 && p(*(deviceTypes.begin()));
+}
+
+static inline bool areAllOfSameDeviceType(const DeviceTypeSet& deviceTypes,
+                                          std::function<bool(audio_devices_t)> p) {
+    return std::all_of(deviceTypes.begin(), deviceTypes.end(), p);
+}
+
+static inline void resetDeviceTypes(DeviceTypeSet& deviceTypes, audio_devices_t typeToAdd) {
+    deviceTypes.clear();
+    deviceTypes.insert(typeToAdd);
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+//  bit mask usages of audio device types.
+static inline audio_devices_t deviceTypesToBitMask(const DeviceTypeSet& deviceTypes) {
+    audio_devices_t types = AUDIO_DEVICE_NONE;
+    for (auto deviceType : deviceTypes) {
+        types |= deviceType;
+    }
+    return types;
+}
+
+// FIXME: This is temporary helper function. Remove this when getting rid of all
+//  bit mask usages of audio device types.
+static inline DeviceTypeSet deviceTypesFromBitMask(audio_devices_t types) {
+    DeviceTypeSet deviceTypes;
+    if ((types & AUDIO_DEVICE_BIT_IN) == 0) {
+        for (auto deviceType : AUDIO_DEVICE_OUT_ALL_ARRAY) {
+            if ((types & deviceType) == deviceType) {
+                deviceTypes.insert(deviceType);
+            }
+        }
+    } else {
+        for (auto deviceType : AUDIO_DEVICE_IN_ALL_ARRAY) {
+            if ((types & deviceType) == deviceType) {
+                deviceTypes.insert(deviceType);
+            }
+        }
+    }
+    return deviceTypes;
+}
+
+bool deviceTypesToString(const DeviceTypeSet& deviceTypes, std::string &str);
+
+std::string dumpDeviceTypes(const DeviceTypeSet& deviceTypes);
+
+/**
+ * Return human readable string for device types.
+ */
+std::string toString(const DeviceTypeSet& deviceTypes);
+
+
+} // namespace android
\ No newline at end of file
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
new file mode 100644
index 0000000..5e5e762
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcelable.h>
+#include <binder/Parcel.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+struct AudioDeviceTypeAddr : public Parcelable {
+    AudioDeviceTypeAddr() = default;
+
+    AudioDeviceTypeAddr(audio_devices_t type, const std::string& address) :
+            mType(type), mAddress(address) {}
+
+    const char* getAddress() const;
+
+    bool equals(const AudioDeviceTypeAddr& other) const;
+
+    void reset();
+
+    status_t readFromParcel(const Parcel *parcel) override;
+
+    status_t writeToParcel(Parcel *parcel) const override;
+
+    audio_devices_t mType = AUDIO_DEVICE_NONE;
+    std::string mAddress;
+};
+
+using AudioDeviceTypeAddrVector = std::vector<AudioDeviceTypeAddr>;
+
+/**
+ * Return a collection of audio device types from a collection of AudioDeviceTypeAddr
+ */
+DeviceTypeSet getAudioDeviceTypes(const AudioDeviceTypeAddrVector& deviceTypeAddrs);
+
+}
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/media/libaudiofoundation/include/media/AudioGain.h
similarity index 82%
rename from services/audiopolicy/common/managerdefinitions/include/AudioGain.h
rename to media/libaudiofoundation/include/media/AudioGain.h
index 4af93e1..859f1e7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/media/libaudiofoundation/include/media/AudioGain.h
@@ -16,15 +16,17 @@
 
 #pragma once
 
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <system/audio.h>
+#include <string>
 #include <vector>
 
 namespace android {
 
-class AudioGain: public RefBase
+class AudioGain: public RefBase, public Parcelable
 {
 public:
     AudioGain(int index, bool useInChannelMask);
@@ -55,7 +57,7 @@
     int getMaxRampInMs() const { return mGain.max_ramp_ms; }
 
     // TODO: remove dump from here (split serialization)
-    void dump(String8 *dst, int spaces, int index) const;
+    void dump(std::string *dst, int spaces, int index) const;
 
     void getDefaultConfig(struct audio_gain_config *config);
     status_t checkConfig(const struct audio_gain_config *config);
@@ -65,6 +67,11 @@
 
     const struct audio_gain &getGain() const { return mGain; }
 
+    bool equals(const sp<AudioGain>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
 private:
     int               mIndex;
     struct audio_gain mGain;
@@ -72,7 +79,7 @@
     bool              mUseForVolume = false;
 };
 
-class AudioGains : public std::vector<sp<AudioGain> >
+class AudioGains : public std::vector<sp<AudioGain> >, public Parcelable
 {
 public:
     bool canUseForVolume() const
@@ -90,6 +97,11 @@
         push_back(gain);
         return 0;
     }
+
+    bool equals(const AudioGains& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
 };
 
 } // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioPort.h b/media/libaudiofoundation/include/media/AudioPort.h
new file mode 100644
index 0000000..3c013cb
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioPort.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioGain.h>
+#include <media/AudioProfile.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort : public virtual RefBase, public virtual Parcelable
+{
+public:
+    AudioPort(const std::string& name, audio_port_type_t type,  audio_port_role_t role) :
+            mName(name), mType(type), mRole(role) {}
+
+    virtual ~AudioPort() = default;
+
+    void setName(const std::string &name) { mName = name; }
+    const std::string &getName() const { return mName; }
+
+    audio_port_type_t getType() const { return mType; }
+    audio_port_role_t getRole() const { return mRole; }
+
+    void setGains(const AudioGains &gains) { mGains = gains; }
+    const AudioGains &getGains() const { return mGains; }
+
+    virtual void toAudioPort(struct audio_port *port) const;
+
+    virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+        mProfiles.add(profile);
+    }
+    virtual void clearAudioProfiles() {
+        mProfiles.clearProfiles();
+    }
+
+    bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+    bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
+
+    void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+    AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
+
+    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const {
+        if (index < 0 || (size_t)index >= mGains.size()) {
+            return BAD_VALUE;
+        }
+        return mGains[index]->checkConfig(gainConfig);
+    }
+
+    bool useInputChannelMask() const
+    {
+        return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
+                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
+    }
+
+    void dump(std::string *dst, int spaces, bool verbose = true) const;
+
+    void log(const char* indent) const;
+
+    bool equals(const sp<AudioPort>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+    AudioGains mGains; // gain controllers
+protected:
+    std::string  mName;
+    audio_port_type_t mType;
+    audio_port_role_t mRole;
+    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+};
+
+
+class AudioPortConfig : public virtual RefBase, public virtual Parcelable
+{
+public:
+    virtual ~AudioPortConfig() = default;
+
+    virtual sp<AudioPort> getAudioPort() const = 0;
+
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
+
+    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+                                   const struct audio_port_config *srcConfig = NULL) const;
+
+    unsigned int getSamplingRate() const { return mSamplingRate; }
+    audio_format_t getFormat() const { return mFormat; }
+    audio_channel_mask_t getChannelMask() const { return mChannelMask; }
+    audio_port_handle_t getId() const { return mId; }
+
+    bool hasGainController(bool canUseForVolume = false) const;
+
+    bool equals(const sp<AudioPortConfig>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+protected:
+    unsigned int mSamplingRate = 0u;
+    audio_format_t mFormat = AUDIO_FORMAT_INVALID;
+    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
+    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
+    struct audio_gain_config mGain = { .index = -1 };
+};
+
+} // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
new file mode 100644
index 0000000..730138a
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class AudioProfile final : public RefBase, public Parcelable
+{
+public:
+    static sp<AudioProfile> createFullDynamic(audio_format_t dynamicFormat = AUDIO_FORMAT_DEFAULT);
+
+    AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
+    AudioProfile(audio_format_t format,
+                 const ChannelMaskSet &channelMasks,
+                 const SampleRateSet &samplingRateCollection);
+
+    audio_format_t getFormat() const { return mFormat; }
+    const ChannelMaskSet &getChannels() const { return mChannelMasks; }
+    const SampleRateSet &getSampleRates() const { return mSamplingRates; }
+    void setChannels(const ChannelMaskSet &channelMasks);
+    void setSampleRates(const SampleRateSet &sampleRates);
+
+    void clear();
+    bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
+    bool supportsChannels(audio_channel_mask_t channels) const
+    {
+        return mChannelMasks.count(channels) != 0;
+    }
+    bool supportsRate(uint32_t rate) const { return mSamplingRates.count(rate) != 0; }
+
+    bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
+    bool hasValidRates() const { return !mSamplingRates.empty(); }
+    bool hasValidChannels() const { return !mChannelMasks.empty(); }
+
+    void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
+    bool isDynamicChannels() const { return mIsDynamicChannels; }
+
+    void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
+    bool isDynamicRate() const { return mIsDynamicRate; }
+
+    void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
+    bool isDynamicFormat() const { return mIsDynamicFormat; }
+
+    bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+
+    void dump(std::string *dst, int spaces) const;
+
+    bool equals(const sp<AudioProfile>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+private:
+    std::string  mName;
+    audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
+    ChannelMaskSet mChannelMasks;
+    SampleRateSet mSamplingRates;
+
+    bool mIsDynamicFormat = false;
+    bool mIsDynamicChannels = false;
+    bool mIsDynamicRate = false;
+};
+
+class AudioProfileVector : public std::vector<sp<AudioProfile>>, public Parcelable
+{
+public:
+    virtual ~AudioProfileVector() = default;
+
+    virtual ssize_t add(const sp<AudioProfile> &profile);
+
+    // If the profile is dynamic format and has valid format, it will be removed when doing
+    // clearProfiles(). Otherwise, AudioProfile::clear() will be called.
+    virtual void clearProfiles();
+
+    sp<AudioProfile> getFirstValidProfile() const;
+    sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
+    bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+
+    FormatVector getSupportedFormats() const;
+    bool hasDynamicChannelsFor(audio_format_t format) const;
+    bool hasDynamicFormat() const;
+    bool hasDynamicProfile() const;
+    bool hasDynamicRateFor(audio_format_t format) const;
+
+    virtual void dump(std::string *dst, int spaces) const;
+
+    bool equals(const AudioProfileVector& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+} // namespace android
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
new file mode 100644
index 0000000..4c03667
--- /dev/null
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <media/AudioContainers.h>
+#include <media/AudioPort.h>
+#include <media/AudioDeviceTypeAddr.h>
+#include <utils/Errors.h>
+#include <cutils/config_utils.h>
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
+namespace android {
+
+class DeviceDescriptorBase : public AudioPort, public AudioPortConfig
+{
+public:
+     // Note that empty name refers by convention to a generic device.
+    explicit DeviceDescriptorBase(audio_devices_t type);
+    DeviceDescriptorBase(audio_devices_t type, const std::string& address);
+    explicit DeviceDescriptorBase(const AudioDeviceTypeAddr& deviceTypeAddr);
+
+    virtual ~DeviceDescriptorBase() {}
+
+    audio_devices_t type() const { return mDeviceTypeAddr.mType; }
+    std::string address() const { return mDeviceTypeAddr.mAddress; }
+    void setAddress(const std::string &address) { mDeviceTypeAddr.mAddress = address; }
+    const AudioDeviceTypeAddr& getDeviceTypeAddr() const { return mDeviceTypeAddr; }
+
+    // AudioPortConfig
+    virtual sp<AudioPort> getAudioPort() const {
+        return static_cast<AudioPort*>(const_cast<DeviceDescriptorBase*>(this));
+    }
+    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+            const struct audio_port_config *srcConfig = NULL) const;
+
+    // AudioPort
+    virtual void toAudioPort(struct audio_port *port) const;
+
+    void dump(std::string *dst, int spaces, int index,
+              const char* extraInfo = nullptr, bool verbose = true) const;
+    void log() const;
+    std::string toString() const;
+
+    bool equals(const sp<DeviceDescriptorBase>& other) const;
+
+    status_t writeToParcel(Parcel* parcel) const override;
+    status_t readFromParcel(const Parcel* parcel) override;
+
+protected:
+    AudioDeviceTypeAddr mDeviceTypeAddr;
+};
+
+using DeviceDescriptorBaseVector = std::vector<sp<DeviceDescriptorBase>>;
+
+/**
+ * Return human readable string for collection of DeviceDescriptorBase.
+ * For a DeviceDescriptorBase, it contains port id, audio device type and address.
+ */
+std::string toString(const DeviceDescriptorBaseVector& devices);
+
+/**
+ * Return a set of device types and addresses from collection of DeviceDescriptorBase.
+ */
+AudioDeviceTypeAddrVector deviceTypeAddrsFromDescriptors(const DeviceDescriptorBaseVector& devices);
+
+} // namespace android
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
new file mode 100644
index 0000000..f258b14
--- /dev/null
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+    name: "audiofoundation_parcelable_test",
+
+    shared_libs: [
+        "libaudiofoundation",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+    ],
+
+    srcs: [
+        "audiofoundation_parcelable_test.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+}
diff --git a/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
new file mode 100644
index 0000000..5baa072
--- /dev/null
+++ b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audiofoundation_parcelable_test"
+
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <media/AudioProfile.h>
+#include <media/DeviceDescriptorBase.h>
+#include <utils/Log.h>
+#include <utils/String16.h>
+
+namespace android {
+
+static const audio_port_config TEST_AUDIO_PORT_CONFIG = {
+        .id = 0,
+        .role = AUDIO_PORT_ROLE_SINK,
+        .type = AUDIO_PORT_TYPE_DEVICE,
+        .config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE | AUDIO_PORT_CONFIG_CHANNEL_MASK |
+                       AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_GAIN,
+        .sample_rate = 48000,
+        .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+        .format = AUDIO_FORMAT_PCM_16_BIT,
+        .gain = {
+                .index = 0,
+                .mode = AUDIO_GAIN_MODE_JOINT,
+                .channel_mask = AUDIO_CHANNEL_OUT_STEREO,
+        }
+};
+
+class AudioPortConfigTestStub : public AudioPortConfig {
+public:
+    sp<AudioPort> getAudioPort() const override { return nullptr; }
+};
+
+AudioGains getAudioGainsForTest() {
+    AudioGains audioGains;
+    sp<AudioGain> audioGain = new AudioGain(0 /*index*/, false /*useInChannelMask*/);
+    audioGain->setMode(AUDIO_GAIN_MODE_JOINT);
+    audioGain->setChannelMask(AUDIO_CHANNEL_OUT_STEREO);
+    audioGain->setMinValueInMb(-3200);
+    audioGain->setMaxValueInMb(600);
+    audioGain->setDefaultValueInMb(0);
+    audioGain->setStepValueInMb(100);
+    audioGain->setMinRampInMs(100);
+    audioGain->setMaxRampInMs(500);
+    audioGains.push_back(audioGain);
+    return audioGains;
+}
+
+AudioProfileVector getAudioProfileVectorForTest() {
+    AudioProfileVector audioProfiles;
+    sp<AudioProfile> audioProfile = AudioProfile::createFullDynamic();
+    audioProfile->setChannels({AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO});
+    audioProfile->setSampleRates({48000});
+    audioProfiles.add(audioProfile);
+    return audioProfiles;
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioGain) {
+    Parcel data;
+    AudioGains audioGains = getAudioGainsForTest();
+
+    ASSERT_EQ(data.writeParcelable(audioGains), NO_ERROR);
+    data.setDataPosition(0);
+    AudioGains audioGainsFromParcel;
+    ASSERT_EQ(data.readParcelable(&audioGainsFromParcel), NO_ERROR);
+    ASSERT_TRUE(audioGainsFromParcel.equals(audioGains));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioProfileVector) {
+    Parcel data;
+    AudioProfileVector audioProfiles = getAudioProfileVectorForTest();
+
+    ASSERT_EQ(data.writeParcelable(audioProfiles), NO_ERROR);
+    data.setDataPosition(0);
+    AudioProfileVector audioProfilesFromParcel;
+    ASSERT_EQ(data.readParcelable(&audioProfilesFromParcel), NO_ERROR);
+    ASSERT_TRUE(audioProfilesFromParcel.equals(audioProfiles));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPort) {
+    Parcel data;
+    sp<AudioPort> audioPort = new AudioPort(
+            "AudioPortName", AUDIO_PORT_TYPE_DEVICE, AUDIO_PORT_ROLE_SINK);
+    audioPort->setGains(getAudioGainsForTest());
+    audioPort->setAudioProfiles(getAudioProfileVectorForTest());
+
+    ASSERT_EQ(data.writeParcelable(*audioPort), NO_ERROR);
+    data.setDataPosition(0);
+    sp<AudioPort> audioPortFromParcel = new AudioPort(
+            "", AUDIO_PORT_TYPE_NONE, AUDIO_PORT_ROLE_NONE);
+    ASSERT_EQ(data.readParcelable(audioPortFromParcel.get()), NO_ERROR);
+    ASSERT_TRUE(audioPortFromParcel->equals(audioPort));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingAudioPortConfig) {
+    Parcel data;
+    sp<AudioPortConfig> audioPortConfig = new AudioPortConfigTestStub();
+    audioPortConfig->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+
+    ASSERT_EQ(data.writeParcelable(*audioPortConfig), NO_ERROR);
+    data.setDataPosition(0);
+    sp<AudioPortConfig> audioPortConfigFromParcel = new AudioPortConfigTestStub();
+    ASSERT_EQ(data.readParcelable(audioPortConfigFromParcel.get()), NO_ERROR);
+    ASSERT_TRUE(audioPortConfigFromParcel->equals(audioPortConfig));
+}
+
+TEST(AudioFoundationParcelableTest, ParcelingDeviceDescriptorBase) {
+    Parcel data;
+    sp<DeviceDescriptorBase> desc = new DeviceDescriptorBase(AUDIO_DEVICE_OUT_SPEAKER);
+    desc->setGains(getAudioGainsForTest());
+    desc->setAudioProfiles(getAudioProfileVectorForTest());
+    desc->applyAudioPortConfig(&TEST_AUDIO_PORT_CONFIG);
+    desc->setAddress("DeviceDescriptorBaseTestAddress");
+
+    ASSERT_EQ(data.writeParcelable(*desc), NO_ERROR);
+    data.setDataPosition(0);
+    sp<DeviceDescriptorBase> descFromParcel = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
+    ASSERT_EQ(data.readParcelable(descFromParcel.get()), NO_ERROR);
+    ASSERT_TRUE(descFromParcel->equals(desc));
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 1b648c9..409a220 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -233,14 +233,14 @@
 
 status_t DeviceHalHidl::openOutputStream(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address,
         sp<StreamOutHalInterface> *outStream) {
     if (mDevice == 0) return NO_INIT;
     DeviceAddress hidlDevice;
-    status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
+    status_t status = deviceAddressFromHal(deviceType, address, &hidlDevice);
     if (status != OK) return status;
     AudioConfig hidlConfig;
     HidlUtils::audioConfigFromHal(*config, &hidlConfig);
@@ -326,6 +326,14 @@
         const struct audio_port_config *sinks,
         audio_patch_handle_t *patch) {
     if (mDevice == 0) return NO_INIT;
+    if (patch == nullptr) return BAD_VALUE;
+
+    if (*patch != AUDIO_PATCH_HANDLE_NONE) {
+        status_t status = releaseAudioPatch(*patch);
+        ALOGW_IF(status != NO_ERROR, "%s error %d releasing patch handle %d",
+            __func__, status, *patch);
+    }
+
     hidl_vec<AudioPortConfig> hidlSources, hidlSinks;
     HidlUtils::audioPortConfigsFromHal(num_sources, sources, &hidlSources);
     HidlUtils::audioPortConfigsFromHal(num_sinks, sinks, &hidlSinks);
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
index ee68252..dfbb6b2 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -104,7 +104,7 @@
 
 status_t DeviceHalLocal::openOutputStream(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address,
@@ -112,11 +112,11 @@
     audio_stream_out_t *halStream;
     ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
             "srate: %d format %#x channels %x address %s",
-            handle, devices, flags,
+            handle, deviceType, flags,
             config->sample_rate, config->format, config->channel_mask,
             address);
     int openResut = mDev->open_output_stream(
-            mDev, handle, devices, flags, config, &halStream, address);
+            mDev, handle, deviceType, flags, config, &halStream, address);
     if (openResut == OK) {
         *outStream = new StreamOutHalLocal(halStream, this);
     }
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index 1335a0c..c30da3c 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -20,6 +20,7 @@
 #define LOG_TAG "DevicesFactoryHalHidl"
 //#define LOG_NDEBUG 0
 
+#include "android/hidl/manager/1.0/IServiceManager.h"
 #include PATH(android/hardware/audio/FILE_VERSION/IDevice.h)
 #include <media/audiohal/hidl/HalDeathHandler.h>
 #include <utils/Log.h>
@@ -28,6 +29,8 @@
 #include "DeviceHalHidl.h"
 #include "DevicesFactoryHalHidl.h"
 
+#include <set>
+
 using ::android::hardware::audio::CPP_VERSION::IDevice;
 using ::android::hardware::audio::CPP_VERSION::Result;
 using ::android::hardware::Return;
@@ -108,5 +111,29 @@
     return BAD_VALUE;
 }
 
+status_t DevicesFactoryHalHidl::getHalPids(std::vector<pid_t> *pids) {
+    std::set<pid_t> pidsSet;
+
+    for (const auto& factory : mDeviceFactories) {
+        using ::android::hidl::base::V1_0::DebugInfo;
+        using android::hidl::manager::V1_0::IServiceManager;
+
+        DebugInfo debugInfo;
+        auto ret = factory->getDebugInfo([&] (const auto &info) {
+               debugInfo = info;
+            });
+        if (!ret.isOk()) {
+           return INVALID_OPERATION;
+        }
+        if (debugInfo.pid == (int)IServiceManager::PidConstant::NO_PID) {
+            continue;
+        }
+        pidsSet.insert(debugInfo.pid);
+    }
+
+    *pids = {pidsSet.begin(), pidsSet.end()};
+    return NO_ERROR;
+}
+
 } // namespace CPP_VERSION
 } // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 8775e7b..52185c8 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -37,6 +37,9 @@
     // Opens a device with the specified name. To close the device, it is
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
+
+            status_t getHalPids(std::vector<pid_t> *pids) override;
+
   private:
     std::vector<sp<IDevicesFactory>> mDeviceFactories;
 
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
index 0e1f1bb..a5aef1b 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp
@@ -37,6 +37,14 @@
     }
     return mLocalFactory->openDevice(name, device);
 }
+
+status_t DevicesFactoryHalHybrid::getHalPids(std::vector<pid_t> *pids) {
+    if (mHidlFactory != 0) {
+        return mHidlFactory->getHalPids(pids);
+    }
+    return INVALID_OPERATION;
+}
+
 } // namespace CPP_VERSION
 
 template <>
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
index 545bb70..2189b36 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHybrid.h
@@ -36,6 +36,8 @@
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
 
+            status_t getHalPids(std::vector<pid_t> *pids) override;
+
   private:
     sp<DevicesFactoryHalInterface> mLocalFactory;
     sp<DevicesFactoryHalInterface> mHidlFactory;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalLocal.h b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
index 5d108dd..2b011f4 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalLocal.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalLocal.h
@@ -33,6 +33,10 @@
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device);
 
+            status_t getHalPids(std::vector<pid_t> *pids __unused) override {
+                return INVALID_OPERATION;
+            }
+
   private:
     friend class DevicesFactoryHalHybrid;
 
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index e565237..2200a7f 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -69,7 +69,7 @@
     // by releasing all references to the returned object.
     virtual status_t openOutputStream(
             audio_io_handle_t handle,
-            audio_devices_t devices,
+            audio_devices_t deviceType,
             audio_output_flags_t flags,
             struct audio_config *config,
             const char *address,
diff --git a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
index 14af384..e9ac1ce 100644
--- a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -20,6 +20,7 @@
 #include <media/audiohal/DeviceHalInterface.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <vector>
 
 namespace android {
 
@@ -30,6 +31,8 @@
     // necessary to release references to the returned object.
     virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device) = 0;
 
+    virtual status_t getHalPids(std::vector<pid_t> *pids) = 0;
+
     static sp<DevicesFactoryHalInterface> create();
 
   protected:
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioprocessing/include/media/AudioMixer.h
similarity index 100%
rename from media/libaudioclient/include/media/AudioMixer.h
rename to media/libaudioprocessing/include/media/AudioMixer.h
diff --git a/media/libmedia/include/media/BufferProviders.h b/media/libaudioprocessing/include/media/BufferProviders.h
similarity index 100%
rename from media/libmedia/include/media/BufferProviders.h
rename to media/libaudioprocessing/include/media/BufferProviders.h
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index 9c82b1d..2a2f36e 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -6,6 +6,7 @@
     srcs: ["EffectDownmix.c"],
 
     shared_libs: [
+        "libaudioutils",
         "libcutils",
         "liblog",
     ],
@@ -23,5 +24,4 @@
         "libaudioeffects",
         "libhardware_headers",
     ],
-    static_libs: ["libaudioutils" ],
 }
diff --git a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
index 7468a90..10eedd9 100644
--- a/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
+++ b/media/libeffects/lvm/lib/Common/lib/VectorArithmetic.h
@@ -53,6 +53,7 @@
                                  LVM_INT16 NrFrames,
                                  LVM_INT32 NrChannels);
 void Copy_Float_Stereo_Mc(       const LVM_FLOAT *src,
+                                 LVM_FLOAT *StereoOut,
                                  LVM_FLOAT *dst,
                                  LVM_INT16 NrFrames,
                                  LVM_INT32 NrChannels);
diff --git a/media/libeffects/lvm/lib/Common/src/Copy_16.c b/media/libeffects/lvm/lib/Common/src/Copy_16.c
index 3858450..3eb3c14 100644
--- a/media/libeffects/lvm/lib/Common/src/Copy_16.c
+++ b/media/libeffects/lvm/lib/Common/src/Copy_16.c
@@ -117,30 +117,31 @@
     }
 }
 
-// Merge a multichannel source with stereo contained in dst, to dst.
+// Merge a multichannel source with stereo contained in StereoOut, to dst.
 void Copy_Float_Stereo_Mc(const LVM_FLOAT *src,
+                 LVM_FLOAT *StereoOut,
                  LVM_FLOAT *dst,
                  LVM_INT16 NrFrames, /* Number of frames*/
                  LVM_INT32 NrChannels)
 {
     LVM_INT16 ii, jj;
-    LVM_FLOAT *src_st = dst + 2 * (NrFrames - 1);
 
-    // repack dst which carries stereo information
+    // pack dst with stereo information of StereoOut
     // together with the upper channels of src.
+    StereoOut += 2 * (NrFrames - 1);
     dst += NrChannels * (NrFrames - 1);
     src += NrChannels * (NrFrames - 1);
     for (ii = NrFrames; ii != 0; ii--)
     {
-        dst[1] = src_st[1];
-        dst[0] = src_st[0]; // copy 1 before 0 is required for NrChannels == 3.
+        dst[1] = StereoOut[1];
+        dst[0] = StereoOut[0]; // copy 1 before 0 is required for NrChannels == 3.
         for (jj = 2; jj < NrChannels; jj++)
         {
             dst[jj] = src[jj];
         }
         dst    -= NrChannels;
         src    -= NrChannels;
-        src_st -= 2;
+        StereoOut -= 2;
     }
 }
 #endif
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
index ab8ccd1..c8df8e4 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Private.h
@@ -60,7 +60,11 @@
 #define LVCS_COMPGAINFRAME          64          /* Compressor gain update interval */
 
 /* Memory */
+#ifdef SUPPORT_MC
+#define LVCS_SCRATCHBUFFERS              8      /* Number of buffers required for inplace processing */
+#else
 #define LVCS_SCRATCHBUFFERS              6      /* Number of buffers required for inplace processing */
+#endif
 #ifdef SUPPORT_MC
 /*
  * The Concert Surround module applies processing only on the first two
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
index ef1d9eb..56fb04f 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Process.c
@@ -106,7 +106,7 @@
      * The Concert Surround module carries out processing only on L, R.
      */
     pInput = pScratch + (2 * NrFrames);
-    pStIn  = pScratch + (LVCS_SCRATCHBUFFERS * NrFrames);
+    pStIn  = pScratch + ((LVCS_SCRATCHBUFFERS - 2) * NrFrames);
     /* The first two channel data is extracted from the input data and
      * copied into pInput buffer
      */
@@ -303,13 +303,45 @@
      */
     if (pInstance->Params.OperatingMode != LVCS_OFF)
     {
+#ifdef SUPPORT_MC
+        LVM_FLOAT *pStereoOut;
+        /*
+         * LVCS_Process_CS uses output buffer to store intermediate outputs of StereoEnhancer,
+         * Equalizer, ReverbGenerator and BypassMixer.
+         * So, to avoid i/o data overlapping, when i/o buffers are common, use scratch buffer
+         * to store intermediate outputs.
+         */
+        if (pOutData == pInData)
+        {
+          /*
+           * Scratch memory is used in 4 chunks of (2 * NrFrames) size.
+           * First chunk of memory is used by LVCS_StereoEnhancer and LVCS_ReverbGenerator,
+           * second and fourth are used as input buffers by pInput and pStIn in LVCS_Process_CS.
+           * Hence, pStereoOut is pointed to use unused third portion of scratch memory.
+           */
+            pStereoOut = (LVM_FLOAT *) \
+                          pInstance->MemoryTable. \
+                          Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress +
+                          ((LVCS_SCRATCHBUFFERS - 4) * NrFrames);
+        }
+        else
+        {
+            pStereoOut = pOutData;
+        }
+
         /*
          * Call CS process function
          */
             err = LVCS_Process_CS(hInstance,
                                   pInData,
+                                  pStereoOut,
+                                  NrFrames);
+#else
+            err = LVCS_Process_CS(hInstance,
+                                  pInData,
                                   pOutData,
                                   NumSamples);
+#endif
 
 
         /*
@@ -329,10 +361,17 @@
 
             if(NumSamples < LVCS_COMPGAINFRAME)
             {
+#ifdef SUPPORT_MC
+                NonLinComp_Float(Gain,                    /* Compressor gain setting */
+                                 pStereoOut,
+                                 pStereoOut,
+                                 (LVM_INT32)(2 * NrFrames));
+#else
                 NonLinComp_Float(Gain,                    /* Compressor gain setting */
                                  pOutData,
                                  pOutData,
                                  (LVM_INT32)(2 * NumSamples));
+#endif
             }
             else
             {
@@ -361,7 +400,11 @@
 
                 FinalGain = Gain;
                 Gain = pInstance->CompressGain;
+#ifdef SUPPORT_MC
+                pOutPtr = pStereoOut;
+#else
                 pOutPtr = pOutData;
+#endif
 
                 while(SampleToProcess > 0)
                 {
@@ -428,6 +471,7 @@
         }
 #ifdef SUPPORT_MC
         Copy_Float_Stereo_Mc(pInData,
+                             pStereoOut,
                              pOutData,
                              NrFrames,
                              channels);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 10dda19..0a2850f 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -2710,7 +2710,7 @@
         name[*pValueSize - 1] = 0;
         *pValueSize = strlen(name) + 1;
         ALOGVV("%s EQ_PARAM_GET_PRESET_NAME preset %d, name %s len %d",
-                __func__, preset, gEqualizerPresets[preset].name, *pValueSize);
+               __func__, preset, name, *pValueSize);
 
     } break;
 
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index bbc14a9..b80f4b4 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -31,6 +31,7 @@
 #include <private/media/VideoFrame.h>
 #include <utils/Log.h>
 #include <utils/RefBase.h>
+#include <vector>
 
 HeifDecoder* createHeifDecoder() {
     return new android::HeifDecoderImpl();
@@ -38,6 +39,22 @@
 
 namespace android {
 
+void initFrameInfo(HeifFrameInfo *info, const VideoFrame *videoFrame) {
+    info->mWidth = videoFrame->mWidth;
+    info->mHeight = videoFrame->mHeight;
+    info->mRotationAngle = videoFrame->mRotationAngle;
+    info->mBytesPerPixel = videoFrame->mBytesPerPixel;
+    info->mDurationUs = videoFrame->mDurationUs;
+    if (videoFrame->mIccSize > 0) {
+        info->mIccData.assign(
+                videoFrame->getFlattenedIccData(),
+                videoFrame->getFlattenedIccData() + videoFrame->mIccSize);
+    } else {
+        // clear old Icc data if there is no Icc data.
+        info->mIccData.clear();
+    }
+}
+
 /*
  * HeifDataSource
  *
@@ -153,7 +170,7 @@
 
     // copy from cache if the request falls entirely in cache
     if (offset + size <= mCachedOffset + mCachedSize) {
-        memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
+        memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
         return size;
     }
 
@@ -251,7 +268,7 @@
     if (bytesAvailable < (int64_t)size) {
         size = bytesAvailable;
     }
-    memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
+    memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
     return size;
 }
 
@@ -290,11 +307,11 @@
     // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
     mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
     mCurScanline(0),
-    mWidth(0),
-    mHeight(0),
+    mTotalScanline(0),
     mFrameDecoded(false),
     mHasImage(false),
     mHasVideo(false),
+    mSequenceLength(0),
     mAvailableLines(0),
     mNumSlices(1),
     mSliceHeight(0),
@@ -333,48 +350,103 @@
 
     mHasImage = hasImage && !strcasecmp(hasImage, "yes");
     mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
-    sp<IMemory> sharedMem;
+
+    HeifFrameInfo* defaultInfo = nullptr;
     if (mHasImage) {
         // image index < 0 to retrieve primary image
-        sharedMem = mRetriever->getImageAtIndex(
+        sp<IMemory> sharedMem = mRetriever->getImageAtIndex(
                 -1, mOutputColor, true /*metaOnly*/);
-    } else if (mHasVideo) {
-        sharedMem = mRetriever->getFrameAtTime(0,
-                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
-                mOutputColor, true /*metaOnly*/);
+
+        if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
+            ALOGE("init: videoFrame is a nullptr");
+            return false;
+        }
+
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->unsecurePointer());
+
+        ALOGV("Image dimension %dx%d, display %dx%d, angle %d, iccSize %d",
+                videoFrame->mWidth,
+                videoFrame->mHeight,
+                videoFrame->mDisplayWidth,
+                videoFrame->mDisplayHeight,
+                videoFrame->mRotationAngle,
+                videoFrame->mIccSize);
+
+        initFrameInfo(&mImageInfo, videoFrame);
+
+        if (videoFrame->mTileHeight >= 512) {
+            // Try decoding in slices only if the image has tiles and is big enough.
+            mSliceHeight = videoFrame->mTileHeight;
+            ALOGV("mSliceHeight %u", mSliceHeight);
+        }
+
+        defaultInfo = &mImageInfo;
     }
 
-    if (sharedMem == nullptr || sharedMem->pointer() == nullptr) {
-        ALOGE("getFrameAtTime: videoFrame is a nullptr");
+    if (mHasVideo) {
+        sp<IMemory> sharedMem = mRetriever->getFrameAtTime(0,
+                MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
+                mOutputColor, true /*metaOnly*/);
+
+        if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
+            ALOGE("init: videoFrame is a nullptr");
+            return false;
+        }
+
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        VideoFrame* videoFrame = static_cast<VideoFrame*>(
+            sharedMem->unsecurePointer());
+
+        ALOGV("Sequence dimension %dx%d, display %dx%d, angle %d, iccSize %d",
+                videoFrame->mWidth,
+                videoFrame->mHeight,
+                videoFrame->mDisplayWidth,
+                videoFrame->mDisplayHeight,
+                videoFrame->mRotationAngle,
+                videoFrame->mIccSize);
+
+        initFrameInfo(&mSequenceInfo, videoFrame);
+
+        mSequenceLength = atoi(mRetriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT));
+
+        if (defaultInfo == nullptr) {
+            defaultInfo = &mSequenceInfo;
+        }
+    }
+
+    if (defaultInfo == nullptr) {
+        ALOGD("No valid image or sequence available");
         return false;
     }
 
-    VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer());
-
-    ALOGV("Meta dimension %dx%d, display %dx%d, angle %d, iccSize %d",
-            videoFrame->mWidth,
-            videoFrame->mHeight,
-            videoFrame->mDisplayWidth,
-            videoFrame->mDisplayHeight,
-            videoFrame->mRotationAngle,
-            videoFrame->mIccSize);
-
     if (frameInfo != nullptr) {
-        frameInfo->set(
-                videoFrame->mWidth,
-                videoFrame->mHeight,
-                videoFrame->mRotationAngle,
-                videoFrame->mBytesPerPixel,
-                videoFrame->mIccSize,
-                videoFrame->getFlattenedIccData());
+        *frameInfo = *defaultInfo;
     }
-    mWidth = videoFrame->mWidth;
-    mHeight = videoFrame->mHeight;
-    if (mHasImage && videoFrame->mTileHeight >= 512 && mWidth >= 3000 && mHeight >= 2000 ) {
-        // Try decoding in slices only if the image has tiles and is big enough.
-        mSliceHeight = videoFrame->mTileHeight;
-        mNumSlices = (videoFrame->mHeight + mSliceHeight - 1) / mSliceHeight;
-        ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
+
+    // default total scanline, this might change if decodeSequence() is used
+    mTotalScanline = defaultInfo->mHeight;
+
+    return true;
+}
+
+bool HeifDecoderImpl::getSequenceInfo(
+        HeifFrameInfo* frameInfo, size_t *frameCount) {
+    ALOGV("%s", __FUNCTION__);
+    if (!mHasVideo) {
+        return false;
+    }
+    if (frameInfo != nullptr) {
+        *frameInfo = mSequenceInfo;
+    }
+    if (frameCount != nullptr) {
+        *frameCount = mSequenceLength;
     }
     return true;
 }
@@ -413,15 +485,15 @@
         ALOGV("decodeAsync(): decoding slice %zu", i);
         size_t top = i * mSliceHeight;
         size_t bottom = (i + 1) * mSliceHeight;
-        if (bottom > mHeight) {
-            bottom = mHeight;
+        if (bottom > mImageInfo.mHeight) {
+            bottom = mImageInfo.mHeight;
         }
         sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
-                -1, mOutputColor, 0, top, mWidth, bottom);
+                -1, mOutputColor, 0, top, mImageInfo.mWidth, bottom);
         {
             Mutex::Autolock autolock(mLock);
 
-            if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
+            if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
                 mAsyncDecodeDone = true;
                 mScanlineReady.signal();
                 break;
@@ -449,42 +521,48 @@
     // See if we want to decode in slices to allow client to start
     // scanline processing in parallel with decode. If this fails
     // we fallback to decoding the full frame.
-    if (mHasImage && mNumSlices > 1) {
-        // get first slice and metadata
-        sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
-                -1, mOutputColor, 0, 0, mWidth, mSliceHeight);
-
-        if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
-            ALOGE("decode: metadata is a nullptr");
-            return false;
+    if (mHasImage) {
+        if (mSliceHeight >= 512 &&
+                mImageInfo.mWidth >= 3000 &&
+                mImageInfo.mHeight >= 2000 ) {
+            // Try decoding in slices only if the image has tiles and is big enough.
+            mNumSlices = (mImageInfo.mHeight + mSliceHeight - 1) / mSliceHeight;
+            ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
         }
 
-        VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->pointer());
+        if (mNumSlices > 1) {
+            // get first slice and metadata
+            sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
+                    -1, mOutputColor, 0, 0, mImageInfo.mWidth, mSliceHeight);
 
-        if (frameInfo != nullptr) {
-            frameInfo->set(
-                    videoFrame->mWidth,
-                    videoFrame->mHeight,
-                    videoFrame->mRotationAngle,
-                    videoFrame->mBytesPerPixel,
-                    videoFrame->mIccSize,
-                    videoFrame->getFlattenedIccData());
+            if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
+                ALOGE("decode: metadata is a nullptr");
+                return false;
+            }
+
+            // TODO: Using unsecurePointer() has some associated security pitfalls
+            //       (see declaration for details).
+            //       Either document why it is safe in this case or address the
+            //       issue (e.g. by copying).
+            VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->unsecurePointer());
+
+            if (frameInfo != nullptr) {
+                initFrameInfo(frameInfo, videoFrame);
+            }
+            mFrameMemory = frameMemory;
+            mAvailableLines = mSliceHeight;
+            mThread = new DecodeThread(this);
+            if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
+                mFrameDecoded = true;
+                return true;
+            }
+            // Fallback to decode without slicing
+            mThread.clear();
+            mNumSlices = 1;
+            mSliceHeight = 0;
+            mAvailableLines = 0;
+            mFrameMemory.clear();
         }
-
-        mFrameMemory = frameMemory;
-        mAvailableLines = mSliceHeight;
-        mThread = new DecodeThread(this);
-        if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
-            mFrameDecoded = true;
-            return true;
-        }
-
-        // Fallback to decode without slicing
-        mThread.clear();
-        mNumSlices = 1;
-        mSliceHeight = 0;
-        mAvailableLines = 0;
-        mFrameMemory.clear();
     }
 
     if (mHasImage) {
@@ -495,12 +573,16 @@
                 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
     }
 
-    if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+    if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
         ALOGE("decode: videoFrame is a nullptr");
         return false;
     }
 
-    VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
     if (videoFrame->mSize == 0 ||
             mFrameMemory->size() < videoFrame->getFlattenedSize()) {
         ALOGE("decode: videoFrame size is invalid");
@@ -517,13 +599,8 @@
             videoFrame->mSize);
 
     if (frameInfo != nullptr) {
-        frameInfo->set(
-                videoFrame->mWidth,
-                videoFrame->mHeight,
-                videoFrame->mRotationAngle,
-                videoFrame->mBytesPerPixel,
-                videoFrame->mIccSize,
-                videoFrame->getFlattenedIccData());
+        initFrameInfo(frameInfo, videoFrame);
+
     }
     mFrameDecoded = true;
 
@@ -533,18 +610,70 @@
     return true;
 }
 
-bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
-    if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
+bool HeifDecoderImpl::decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) {
+    ALOGV("%s: frame index %d", __FUNCTION__, frameIndex);
+    if (!mHasVideo) {
         return false;
     }
-    VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
+
+    if (frameIndex < 0 || frameIndex >= mSequenceLength) {
+        ALOGE("invalid frame index: %d, total frames %zu", frameIndex, mSequenceLength);
+        return false;
+    }
+
+    mCurScanline = 0;
+
+    // set total scanline to sequence height now
+    mTotalScanline = mSequenceInfo.mHeight;
+
+    mFrameMemory = mRetriever->getFrameAtIndex(frameIndex, mOutputColor);
+    if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
+        ALOGE("decode: videoFrame is a nullptr");
+        return false;
+    }
+
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
+    if (videoFrame->mSize == 0 ||
+            mFrameMemory->size() < videoFrame->getFlattenedSize()) {
+        ALOGE("decode: videoFrame size is invalid");
+        return false;
+    }
+
+    ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
+            videoFrame->mWidth,
+            videoFrame->mHeight,
+            videoFrame->mDisplayWidth,
+            videoFrame->mDisplayHeight,
+            videoFrame->mRotationAngle,
+            videoFrame->mRowBytes,
+            videoFrame->mSize);
+
+    if (frameInfo != nullptr) {
+        initFrameInfo(frameInfo, videoFrame);
+    }
+    return true;
+}
+
+bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
+    if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
+        return false;
+    }
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
     uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
     memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
     return true;
 }
 
 bool HeifDecoderImpl::getScanline(uint8_t* dst) {
-    if (mCurScanline >= mHeight) {
+    if (mCurScanline >= mTotalScanline) {
         ALOGE("no more scanline available");
         return false;
     }
@@ -564,8 +693,8 @@
 size_t HeifDecoderImpl::skipScanlines(size_t count) {
     uint32_t oldScanline = mCurScanline;
     mCurScanline += count;
-    if (mCurScanline > mHeight) {
-        mCurScanline = mHeight;
+    if (mCurScanline > mTotalScanline) {
+        mCurScanline = mTotalScanline;
     }
     return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
 }
diff --git a/media/libheif/HeifDecoderImpl.h b/media/libheif/HeifDecoderImpl.h
index 528ee3b..69c74a7 100644
--- a/media/libheif/HeifDecoderImpl.h
+++ b/media/libheif/HeifDecoderImpl.h
@@ -40,12 +40,16 @@
 
     bool init(HeifStream* stream, HeifFrameInfo* frameInfo) override;
 
+    bool getSequenceInfo(HeifFrameInfo* frameInfo, size_t *frameCount) override;
+
     bool getEncodedColor(HeifEncodedColor* outColor) const override;
 
     bool setOutputColor(HeifColorFormat heifColor) override;
 
     bool decode(HeifFrameInfo* frameInfo) override;
 
+    bool decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) override;
+
     bool getScanline(uint8_t* dst) override;
 
     size_t skipScanlines(size_t count) override;
@@ -56,13 +60,15 @@
     sp<IDataSource> mDataSource;
     sp<MediaMetadataRetriever> mRetriever;
     sp<IMemory> mFrameMemory;
+    HeifFrameInfo mImageInfo;
+    HeifFrameInfo mSequenceInfo;
     android_pixel_format_t mOutputColor;
     size_t mCurScanline;
-    uint32_t mWidth;
-    uint32_t mHeight;
+    size_t mTotalScanline;
     bool mFrameDecoded;
     bool mHasImage;
     bool mHasVideo;
+    size_t mSequenceLength;
 
     // Slice decoding only
     Mutex mLock;
diff --git a/media/libheif/include/HeifDecoderAPI.h b/media/libheif/include/HeifDecoderAPI.h
index aa10f33..9073672 100644
--- a/media/libheif/include/HeifDecoderAPI.h
+++ b/media/libheif/include/HeifDecoderAPI.h
@@ -17,7 +17,7 @@
 #ifndef _HEIF_DECODER_API_
 #define _HEIF_DECODER_API_
 
-#include <memory>
+#include <vector>
 
 /*
  * The output color pixel format of heif decoder.
@@ -40,41 +40,13 @@
 /*
  * Represents a color converted (RGB-based) video frame
  */
-struct HeifFrameInfo
-{
-    HeifFrameInfo() :
-        mWidth(0), mHeight(0), mRotationAngle(0), mBytesPerPixel(0),
-        mIccSize(0), mIccData(nullptr) {}
-
-    // update the frame info, will make a copy of |iccData| internally
-    void set(uint32_t width, uint32_t height, int32_t rotation, uint32_t bpp,
-            uint32_t iccSize, uint8_t* iccData) {
-        mWidth = width;
-        mHeight = height;
-        mRotationAngle = rotation;
-        mBytesPerPixel = bpp;
-
-        if (mIccData != nullptr) {
-            mIccData.reset(nullptr);
-        }
-        mIccSize = iccSize;
-        if (iccSize > 0) {
-            mIccData.reset(new uint8_t[iccSize]);
-            if (mIccData.get() != nullptr) {
-                memcpy(mIccData.get(), iccData, iccSize);
-            } else {
-                mIccSize = 0;
-            }
-        }
-    }
-
-    // Intentional public access modifiers:
+struct HeifFrameInfo {
     uint32_t mWidth;
     uint32_t mHeight;
     int32_t  mRotationAngle;           // Rotation angle, clockwise, should be multiple of 90
     uint32_t mBytesPerPixel;           // Number of bytes for one pixel
-    uint32_t mIccSize;                 // Number of bytes in mIccData
-    std::unique_ptr<uint8_t[]> mIccData; // Actual ICC data, memory is owned by this structure
+    int64_t mDurationUs;               // Duration of the frame in us
+    std::vector<uint8_t> mIccData;     // ICC data array
 };
 
 /*
@@ -113,8 +85,8 @@
     virtual size_t getLength() const = 0;
 
 private:
-    HeifStream(const HeifFrameInfo&) = delete;
-    HeifStream& operator=(const HeifFrameInfo&) = delete;
+    HeifStream(const HeifStream&) = delete;
+    HeifStream& operator=(const HeifStream&) = delete;
 };
 
 /*
@@ -146,6 +118,14 @@
     virtual bool init(HeifStream* stream, HeifFrameInfo* frameInfo) = 0;
 
     /*
+     * Returns true if the stream contains an image sequence and false otherwise.
+     * |frameInfo| will be filled with information of pictures in the sequence
+     * and |frameCount| the length of the sequence upon success and unmodified
+     * upon failure.
+     */
+    virtual bool getSequenceInfo(HeifFrameInfo* frameInfo, size_t *frameCount) = 0;
+
+    /*
      * Decode the picture internally, returning whether it succeeded. |frameInfo|
      * will be filled with information of the primary picture upon success and
      * unmodified upon failure.
@@ -156,6 +136,20 @@
     virtual bool decode(HeifFrameInfo* frameInfo) = 0;
 
     /*
+     * Decode the picture from the image sequence at index |frameIndex|.
+     * |frameInfo| will be filled with information of the decoded picture upon
+     * success and unmodified upon failure.
+     *
+     * |frameIndex| is the 0-based index of the video frame to retrieve. The frame
+     * index must be that of a valid frame. The total number of frames available for
+     * retrieval was reported via getSequenceInfo().
+     *
+     * After this succeeded, getScanline can be called to read the scanlines
+     * that were decoded.
+     */
+    virtual bool decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) = 0;
+
+    /*
      * Read the next scanline (in top-down order), returns true upon success
      * and false otherwise.
      */
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index b49df9e..b064f08 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -2,7 +2,7 @@
     name: "libmedia_headers",
     vendor_available: true,
     export_include_dirs: ["include"],
-    header_libs:[
+    header_libs: [
         "libbase_headers",
         "libgui_headers",
         "libstagefright_headers",
@@ -15,40 +15,28 @@
     ],
 }
 
-cc_library {
-    name: "libmedia_helper",
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
-    double_loadable: true,
-    srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
-    cflags: [
-        "-Werror",
-        "-Wno-error=deprecated-declarations",
-        "-Wall",
-    ],
-    shared_libs: ["libutils", "liblog"],
-    header_libs: [
-        "libmedia_headers",
-        "libaudioclient_headers",
-        "libaudio_system_headers",
-    ],
-    export_header_lib_headers: [
-        "libmedia_headers",
-    ],
-    clang: true,
-}
-
 filegroup {
     name: "libmedia_omx_aidl",
     srcs: [
-        "aidl/android/IGraphicBufferSource.aidl",
         "aidl/android/IOMXBufferSource.aidl",
     ],
     path: "aidl",
 }
 
+aidl_interface {
+    name: "resourcemanager_aidl_interface",
+    local_include_dir: "aidl",
+    srcs: [
+        "aidl/android/media/IResourceManagerClient.aidl",
+        "aidl/android/media/IResourceManagerService.aidl",
+        "aidl/android/media/MediaResourceType.aidl",
+        "aidl/android/media/MediaResourceSubType.aidl",
+        "aidl/android/media/MediaResourceParcel.aidl",
+        "aidl/android/media/MediaResourcePolicyParcel.aidl",
+    ],
+    versions: ["1"],
+}
+
 cc_library_shared {
     name: "libmedia_omx",
     vendor_available: true,
@@ -63,7 +51,6 @@
         "IOMX.cpp",
         "MediaCodecBuffer.cpp",
         "OMXBuffer.cpp",
-        "omx/1.0/WGraphicBufferSource.cpp",
         "omx/1.0/WOmxBufferSource.cpp",
         "omx/1.0/WOmxNode.cpp",
         "omx/1.0/WOmxObserver.cpp",
@@ -127,7 +114,6 @@
     },
 }
 
-
 cc_library_shared {
     name: "libmedia_omx_client",
 
@@ -278,8 +264,6 @@
         "IMediaSource.cpp",
         "IRemoteDisplay.cpp",
         "IRemoteDisplayClient.cpp",
-        "IResourceManagerClient.cpp",
-        "IResourceManagerService.cpp",
         "IStreamSource.cpp",
         "MediaUtils.cpp",
         "Metadata.cpp",
@@ -342,7 +326,12 @@
     ],
 
     static_libs: [
-        "libc_malloc_debug_backtrace",  // for memory heap analysis
+        "libc_malloc_debug_backtrace", // for memory heap analysis
+        "resourcemanager_aidl_interface-unstable-cpp",
+    ],
+
+    export_static_lib_headers: [
+        "resourcemanager_aidl_interface-unstable-cpp",
     ],
 
     export_include_dirs: [
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
index 1bb8d67..8cbb4c2 100644
--- a/media/libmedia/IMediaHTTPConnection.cpp
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -128,12 +128,12 @@
            ALOGE("readAt got a NULL buffer");
            return UNKNOWN_ERROR;
         }
-        if (mMemory->pointer() == NULL) {
-           ALOGE("readAt got a NULL mMemory->pointer()");
+        if (mMemory->unsecurePointer() == NULL) {
+           ALOGE("readAt got a NULL mMemory->unsecurePointer()");
            return UNKNOWN_ERROR;
         }
 
-        memcpy(buffer, mMemory->pointer(), len);
+        memcpy(buffer, mMemory->unsecurePointer(), len);
 
         return len;
     }
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index f9fa86e..d95bc8e 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -109,7 +109,7 @@
             data.writeInt32(0);
         } else {
             // serialize the headers
-            data.writeInt64(headers->size());
+            data.writeInt32(headers->size());
             for (size_t i = 0; i < headers->size(); ++i) {
                 data.writeString8(headers->keyAt(i));
                 data.writeString8(headers->valueAt(i));
@@ -213,15 +213,14 @@
         return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
-    status_t getFrameAtIndex(std::vector<sp<IMemory> > *frames,
-            int frameIndex, int numFrames, int colorFormat, bool metaOnly)
+    sp<IMemory> getFrameAtIndex(
+            int index, int colorFormat, bool metaOnly)
     {
-        ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
-                frameIndex, numFrames, colorFormat, metaOnly);
+        ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
+                index, colorFormat, metaOnly);
         Parcel data, reply;
         data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
-        data.writeInt32(frameIndex);
-        data.writeInt32(numFrames);
+        data.writeInt32(index);
         data.writeInt32(colorFormat);
         data.writeInt32(metaOnly);
 #ifndef DISABLE_GROUP_SCHEDULE_HACK
@@ -230,16 +229,9 @@
         remote()->transact(GET_FRAME_AT_INDEX, data, &reply);
         status_t ret = reply.readInt32();
         if (ret != NO_ERROR) {
-            return ret;
+            return NULL;
         }
-        int retNumFrames = reply.readInt32();
-        if (retNumFrames < numFrames) {
-            numFrames = retNumFrames;
-        }
-        for (int i = 0; i < numFrames; i++) {
-            frames->push_back(interface_cast<IMemory>(reply.readStrongBinder()));
-        }
-        return OK;
+        return interface_cast<IMemory>(reply.readStrongBinder());
     }
 
     sp<IMemory> extractAlbumArt()
@@ -318,11 +310,22 @@
             }
 
             KeyedVector<String8, String8> headers;
-            size_t numHeaders = (size_t) data.readInt64();
+            size_t numHeaders = (size_t) data.readInt32();
             for (size_t i = 0; i < numHeaders; ++i) {
-                String8 key = data.readString8();
-                String8 value = data.readString8();
-                headers.add(key, value);
+                String8 key;
+                String8 value;
+                status_t status;
+                status = data.readString8(&key);
+                if (status != OK) {
+                    return status;
+                }
+                status = data.readString8(&value);
+                if (status != OK) {
+                    return status;
+                }
+                if (headers.add(key, value) < 0) {
+                    return UNKNOWN_ERROR;
+                }
             }
 
             reply->writeInt32(
@@ -431,24 +434,20 @@
 
         case GET_FRAME_AT_INDEX: {
             CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
-            int frameIndex = data.readInt32();
-            int numFrames = data.readInt32();
+            int index = data.readInt32();
             int colorFormat = data.readInt32();
             bool metaOnly = (data.readInt32() != 0);
-            ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
-                    frameIndex, numFrames, colorFormat, metaOnly);
+            ALOGV("getFrameAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
+                    index, colorFormat, metaOnly);
 #ifndef DISABLE_GROUP_SCHEDULE_HACK
             setSchedPolicy(data);
 #endif
-            std::vector<sp<IMemory> > frames;
-            status_t err = getFrameAtIndex(
-                    &frames, frameIndex, numFrames, colorFormat, metaOnly);
-            reply->writeInt32(err);
-            if (OK == err) {
-                reply->writeInt32(frames.size());
-                for (size_t i = 0; i < frames.size(); i++) {
-                    reply->writeStrongBinder(IInterface::asBinder(frames[i]));
-                }
+            sp<IMemory> frame = getFrameAtIndex(index, colorFormat, metaOnly);
+            if (frame != nullptr) {  // Don't send NULL across the binder interface
+                reply->writeInt32(NO_ERROR);
+                reply->writeStrongBinder(IInterface::asBinder(frame));
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
             }
 #ifndef DISABLE_GROUP_SCHEDULE_HACK
             restoreSchedPolicy();
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index bc0c2cd..959a3d7 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -29,7 +29,6 @@
 #include <utils/NativeHandle.h>
 
 #include <media/omx/1.0/WOmxNode.h>
-#include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
 
 namespace android {
diff --git a/media/libmedia/IResourceManagerClient.cpp b/media/libmedia/IResourceManagerClient.cpp
deleted file mode 100644
index 1fea479..0000000
--- a/media/libmedia/IResourceManagerClient.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <utils/RefBase.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IResourceManagerClient.h>
-
-namespace android {
-
-enum {
-    RECLAIM_RESOURCE = IBinder::FIRST_CALL_TRANSACTION,
-    GET_NAME,
-};
-
-class BpResourceManagerClient: public BpInterface<IResourceManagerClient>
-{
-public:
-    explicit BpResourceManagerClient(const sp<IBinder> &impl)
-        : BpInterface<IResourceManagerClient>(impl)
-    {
-    }
-
-    virtual bool reclaimResource() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IResourceManagerClient::getInterfaceDescriptor());
-
-        bool ret = false;
-        status_t status = remote()->transact(RECLAIM_RESOURCE, data, &reply);
-        if (status == NO_ERROR) {
-            ret = (bool)reply.readInt32();
-        }
-        return ret;
-    }
-
-    virtual String8 getName() {
-        Parcel data, reply;
-        data.writeInterfaceToken(IResourceManagerClient::getInterfaceDescriptor());
-
-        String8 ret;
-        status_t status = remote()->transact(GET_NAME, data, &reply);
-        if (status == NO_ERROR) {
-            ret = reply.readString8();
-        }
-        return ret;
-    }
-
-};
-
-IMPLEMENT_META_INTERFACE(ResourceManagerClient, "android.media.IResourceManagerClient");
-
-// ----------------------------------------------------------------------
-
-status_t BnResourceManagerClient::onTransact(
-    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
-{
-    switch (code) {
-        case RECLAIM_RESOURCE: {
-            CHECK_INTERFACE(IResourceManagerClient, data, reply);
-            bool ret = reclaimResource();
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        } break;
-        case GET_NAME: {
-            CHECK_INTERFACE(IResourceManagerClient, data, reply);
-            String8 ret = getName();
-            reply->writeString8(ret);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}; // namespace android
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
deleted file mode 100644
index f8a0a14..0000000
--- a/media/libmedia/IResourceManagerService.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "IResourceManagerService"
-#include <utils/Log.h>
-
-#include <media/IResourceManagerService.h>
-
-#include <binder/Parcel.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-
-namespace android {
-
-enum {
-    CONFIG = IBinder::FIRST_CALL_TRANSACTION,
-    ADD_RESOURCE,
-    REMOVE_RESOURCE,
-    REMOVE_CLIENT,
-    RECLAIM_RESOURCE,
-};
-
-template <typename T>
-static void writeToParcel(Parcel *data, const Vector<T> &items) {
-    size_t size = items.size();
-    // truncates size, but should be okay for this usecase
-    data->writeUint32(static_cast<uint32_t>(size));
-    for (size_t i = 0; i < size; i++) {
-        items[i].writeToParcel(data);
-    }
-}
-
-template <typename T>
-static void readFromParcel(const Parcel &data, Vector<T> *items) {
-    size_t size = (size_t)data.readUint32();
-    for (size_t i = 0; i < size && data.dataAvail() > 0; i++) {
-        T item;
-        item.readFromParcel(data);
-        items->add(item);
-    }
-}
-
-class BpResourceManagerService : public BpInterface<IResourceManagerService>
-{
-public:
-    explicit BpResourceManagerService(const sp<IBinder> &impl)
-        : BpInterface<IResourceManagerService>(impl)
-    {
-    }
-
-    virtual void config(const Vector<MediaResourcePolicy> &policies) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
-        writeToParcel(&data, policies);
-        remote()->transact(CONFIG, data, &reply);
-    }
-
-    virtual void addResource(
-            int pid,
-            int uid,
-            int64_t clientId,
-            const sp<IResourceManagerClient> client,
-            const Vector<MediaResource> &resources) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
-        data.writeInt32(pid);
-        data.writeInt32(uid);
-        data.writeInt64(clientId);
-        data.writeStrongBinder(IInterface::asBinder(client));
-        writeToParcel(&data, resources);
-
-        remote()->transact(ADD_RESOURCE, data, &reply);
-    }
-
-    virtual void removeResource(int pid, int64_t clientId, const Vector<MediaResource> &resources) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
-        data.writeInt32(pid);
-        data.writeInt64(clientId);
-        writeToParcel(&data, resources);
-
-        remote()->transact(REMOVE_RESOURCE, data, &reply);
-    }
-
-    virtual void removeClient(int pid, int64_t clientId) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
-        data.writeInt32(pid);
-        data.writeInt64(clientId);
-
-        remote()->transact(REMOVE_CLIENT, data, &reply);
-    }
-
-    virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
-        data.writeInt32(callingPid);
-        writeToParcel(&data, resources);
-
-        bool ret = false;
-        status_t status = remote()->transact(RECLAIM_RESOURCE, data, &reply);
-        if (status == NO_ERROR) {
-            ret = (bool)reply.readInt32();
-        }
-        return ret;
-    }
-};
-
-IMPLEMENT_META_INTERFACE(ResourceManagerService, "android.media.IResourceManagerService");
-
-// ----------------------------------------------------------------------
-
-
-status_t BnResourceManagerService::onTransact(
-    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
-{
-    switch (code) {
-        case CONFIG: {
-            CHECK_INTERFACE(IResourceManagerService, data, reply);
-            Vector<MediaResourcePolicy> policies;
-            readFromParcel(data, &policies);
-            config(policies);
-            return NO_ERROR;
-        } break;
-
-        case ADD_RESOURCE: {
-            CHECK_INTERFACE(IResourceManagerService, data, reply);
-            int pid = data.readInt32();
-            int uid = data.readInt32();
-            int64_t clientId = data.readInt64();
-            sp<IResourceManagerClient> client(
-                    interface_cast<IResourceManagerClient>(data.readStrongBinder()));
-            if (client == NULL) {
-                return NO_ERROR;
-            }
-            Vector<MediaResource> resources;
-            readFromParcel(data, &resources);
-            addResource(pid, uid, clientId, client, resources);
-            return NO_ERROR;
-        } break;
-
-        case REMOVE_RESOURCE: {
-            CHECK_INTERFACE(IResourceManagerService, data, reply);
-            int pid = data.readInt32();
-            int64_t clientId = data.readInt64();
-            Vector<MediaResource> resources;
-            readFromParcel(data, &resources);
-            removeResource(pid, clientId, resources);
-            return NO_ERROR;
-        } break;
-
-        case REMOVE_CLIENT: {
-            CHECK_INTERFACE(IResourceManagerService, data, reply);
-            int pid = data.readInt32();
-            int64_t clientId = data.readInt64();
-            removeClient(pid, clientId);
-            return NO_ERROR;
-        } break;
-
-        case RECLAIM_RESOURCE: {
-            CHECK_INTERFACE(IResourceManagerService, data, reply);
-            int callingPid = data.readInt32();
-            Vector<MediaResource> resources;
-            readFromParcel(data, &resources);
-            bool ret = reclaimResource(callingPid, resources);
-            reply->writeInt32(ret);
-            return NO_ERROR;
-        } break;
-
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index e636a50..fe86d27 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -19,47 +19,73 @@
 #include <utils/Log.h>
 #include <media/MediaResource.h>
 
+#include <vector>
+
 namespace android {
 
-MediaResource::MediaResource()
-        : mType(kUnspecified),
-          mSubType(kUnspecifiedSubType),
-          mValue(0) {}
-
-MediaResource::MediaResource(Type type, uint64_t value)
-        : mType(type),
-          mSubType(kUnspecifiedSubType),
-          mValue(value) {}
-
-MediaResource::MediaResource(Type type, SubType subType, uint64_t value)
-        : mType(type),
-          mSubType(subType),
-          mValue(value) {}
-
-void MediaResource::readFromParcel(const Parcel &parcel) {
-    mType = static_cast<Type>(parcel.readInt32());
-    mSubType = static_cast<SubType>(parcel.readInt32());
-    mValue = parcel.readUint64();
+MediaResource::MediaResource(Type type, int64_t value) {
+    this->type = type;
+    this->subType = SubType::kUnspecifiedSubType;
+    this->value = value;
 }
 
-void MediaResource::writeToParcel(Parcel *parcel) const {
-    parcel->writeInt32(static_cast<int32_t>(mType));
-    parcel->writeInt32(static_cast<int32_t>(mSubType));
-    parcel->writeUint64(mValue);
+MediaResource::MediaResource(Type type, SubType subType, int64_t value) {
+    this->type = type;
+    this->subType = subType;
+    this->value = value;
 }
 
-String8 MediaResource::toString() const {
+MediaResource::MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value) {
+    this->type = type;
+    this->subType = SubType::kUnspecifiedSubType;
+    this->id = id;
+    this->value = value;
+}
+
+//static
+MediaResource MediaResource::CodecResource(bool secure, bool video) {
+    return MediaResource(
+            secure ? Type::kSecureCodec : Type::kNonSecureCodec,
+            video ? SubType::kVideoCodec : SubType::kAudioCodec,
+            1);
+}
+
+//static
+MediaResource MediaResource::GraphicMemoryResource(int64_t value) {
+    return MediaResource(Type::kGraphicMemory, value);
+}
+
+//static
+MediaResource MediaResource::CpuBoostResource() {
+    return MediaResource(Type::kCpuBoost, 1);
+}
+
+//static
+MediaResource MediaResource::VideoBatteryResource() {
+    return MediaResource(Type::kBattery, SubType::kVideoCodec, 1);
+}
+
+//static
+MediaResource MediaResource::DrmSessionResource(const std::vector<uint8_t> &id, int64_t value) {
+    return MediaResource(Type::kDrmSession, id, value);
+}
+
+static String8 bytesToHexString(const std::vector<uint8_t> &bytes) {
     String8 str;
-    str.appendFormat("%s/%s:%llu", asString(mType), asString(mSubType), (unsigned long long)mValue);
+    for (auto &b : bytes) {
+        str.appendFormat("%02x", b);
+    }
     return str;
 }
 
-bool MediaResource::operator==(const MediaResource &other) const {
-    return (other.mType == mType) && (other.mSubType == mSubType) && (other.mValue == mValue);
-}
+String8 toString(const MediaResourceParcel& resource) {
+    String8 str;
 
-bool MediaResource::operator!=(const MediaResource &other) const {
-    return !(*this == other);
+    str.appendFormat("%s/%s:[%s]:%lld",
+            asString(resource.type), asString(resource.subType),
+            bytesToHexString(resource.id).c_str(),
+            (long long)resource.value);
+    return str;
 }
 
 }; // namespace android
diff --git a/media/libmedia/MediaResourcePolicy.cpp b/media/libmedia/MediaResourcePolicy.cpp
index 5210825..c463179 100644
--- a/media/libmedia/MediaResourcePolicy.cpp
+++ b/media/libmedia/MediaResourcePolicy.cpp
@@ -18,31 +18,29 @@
 #define LOG_TAG "MediaResourcePolicy"
 #include <utils/Log.h>
 #include <media/MediaResourcePolicy.h>
+#include <android/media/IResourceManagerService.h>
 
 namespace android {
 
-const char kPolicySupportsMultipleSecureCodecs[] = "supports-multiple-secure-codecs";
-const char kPolicySupportsSecureWithNonSecureCodec[] = "supports-secure-with-non-secure-codec";
-
-MediaResourcePolicy::MediaResourcePolicy() {}
-
-MediaResourcePolicy::MediaResourcePolicy(String8 type, String8 value)
-        : mType(type),
-          mValue(value) {}
-
-void MediaResourcePolicy::readFromParcel(const Parcel &parcel) {
-    mType = parcel.readString8();
-    mValue = parcel.readString8();
+using android::media::IResourceManagerService;
+//static
+const ::std::string& MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs() {
+    return IResourceManagerService::kPolicySupportsMultipleSecureCodecs();
+}
+//static
+const ::std::string& MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec() {
+    return IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec();
 }
 
-void MediaResourcePolicy::writeToParcel(Parcel *parcel) const {
-    parcel->writeString8(mType);
-    parcel->writeString8(mValue);
+MediaResourcePolicy::MediaResourcePolicy(
+        const std::string& type, const std::string& value) {
+    this->type = type;
+    this->value = value;
 }
 
-String8 MediaResourcePolicy::toString() const {
+String8 toString(const MediaResourcePolicyParcel &policy) {
     String8 str;
-    str.appendFormat("%s:%s", mType.string(), mValue.string());
+    str.appendFormat("%s:%s", policy.type.c_str(), policy.value.c_str());
     return str;
 }
 
diff --git a/media/libmedia/aidl/android/media/IResourceManagerClient.aidl b/media/libmedia/aidl/android/media/IResourceManagerClient.aidl
new file mode 100644
index 0000000..4c3ef47
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IResourceManagerClient.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * IResourceManagerClient interface for the ResourceManagerService to
+ * call the client.
+ *
+ * {@hide}
+ */
+interface IResourceManagerClient {
+    /**
+     * Instruct the client to reclaim its resources.
+     *
+     * @return true if the reclaim was successful and false otherwise.
+     */
+    boolean reclaimResource();
+
+    /**
+     * Retrieve the name of the client.
+     *
+     * @return name of the client.
+     */
+    @utf8InCpp String getName();
+}
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
new file mode 100644
index 0000000..3e6f8db
--- /dev/null
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -0,0 +1,87 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.IResourceManagerClient;
+import android.media.MediaResourceParcel;
+import android.media.MediaResourcePolicyParcel;
+
+/**
+ * ResourceManagerService interface that keeps track of media resource
+ * owned by clients, and reclaims resources based on configured policies
+ * when necessary.
+ *
+ * {@hide}
+ */
+interface IResourceManagerService {
+    const @utf8InCpp String kPolicySupportsMultipleSecureCodecs
+            = "supports-multiple-secure-codecs";
+    const @utf8InCpp String kPolicySupportsSecureWithNonSecureCodec
+            = "supports-secure-with-non-secure-codec";
+
+    /**
+     * Configure the ResourceManagerService to adopted particular policies when
+     * managing the resources.
+     *
+     * @param policies an array of policies to be adopted.
+     */
+    void config(in MediaResourcePolicyParcel[] policies);
+
+    /**
+     * Add a client to a process with a list of resources.
+     *
+     * @param pid pid of the client.
+     * @param uid uid of the client.
+     * @param clientId an identifier that uniquely identifies the client within the pid.
+     * @param client interface for the ResourceManagerService to call the client.
+     * @param resources an array of resources to be added.
+     */
+    void addResource(
+            int pid,
+            int uid,
+            long clientId,
+            IResourceManagerClient client,
+            in MediaResourceParcel[] resources);
+
+    /**
+     * Remove the listed resources from a client.
+     *
+     * @param pid pid from which the list of resources will be removed.
+     * @param clientId clientId within the pid from which the list of resources will be removed.
+     * @param resources an array of resources to be removed from the client.
+     */
+    void removeResource(int pid, long clientId, in MediaResourceParcel[] resources);
+
+    /**
+     * Remove all resources from a client.
+     *
+     * @param pid pid from which the client's resources will be removed.
+     * @param clientId clientId within the pid that will be removed.
+     */
+    void removeClient(int pid, long clientId);
+
+    /**
+     * Tries to reclaim resource from processes with lower priority than the
+     * calling process according to the requested resources.
+     *
+     * @param callingPid pid of the calling process.
+     * @param resources an array of resources to be reclaimed.
+     *
+     * @return true if the reclaim was successful and false otherwise.
+     */
+    boolean reclaimResource(int callingPid, in MediaResourceParcel[] resources);
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceParcel.aidl b/media/libmedia/aidl/android/media/MediaResourceParcel.aidl
new file mode 100644
index 0000000..b0f2b71
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceParcel.aidl
@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.MediaResourceType;
+import android.media.MediaResourceSubType;
+
+/**
+ * Description of a media resource to be tracked by MediaResourceManager.
+ *
+ * {@hide}
+ */
+parcelable MediaResourceParcel {
+    // TODO: default enum value is not supported yet.
+    // Set default enum value when b/142739329 is fixed.
+
+    /**
+     * Type of the media resource.
+     */
+    MediaResourceType type;// = MediaResourceTypeEnum::kUnspecified;
+
+    /**
+     * Sub-type of the media resource.
+     */
+    MediaResourceSubType subType;// = MediaResourceSubTypeEnum::kUnspecifiedSubType;
+
+    /**
+     * Identifier of the media resource (eg. Drm session id).
+     */
+    byte[] id;
+
+    /**
+     * Number of units of the media resource (bytes of graphic memory, number of codecs, etc.).
+     */
+    long value = 0;
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl b/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl
new file mode 100644
index 0000000..4ea859a
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourcePolicyParcel.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Description of a policy to be adopted by ResourceManagerService.
+ * {@hide}
+ */
+parcelable MediaResourcePolicyParcel {
+    /**
+     * Name of the policy to be adopted.
+     */
+    @utf8InCpp String type;
+
+    /**
+     * Value of the policy to be adopted.
+     */
+    @utf8InCpp String value;
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceSubType.aidl b/media/libmedia/aidl/android/media/MediaResourceSubType.aidl
new file mode 100644
index 0000000..af2ba68
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceSubType.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Sub-type enums of media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaResourceSubType {
+    kUnspecifiedSubType = 0,
+    kAudioCodec = 1,
+    kVideoCodec = 2,
+}
diff --git a/media/libmedia/aidl/android/media/MediaResourceType.aidl b/media/libmedia/aidl/android/media/MediaResourceType.aidl
new file mode 100644
index 0000000..b2bb71b
--- /dev/null
+++ b/media/libmedia/aidl/android/media/MediaResourceType.aidl
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Type enums of media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaResourceType {
+    kUnspecified = 0,
+    kSecureCodec = 1,
+    kNonSecureCodec = 2,
+    kGraphicMemory = 3,
+    kCpuBoost = 4,
+    kBattery = 5,
+    kDrmSession = 6,
+}
diff --git a/media/libmedia/aidl_api/resourcemanager_aidl_interface/.hash b/media/libmedia/aidl_api/resourcemanager_aidl_interface/.hash
new file mode 100644
index 0000000..e56d56b
--- /dev/null
+++ b/media/libmedia/aidl_api/resourcemanager_aidl_interface/.hash
@@ -0,0 +1,18 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+58fe4b26909c9c4f17b1803baa4005c10ee40750  -
diff --git a/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/IResourceManagerClient.aidl b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/IResourceManagerClient.aidl
new file mode 100644
index 0000000..20bfe72
--- /dev/null
+++ b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/IResourceManagerClient.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+interface IResourceManagerClient {
+  boolean reclaimResource();
+  @utf8InCpp String getName();
+}
diff --git a/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/IResourceManagerService.aidl b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/IResourceManagerService.aidl
new file mode 100644
index 0000000..53cf036
--- /dev/null
+++ b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/IResourceManagerService.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+interface IResourceManagerService {
+  void config(in android.media.MediaResourcePolicyParcel[] policies);
+  void addResource(int pid, int uid, long clientId, android.media.IResourceManagerClient client, in android.media.MediaResourceParcel[] resources);
+  void removeResource(int pid, long clientId, in android.media.MediaResourceParcel[] resources);
+  void removeClient(int pid, long clientId);
+  boolean reclaimResource(int pid, in android.media.MediaResourceParcel[] resources);
+  const String kPolicySupportsMultipleSecureCodecs = "supports-multiple-secure-codecs";
+  const String kPolicySupportsSecureWithNonSecureCodec = "supports-secure-with-non-secure-codec";
+}
diff --git a/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceParcel.aidl b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceParcel.aidl
new file mode 100644
index 0000000..47ea9bc
--- /dev/null
+++ b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+parcelable MediaResourceParcel {
+  android.media.MediaResourceType type;
+  android.media.MediaResourceSubType subType;
+  byte[] id;
+  long value = 0;
+}
diff --git a/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourcePolicyParcel.aidl b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourcePolicyParcel.aidl
new file mode 100644
index 0000000..85d2588
--- /dev/null
+++ b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourcePolicyParcel.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+parcelable MediaResourcePolicyParcel {
+  @utf8InCpp String type;
+  @utf8InCpp String value;
+}
diff --git a/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceSubType.aidl b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceSubType.aidl
new file mode 100644
index 0000000..19b68af
--- /dev/null
+++ b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceSubType.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+@Backing(type="int")
+enum MediaResourceSubType {
+  kUnspecifiedSubType = 0,
+  kAudioCodec = 1,
+  kVideoCodec = 2,
+}
diff --git a/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceType.aidl b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceType.aidl
new file mode 100644
index 0000000..6a123fc
--- /dev/null
+++ b/media/libmedia/aidl_api/resourcemanager_aidl_interface/1/android/media/MediaResourceType.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a frozen snapshot of an AIDL interface (or parcelable). Do not
+// try to edit this file. It looks like you are doing that because you have
+// modified an AIDL interface in a backward-incompatible way, e.g., deleting a
+// function from an interface or a field from a parcelable and it broke the
+// build. That breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.media;
+@Backing(type="int")
+enum MediaResourceType {
+  kUnspecified = 0,
+  kSecureCodec = 1,
+  kNonSecureCodec = 2,
+  kGraphicMemory = 3,
+  kCpuBoost = 4,
+  kBattery = 5,
+  kDrmSession = 6,
+}
diff --git a/media/libmedia/include/media/IMediaMetadataRetriever.h b/media/libmedia/include/media/IMediaMetadataRetriever.h
index c6f422d..28d2192 100644
--- a/media/libmedia/include/media/IMediaMetadataRetriever.h
+++ b/media/libmedia/include/media/IMediaMetadataRetriever.h
@@ -48,9 +48,8 @@
             int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
     virtual sp<IMemory>     getImageRectAtIndex(
             int index, int colorFormat, int left, int top, int right, int bottom) = 0;
-    virtual status_t        getFrameAtIndex(
-            std::vector<sp<IMemory> > *frames,
-            int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
+    virtual sp<IMemory>     getFrameAtIndex(
+            int index, int colorFormat, bool metaOnly) = 0;
     virtual sp<IMemory>     extractAlbumArt() = 0;
     virtual const char*     extractMetadata(int keyCode) = 0;
 };
diff --git a/media/libmedia/include/media/IOMX.h b/media/libmedia/include/media/IOMX.h
index 7e7c2d2..70c8a74 100644
--- a/media/libmedia/include/media/IOMX.h
+++ b/media/libmedia/include/media/IOMX.h
@@ -34,9 +34,17 @@
 #include <media/openmax/OMX_VideoExt.h>
 
 namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+struct IGraphicBufferSource;
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
 
 class IGraphicBufferProducer;
-class IGraphicBufferSource;
 class IMemory;
 class IOMXBufferSource;
 class IOMXNode;
@@ -82,7 +90,7 @@
 
     virtual status_t createInputSurface(
             sp<IGraphicBufferProducer> *bufferProducer,
-            sp<IGraphicBufferSource> *bufferSource) = 0;
+            sp<hardware::media::omx::V1_0::IGraphicBufferSource> *bufferSource) = 0;
 };
 
 class IOMXNode : public IInterface {
diff --git a/media/libmedia/include/media/IResourceManagerClient.h b/media/libmedia/include/media/IResourceManagerClient.h
deleted file mode 100644
index aa0cd88..0000000
--- a/media/libmedia/include/media/IResourceManagerClient.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IRESOURCEMANAGERCLIENT_H
-#define ANDROID_IRESOURCEMANAGERCLIENT_H
-
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class IResourceManagerClient: public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(ResourceManagerClient);
-
-    virtual bool reclaimResource() = 0;
-    virtual String8 getName() = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnResourceManagerClient: public BnInterface<IResourceManagerClient>
-{
-public:
-    virtual status_t onTransact(uint32_t code,
-                                const Parcel &data,
-                                Parcel *reply,
-                                uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IRESOURCEMANAGERCLIENT_H
diff --git a/media/libmedia/include/media/IResourceManagerService.h b/media/libmedia/include/media/IResourceManagerService.h
deleted file mode 100644
index 8992f8b..0000000
--- a/media/libmedia/include/media/IResourceManagerService.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_IRESOURCEMANAGERSERVICE_H
-#define ANDROID_IRESOURCEMANAGERSERVICE_H
-
-#include <utils/Errors.h>  // for status_t
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <utils/String8.h>
-#include <binder/IInterface.h>
-#include <binder/Parcel.h>
-
-#include <media/IResourceManagerClient.h>
-#include <media/MediaResource.h>
-#include <media/MediaResourcePolicy.h>
-
-namespace android {
-
-class IResourceManagerService: public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(ResourceManagerService);
-
-    virtual void config(const Vector<MediaResourcePolicy> &policies) = 0;
-
-    virtual void addResource(
-            int pid,
-            int uid,
-            int64_t clientId,
-            const sp<IResourceManagerClient> client,
-            const Vector<MediaResource> &resources) = 0;
-
-    virtual void removeResource(int pid, int64_t clientId,
-            const Vector<MediaResource> &resources) = 0;
-
-    virtual void removeClient(int pid, int64_t clientId) = 0;
-
-    virtual bool reclaimResource(
-            int callingPid,
-            const Vector<MediaResource> &resources) = 0;
-};
-
-// ----------------------------------------------------------------------------
-
-class BnResourceManagerService: public BnInterface<IResourceManagerService>
-{
-public:
-    virtual status_t onTransact(uint32_t code,
-                                const Parcel &data,
-                                Parcel *reply,
-                                uint32_t flags = 0);
-};
-
-}; // namespace android
-
-#endif // ANDROID_IRESOURCEMANAGERSERVICE_H
diff --git a/media/libmedia/include/media/LinearMap.h b/media/libmedia/include/media/LinearMap.h
deleted file mode 100644
index 2220a0c..0000000
--- a/media/libmedia/include/media/LinearMap.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_LINEAR_MAP_H
-#define ANDROID_LINEAR_MAP_H
-
-#include <stdint.h>
-
-namespace android {
-
-/*
-A general purpose lookup utility that defines a mapping between X and Y as a
-continuous set of line segments with shared (x, y) end-points.
-The (x, y) points must be added in order, monotonically increasing in both x and y;
-a log warning is emitted if this does not happen (See general usage notes below).
-
-A limited history of (x, y) points is kept for space reasons (See general usage notes).
-
-In AudioFlinger, we use the LinearMap to associate track frames to
-sink frames.  When we want to obtain a client track timestamp, we first
-get a timestamp from the sink.  The sink timestamp's position (mPosition)
-corresponds to the sink frames written. We use LinearMap to figure out which track frame
-the sink frame corresponds to. This allows us to substitute a track frame for the
-the sink frame (keeping the mTime identical) and return that timestamp back to the client.
-
-The method findX() can be used to retrieve an x value from a given y value and is
-used for timestamps, similarly for findY() which is provided for completeness.
-
-We update the (track frame, sink frame) points in the LinearMap each time we write data
-to the sink by the AudioFlinger PlaybackThread (MixerThread).
-
-
-AudioFlinger Timestamp Notes:
-
-1) Example: Obtaining a track timestamp during playback.  In this case, the LinearMap
-looks something like this:
-
-Track Frame    Sink Frame
-(track start)
-0              50000  (track starts here, the sink may already be running)
-1000           51000
-2000           52000
-
-When we request a track timestamp, we call the sink getTimestamp() and get for example
-mPosition = 51020.  Using the LinearMap, we find we have played to track frame 1020.
-We substitute the sink mPosition of 51020 with the track position 1020,
-and return that timestamp to the app.
-
-2) Example: Obtaining a track timestamp duing pause. In this case, the LinearMap
-looks something like this:
-
-Track Frame    Sink Frame
-... (some time has gone by)
-15000          30000
-16000          31000
-17000          32000
-(pause here)
-(suppose we call sink getTimestamp() here and get sink mPosition = 31100; that means
-        we have played to track frame 16100.  The track timestamp mPosition will
-        continue to advance until the sink timestamp returns a value of mPosition
-        greater than 32000, corresponding to track frame 17000 when the pause was called).
-17000          33000
-17000          34000
-...
-
-3) If the track underruns, it appears as if a pause was called on that track.
-
-4) If there is an underrun in the HAL layer, then it may be possible that
-the sink getTimestamp() will return a value greater than the number of frames written
-(it should always be less). This should be rare, if not impossible by some
-HAL implementations of the sink getTimestamp. In that case, timing is lost
-and we will return the most recent track frame written.
-
-5) When called with no points in the map, findX() returns the start value (default 0).
-This is consistent with starting after a stop() or flush().
-
-6) Resuming after Track standby will be similar to coming out of pause, as the HAL ensures
-framesWritten() and getTimestamp() are contiguous for non-offloaded/direct tracks.
-
-7) LinearMap works for different speeds and sample rates as it uses
-linear interpolation. Since AudioFlinger only updates speed and sample rate
-exactly at the sample points pushed into the LinearMap, the returned values
-from findX() and findY() are accurate regardless of how many speed or sample
-rate changes are made, so long as the coordinate looked up is within the
-sample history.
-
-General usage notes:
-
-1) In order for the LinearMap to work reliably, you cannot look backwards more
-than the size of its circular buffer history, set upon creation (typically 16).
-If you look back further, the position is extrapolated either from a passed in
-extrapolation parameter or from the oldest line segment.
-
-2) Points must monotonically increase in x and y. The increment between adjacent
-points cannot be greater than signed 32 bits. Wrap in the x, y coordinates are supported,
-since we use differences in our computation.
-
-3) If the frame data is discontinuous (due to stop or flush) call reset() to clear
-the sample counter.
-
-4) If (x, y) are not strictly monotonic increasing, i.e. (x2 > x1) and (y2 > y1),
-then one or both of the inverses y = f(x) or x = g(y) may have multiple solutions.
-In that case, the most recent solution is returned by findX() or findY().  We
-do not warn if (x2 == x1) or (y2 == y1), but we do logcat warn if (x2 < x1) or
-(y2 < y1).
-
-5) Due to rounding it is possible x != findX(findY(x)) or y != findY(findX(y))
-even when the inverse exists. Nevertheless, the values should be close.
-
-*/
-
-template <typename T>
-class LinearMap {
-public:
-    // This enumeration describes the reliability of the findX() or findY() estimation
-    // in descending order.
-    enum FindMethod {
-        FIND_METHOD_INTERPOLATION,           // High reliability (errors due to rounding)
-        FIND_METHOD_FORWARD_EXTRAPOLATION,   // Reliability based on no future speed changes
-        FIND_METHOD_BACKWARD_EXTRAPOLATION,  // Reliability based on prior estimated speed
-        FIND_METHOD_START_VALUE,             // No samples in history, using start value
-    };
-
-    explicit LinearMap(size_t size)
-            : mSize(size),
-              mPos(0), // a circular buffer, so could start anywhere. the first sample is at 1.
-              mSamples(0),
-              // mStepValid(false),      // only valid if mSamples > 1
-              // mExtrapolateTail(false), // only valid if mSamples > 0
-              mX(new T[size]),
-              mY(new T[size]) { }
-
-    ~LinearMap() {
-        delete[] mX;
-        delete[] mY;
-    }
-
-    // Add a new sample point to the linear map.
-    //
-    // The difference between the new sample and the previous sample
-    // in the x or y coordinate must be less than INT32_MAX for purposes
-    // of the linear interpolation or extrapolation.
-    //
-    // The value should be monotonic increasing (e.g. diff >= 0);
-    // logcat warnings are issued if they are not.
-    __attribute__((no_sanitize("integer")))
-    void push(T x, T y) {
-        // Assumption: we assume x, y are monotonic increasing values,
-        // which (can) wrap in precision no less than 32 bits and have
-        // "step" or differences between adjacent points less than 32 bits.
-
-        if (mSamples > 0) {
-            const bool lastStepValid = mStepValid;
-            int32_t xdiff;
-            int32_t ydiff;
-            // check difference assumption here
-            mStepValid = checkedDiff(&xdiff, x, mX[mPos], "x")
-                    & /* bitwise AND to always warn for ydiff, though logical AND is also OK */
-                    checkedDiff(&ydiff, y, mY[mPos], "y");
-
-            // Optimization: do not add a new sample if the line segment would
-            // simply extend the previous line segment.  This extends the useful
-            // history by removing redundant points.
-            if (mSamples > 1 && mStepValid && lastStepValid) {
-                const size_t prev = previousPosition();
-                const int32_t xdiff2 = x - mX[prev];
-                const int32_t ydiff2 = y - mY[prev];
-
-                // if both current step and previous step are valid (non-negative and
-                // less than INT32_MAX for precision greater than 4 bytes)
-                // then the sum of the two steps is valid when the
-                // int32_t difference is non-negative.
-                if (xdiff2 >= 0 && ydiff2 >= 0
-                        && (int64_t)xdiff2 * ydiff == (int64_t)ydiff2 * xdiff) {
-                    // ALOGD("reusing sample! (%u, %u) sample depth %zd", x, y, mSamples);
-                    mX[mPos] = x;
-                    mY[mPos] = y;
-                    return;
-                }
-            }
-        }
-        if (++mPos >= mSize) {
-            mPos = 0;
-        }
-        if (mSamples < mSize) {
-            mExtrapolateTail = false;
-            ++mSamples;
-        } else {
-            // we enable extrapolation beyond the oldest sample
-            // if the sample buffers are completely full and we
-            // no longer know the full history.
-            mExtrapolateTail = true;
-        }
-        mX[mPos] = x;
-        mY[mPos] = y;
-    }
-
-    // clear all samples from the circular array
-    void reset() {
-        // no need to reset mPos, we use a circular buffer.
-        // computed values such as mStepValid are set after a subsequent push().
-        mSamples = 0;
-    }
-
-    // returns true if LinearMap contains at least one sample.
-    bool hasData() const {
-        return mSamples != 0;
-    }
-
-    // find the corresponding X point from a Y point.
-    // See findU for details.
-    __attribute__((no_sanitize("integer")))
-    T findX(T y, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
-        return findU(y, mX, mY, method, extrapolation, startValue);
-    }
-
-    // find the corresponding Y point from a X point.
-    // See findU for details.
-    __attribute__((no_sanitize("integer")))
-    T findY(T x, FindMethod *method = NULL, double extrapolation = 0.0, T startValue = 0) const {
-        return findU(x, mY, mX, method, extrapolation, startValue);
-    }
-
-protected:
-
-    // returns false if the diff is out of int32_t bounds or negative.
-    __attribute__((no_sanitize("integer")))
-    static inline bool checkedDiff(int32_t *diff, T x2, T x1, const char *coord) {
-        if (sizeof(T) >= 8) {
-            const int64_t diff64 = x2 - x1;
-            *diff = (int32_t)diff64;  // intentionally lose precision
-            if (diff64 > INT32_MAX) {
-                ALOGW("LinearMap: %s overflow diff(%lld) from %llu - %llu exceeds INT32_MAX",
-                        coord, (long long)diff64,
-                        (unsigned long long)x2, (unsigned long long)x1);
-                return false;
-            } else if (diff64 < 0) {
-                ALOGW("LinearMap: %s negative diff(%lld) from %llu - %llu",
-                        coord, (long long)diff64,
-                        (unsigned long long)x2, (unsigned long long)x1);
-                return false;
-            }
-            return true;
-        }
-        // for 32 bit integers we cannot detect overflow (it
-        // shows up as a negative difference).
-        *diff = x2 - x1;
-        if (*diff < 0) {
-            ALOGW("LinearMap: %s negative diff(%d) from %u - %u",
-                    coord, *diff, (unsigned)x2, (unsigned)x1);
-            return false;
-        }
-        return true;
-    }
-
-    // Returns the previous position in the mSamples array
-    // going backwards back steps.
-    //
-    // Parameters:
-    //   back: number of backward steps, cannot be less than zero or greater than mSamples.
-    //
-    __attribute__((no_sanitize("integer")))
-    size_t previousPosition(ssize_t back = 1) const {
-        LOG_ALWAYS_FATAL_IF(back < 0 || (size_t)back > mSamples, "Invalid back(%zd)", back);
-        ssize_t position = mPos - back;
-        if (position < 0) position += mSize;
-        return (size_t)position;
-    }
-
-    // A generic implementation of finding the "other coordinate" with coordinates
-    // (u, v) = (x, y) or (u, v) = (y, x).
-    //
-    // Parameters:
-    //   uArray: the u axis samples.
-    //   vArray: the v axis samples.
-    //   method: [out] how the returned value was computed.
-    //   extrapolation: the slope used when extrapolating from the
-    //     first sample value or the last sample value in the history.
-    //     If mExtrapolateTail is set, the slope of the last line segment
-    //     is used if the extrapolation parameter is zero to continue the tail of history.
-    //     At this time, we do not use a different value for forward extrapolation from the
-    //     head of history from backward extrapolation from the tail of history.
-    //     TODO: back extrapolation value could be stored along with mX, mY in history.
-    //   startValue: used only when there are no samples in history. One can detect
-    //     whether there are samples in history by the method hasData().
-    //
-    __attribute__((no_sanitize("integer")))
-    T findU(T v, T *uArray, T *vArray, FindMethod *method,
-            double extrapolation, T startValue) const {
-        if (mSamples == 0) {
-            if (method != NULL) {
-                *method = FIND_METHOD_START_VALUE;
-            }
-            return startValue;  // nothing yet
-        }
-        ssize_t previous = 0;
-        int32_t diff = 0;
-        for (ssize_t i = 0; i < (ssize_t)mSamples; ++i) {
-            size_t current = previousPosition(i);
-
-            // Assumption: even though the type "T" may have precision greater
-            // than 32 bits, the difference between adjacent points is limited to 32 bits.
-            diff = v - vArray[current];
-            if (diff >= 0 ||
-                    (i == (ssize_t)mSamples - 1 && mExtrapolateTail && extrapolation == 0.0)) {
-                // ALOGD("depth = %zd out of %zd", i, limit);
-                if (i == 0) {
-                    if (method != NULL) {
-                        *method = FIND_METHOD_FORWARD_EXTRAPOLATION;
-                    }
-                    return uArray[current] + diff * extrapolation;
-                }
-                // interpolate / extrapolate: For this computation, we
-                // must use differentials here otherwise we have inconsistent
-                // values on modulo wrap. previous is always valid here since
-                // i > 0.  we also perform rounding with the assumption
-                // that uStep, vStep, and diff are non-negative.
-                int32_t uStep = uArray[previous] - uArray[current]; // non-negative
-                int32_t vStep = vArray[previous] - vArray[current]; // positive
-                T u = uStep <= 0 || vStep <= 0 ?  // we do not permit negative ustep or vstep
-                        uArray[current]
-                      : ((int64_t)diff * uStep + (vStep >> 1)) / vStep + uArray[current];
-                // ALOGD("u:%u  diff:%d  uStep:%d  vStep:%d  u_current:%d",
-                //         u, diff, uStep, vStep, uArray[current]);
-                if (method != NULL) {
-                    *method = (diff >= 0) ?
-                            FIND_METHOD_INTERPOLATION : FIND_METHOD_BACKWARD_EXTRAPOLATION;
-                }
-                return u;
-            }
-            previous = current;
-        }
-        // previous is always valid here.
-        if (method != NULL) {
-            *method = FIND_METHOD_BACKWARD_EXTRAPOLATION;
-        }
-        return uArray[previous] + diff * extrapolation;
-    }
-
-private:
-    const size_t    mSize;      // Size of mX and mY arrays (history).
-    size_t          mPos;       // Index in mX and mY of last pushed data;
-                                // (incremented after push) [0, mSize - 1].
-    size_t          mSamples;   // Number of valid samples in the array [0, mSize].
-    bool            mStepValid; // Last sample step was valid (non-negative)
-    bool            mExtrapolateTail; // extrapolate tail using oldest line segment
-    T * const       mX;         // History of X values as a circular array.
-    T * const       mY;         // History of Y values as a circular array.
-};
-
-} // namespace android
-
-#endif // ANDROID_LINEAR_MAP_H
diff --git a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
index 98d300f..37dc401 100644
--- a/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
+++ b/media/libmedia/include/media/MediaMetadataRetrieverInterface.h
@@ -49,9 +49,8 @@
             int index, int colorFormat, bool metaOnly, bool thumbnail) = 0;
     virtual sp<IMemory> getImageRectAtIndex(
             int index, int colorFormat, int left, int top, int right, int bottom) = 0;
-    virtual status_t getFrameAtIndex(
-            std::vector<sp<IMemory> >* frames,
-            int frameIndex, int numFrames, int colorFormat, bool metaOnly) = 0;
+    virtual sp<IMemory> getFrameAtIndex(
+            int frameIndex, int colorFormat, bool metaOnly) = 0;
     virtual MediaAlbumArt* extractAlbumArt() = 0;
     virtual const char* extractMetadata(int keyCode) = 0;
 };
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 10a07bb..caf03b1 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -18,66 +18,55 @@
 #ifndef ANDROID_MEDIA_RESOURCE_H
 #define ANDROID_MEDIA_RESOURCE_H
 
-#include <binder/Parcel.h>
-#include <utils/String8.h>
+#include <android/media/MediaResourceParcel.h>
 
 namespace android {
 
-class MediaResource {
+using android::media::MediaResourceParcel;
+using android::media::MediaResourceSubType;
+using android::media::MediaResourceType;
+
+class MediaResource : public MediaResourceParcel {
 public:
-    enum Type {
-        kUnspecified = 0,
-        kSecureCodec,
-        kNonSecureCodec,
-        kGraphicMemory,
-        kCpuBoost,
-        kBattery,
-    };
+    using Type = MediaResourceType;
+    using SubType = MediaResourceSubType;
 
-    enum SubType {
-        kUnspecifiedSubType = 0,
-        kAudioCodec,
-        kVideoCodec,
-    };
+    MediaResource() = delete;
+    MediaResource(Type type, int64_t value);
+    MediaResource(Type type, SubType subType, int64_t value);
+    MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
 
-    MediaResource();
-    MediaResource(Type type, uint64_t value);
-    MediaResource(Type type, SubType subType, uint64_t value);
-
-    void readFromParcel(const Parcel &parcel);
-    void writeToParcel(Parcel *parcel) const;
-
-    String8 toString() const;
-
-    bool operator==(const MediaResource &other) const;
-    bool operator!=(const MediaResource &other) const;
-
-    Type mType;
-    SubType mSubType;
-    uint64_t mValue;
+    static MediaResource CodecResource(bool secure, bool video);
+    static MediaResource GraphicMemoryResource(int64_t value);
+    static MediaResource CpuBoostResource();
+    static MediaResource VideoBatteryResource();
+    static MediaResource DrmSessionResource(const std::vector<uint8_t> &id, int64_t value);
 };
 
 inline static const char *asString(MediaResource::Type i, const char *def = "??") {
     switch (i) {
-        case MediaResource::kUnspecified:    return "unspecified";
-        case MediaResource::kSecureCodec:    return "secure-codec";
-        case MediaResource::kNonSecureCodec: return "non-secure-codec";
-        case MediaResource::kGraphicMemory:  return "graphic-memory";
-        case MediaResource::kCpuBoost:       return "cpu-boost";
-        case MediaResource::kBattery:        return "battery";
-        default:                             return def;
+        case MediaResource::Type::kUnspecified:    return "unspecified";
+        case MediaResource::Type::kSecureCodec:    return "secure-codec";
+        case MediaResource::Type::kNonSecureCodec: return "non-secure-codec";
+        case MediaResource::Type::kGraphicMemory:  return "graphic-memory";
+        case MediaResource::Type::kCpuBoost:       return "cpu-boost";
+        case MediaResource::Type::kBattery:        return "battery";
+        case MediaResource::Type::kDrmSession:     return "drm-session";
+        default:                                   return def;
     }
 }
 
 inline static const char *asString(MediaResource::SubType i, const char *def = "??") {
     switch (i) {
-        case MediaResource::kUnspecifiedSubType: return "unspecified";
-        case MediaResource::kAudioCodec:         return "audio-codec";
-        case MediaResource::kVideoCodec:         return "video-codec";
+        case MediaResource::SubType::kUnspecifiedSubType: return "unspecified";
+        case MediaResource::SubType::kAudioCodec:         return "audio-codec";
+        case MediaResource::SubType::kVideoCodec:         return "video-codec";
         default:                                 return def;
     }
 }
 
+String8 toString(const MediaResourceParcel& resource);
+
 }; // namespace android
 
 #endif  // ANDROID_MEDIA_RESOURCE_H
diff --git a/media/libmedia/include/media/MediaResourcePolicy.h b/media/libmedia/include/media/MediaResourcePolicy.h
index 9bc2eec..7ae1a73 100644
--- a/media/libmedia/include/media/MediaResourcePolicy.h
+++ b/media/libmedia/include/media/MediaResourcePolicy.h
@@ -18,28 +18,23 @@
 #ifndef ANDROID_MEDIA_RESOURCE_POLICY_H
 #define ANDROID_MEDIA_RESOURCE_POLICY_H
 
-#include <binder/Parcel.h>
-#include <utils/String8.h>
+#include <android/media/MediaResourcePolicyParcel.h>
 
 namespace android {
 
-extern const char kPolicySupportsMultipleSecureCodecs[];
-extern const char kPolicySupportsSecureWithNonSecureCodec[];
+using media::MediaResourcePolicyParcel;
 
-class MediaResourcePolicy {
+class MediaResourcePolicy : public MediaResourcePolicyParcel {
 public:
-    MediaResourcePolicy();
-    MediaResourcePolicy(String8 type, String8 value);
+    MediaResourcePolicy() = delete;
+    MediaResourcePolicy(const std::string& type, const std::string& value);
 
-    void readFromParcel(const Parcel &parcel);
-    void writeToParcel(Parcel *parcel) const;
-
-    String8 toString() const;
-
-    String8 mType;
-    String8 mValue;
+    static const ::std::string& kPolicySupportsMultipleSecureCodecs();
+    static const ::std::string& kPolicySupportsSecureWithNonSecureCodec();
 };
 
+String8 toString(const MediaResourcePolicyParcel &policy);
+
 }; // namespace android
 
 #endif  // ANDROID_MEDIA_RESOURCE_POLICY_H
diff --git a/media/libmedia/include/media/PluginMetricsReporting.h b/media/libmedia/include/media/PluginMetricsReporting.h
index e00bd43..f71c52d 100644
--- a/media/libmedia/include/media/PluginMetricsReporting.h
+++ b/media/libmedia/include/media/PluginMetricsReporting.h
@@ -18,6 +18,7 @@
 
 #define PLUGIN_METRICS_REPORTING_H_
 
+#include <sys/types.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 
@@ -26,7 +27,7 @@
 status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
                                 const String8& vendorName,
                                 const String8& description,
-                                const String8& appPackageName);
+                                uid_t appUid);
 
 }  // namespace android
 
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index d29e97d..138a014 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -98,9 +98,8 @@
             int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false, bool thumbnail = false);
     sp<IMemory> getImageRectAtIndex(
             int index, int colorFormat, int left, int top, int right, int bottom);
-    status_t getFrameAtIndex(
-            std::vector<sp<IMemory> > *frames, int frameIndex, int numFrames = 1,
-            int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
+    sp<IMemory>  getFrameAtIndex(
+            int index, int colorFormat = HAL_PIXEL_FORMAT_RGB_565, bool metaOnly = false);
     sp<IMemory> extractAlbumArt();
     const char* extractMetadata(int keyCode);
 
diff --git a/media/libmedia/include/media/omx/1.0/Conversion.h b/media/libmedia/include/media/omx/1.0/Conversion.h
index 6dc46b7..811936b 100644
--- a/media/libmedia/include/media/omx/1.0/Conversion.h
+++ b/media/libmedia/include/media/omx/1.0/Conversion.h
@@ -45,7 +45,6 @@
 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
-#include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
 
 namespace android {
diff --git a/media/libmedia/include/media/omx/1.0/WOmx.h b/media/libmedia/include/media/omx/1.0/WOmx.h
index 0680eec..46ada9b 100644
--- a/media/libmedia/include/media/omx/1.0/WOmx.h
+++ b/media/libmedia/include/media/omx/1.0/WOmx.h
@@ -67,7 +67,7 @@
             sp<IOMXNode>* omxNode) override;
     status_t createInputSurface(
             sp<::android::IGraphicBufferProducer>* bufferProducer,
-            sp<::android::IGraphicBufferSource>* bufferSource) override;
+            sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource>* bufferSource) override;
 };
 
 }  // namespace utils
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index e61b04d..2ae76b3 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -179,18 +179,16 @@
             index, colorFormat, left, top, right, bottom);
 }
 
-status_t MediaMetadataRetriever::getFrameAtIndex(
-        std::vector<sp<IMemory> > *frames,
-        int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
-    ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d) metaOnly(%d)",
-            frameIndex, numFrames, colorFormat, metaOnly);
+sp<IMemory>  MediaMetadataRetriever::getFrameAtIndex(
+        int index, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
+            index, colorFormat, metaOnly);
     Mutex::Autolock _l(mLock);
     if (mRetriever == 0) {
         ALOGE("retriever is not initialized");
-        return INVALID_OPERATION;
+        return NULL;
     }
-    return mRetriever->getFrameAtIndex(
-            frames, frameIndex, numFrames, colorFormat, metaOnly);
+    return mRetriever->getFrameAtIndex(index, colorFormat, metaOnly);
 }
 
 const char* MediaMetadataRetriever::extractMetadata(int keyCode)
diff --git a/media/libmedia/omx/1.0/WOmx.cpp b/media/libmedia/omx/1.0/WOmx.cpp
index ce624fa..4bacdda 100644
--- a/media/libmedia/omx/1.0/WOmx.cpp
+++ b/media/libmedia/omx/1.0/WOmx.cpp
@@ -18,7 +18,6 @@
 #include <media/omx/1.0/WOmx.h>
 #include <media/omx/1.0/WOmxNode.h>
 #include <media/omx/1.0/WOmxObserver.h>
-#include <media/omx/1.0/WGraphicBufferSource.h>
 #include <media/omx/1.0/Conversion.h>
 
 namespace android {
@@ -70,7 +69,7 @@
 
 status_t LWOmx::createInputSurface(
         sp<::android::IGraphicBufferProducer>* bufferProducer,
-        sp<::android::IGraphicBufferSource>* bufferSource) {
+        sp<::android::hardware::media::omx::V1_0::IGraphicBufferSource>* bufferSource) {
     status_t fnStatus;
     status_t transStatus = toStatusT(mBase->createInputSurface(
             [&fnStatus, bufferProducer, bufferSource] (
@@ -79,7 +78,7 @@
                     sp<IGraphicBufferSource> const& tSource) {
                 fnStatus = toStatusT(status);
                 *bufferProducer = new H2BGraphicBufferProducer(tProducer);
-                *bufferSource = new LWGraphicBufferSource(tSource);
+                *bufferSource = tSource;
             }));
     return transStatus == NO_ERROR ? fnStatus : transStatus;
 }
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
new file mode 100644
index 0000000..72edeec
--- /dev/null
+++ b/media/libmediahelper/Android.bp
@@ -0,0 +1,29 @@
+cc_library_headers {
+    name: "libmedia_helper_headers",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
+
+cc_library {
+    name: "libmedia_helper",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    double_loadable: true,
+    srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
+    cflags: [
+        "-Werror",
+        "-Wextra",
+        "-Wall",
+    ],
+    shared_libs: ["libutils", "liblog"],
+    header_libs: [
+        "libmedia_helper_headers",
+        "libaudio_system_headers",
+    ],
+    export_header_lib_headers: [
+        "libmedia_helper_headers",
+    ],
+    clang: true,
+}
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmediahelper/AudioParameter.cpp
similarity index 100%
rename from media/libmedia/AudioParameter.cpp
rename to media/libmediahelper/AudioParameter.cpp
diff --git a/media/libmedia/TypeConverter.cpp b/media/libmediahelper/TypeConverter.cpp
similarity index 99%
rename from media/libmedia/TypeConverter.cpp
rename to media/libmediahelper/TypeConverter.cpp
index 5be78d1..817aadf 100644
--- a/media/libmedia/TypeConverter.cpp
+++ b/media/libmediahelper/TypeConverter.cpp
@@ -325,6 +325,7 @@
     MAKE_STRING_FROM_ENUM(AUDIO_MODE_RINGTONE),
     MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_CALL),
     MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_COMMUNICATION),
+    MAKE_STRING_FROM_ENUM(AUDIO_MODE_CALL_SCREEN),
     TERMINATOR
 };
 
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libmediahelper/include/media/AudioParameter.h
similarity index 100%
rename from media/libaudioclient/include/media/AudioParameter.h
rename to media/libmediahelper/include/media/AudioParameter.h
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmediahelper/include/media/TypeConverter.h
similarity index 95%
rename from media/libmedia/include/media/TypeConverter.h
rename to media/libmediahelper/include/media/TypeConverter.h
index 2f8c209..011498a 100644
--- a/media/libmedia/include/media/TypeConverter.h
+++ b/media/libmediahelper/include/media/TypeConverter.h
@@ -17,10 +17,11 @@
 #ifndef ANDROID_TYPE_CONVERTER_H_
 #define ANDROID_TYPE_CONVERTER_H_
 
+#include <set>
 #include <string>
 #include <string.h>
-
 #include <vector>
+
 #include <system/audio.h>
 #include <utils/Log.h>
 #include <utils/Vector.h>
@@ -42,16 +43,6 @@
     }
 };
 template <typename T>
-struct VectorTraits
-{
-    typedef T Type;
-    typedef Vector<Type> Collection;
-    static void add(Collection &collection, Type value)
-    {
-        collection.add(value);
-    }
-};
-template <typename T>
 struct SortedVectorTraits
 {
     typedef T Type;
@@ -61,18 +52,28 @@
         collection.add(value);
     }
 };
+template <typename T>
+struct SetTraits
+{
+    typedef T Type;
+    typedef std::set<Type> Collection;
+    static void add(Collection &collection, Type value)
+    {
+        collection.insert(value);
+    }
+};
 
-using SampleRateTraits = SortedVectorTraits<uint32_t>;
+using SampleRateTraits = SetTraits<uint32_t>;
 using DeviceTraits = DefaultTraits<audio_devices_t>;
 struct OutputDeviceTraits : public DeviceTraits {};
 struct InputDeviceTraits : public DeviceTraits {};
-using ChannelTraits = SortedVectorTraits<audio_channel_mask_t>;
+using ChannelTraits = SetTraits<audio_channel_mask_t>;
 struct OutputChannelTraits : public ChannelTraits {};
 struct InputChannelTraits : public ChannelTraits {};
 struct ChannelIndexTraits : public ChannelTraits {};
 using InputFlagTraits = DefaultTraits<audio_input_flags_t>;
 using OutputFlagTraits = DefaultTraits<audio_output_flags_t>;
-using FormatTraits = VectorTraits<audio_format_t>;
+using FormatTraits = DefaultTraits<audio_format_t>;
 using GainModeTraits = DefaultTraits<audio_gain_mode_t>;
 using StreamTraits = DefaultTraits<audio_stream_type_t>;
 using AudioModeTraits = DefaultTraits<audio_mode_t>;
@@ -259,6 +260,7 @@
                                     || std::is_same<T, audio_source_t>::value
                                     || std::is_same<T, audio_stream_type_t>::value
                                     || std::is_same<T, audio_usage_t>::value
+                                    || std::is_same<T, audio_format_t>::value
                                     , int> = 0>
 static inline std::string toString(const T& value)
 {
@@ -291,14 +293,6 @@
     return result;
 }
 
-// TODO: Remove when FormatTraits uses DefaultTraits.
-static inline std::string toString(const audio_format_t& format)
-{
-    std::string result;
-    return TypeConverter<VectorTraits<audio_format_t>>::toString(format, result)
-            ? result : std::to_string(static_cast<int>(format));
-}
-
 static inline std::string toString(const audio_attributes_t& attributes)
 {
     std::ostringstream result;
diff --git a/media/libmedia/include/media/convert.h b/media/libmediahelper/include/media/convert.h
similarity index 100%
rename from media/libmedia/include/media/convert.h
rename to media/libmediahelper/include/media/convert.h
diff --git a/media/libmediametrics/Android.bp b/media/libmediametrics/Android.bp
index 15ea578..f599190 100644
--- a/media/libmediametrics/Android.bp
+++ b/media/libmediametrics/Android.bp
@@ -37,6 +37,16 @@
             "1" ,
         ]
     },
+
+    header_abi_checker: {
+        enabled: true,
+        symbol_file: "libmediametrics.map.txt",
+    },
+
+    visibility: [
+        "//cts/tests/tests/nativemedia/mediametrics",
+        "//frameworks/av:__subpackages__",
+        "//frameworks/base/core/jni",
+        "//frameworks/base/media/jni",
+    ],
 }
-
-
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
index 9114927..4324f6d 100644
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ b/media/libmediametrics/IMediaAnalyticsService.cpp
@@ -32,15 +32,10 @@
 #include <media/MediaAnalyticsItem.h>
 #include <media/IMediaAnalyticsService.h>
 
-#define DEBUGGING               0
-#define DEBUGGING_FLOW          0
-#define DEBUGGING_RETURNS       0
-
 namespace android {
 
 enum {
-    GENERATE_UNIQUE_SESSIONID = IBinder::FIRST_CALL_TRANSACTION,
-    SUBMIT_ITEM,
+    SUBMIT_ITEM_ONEWAY = IBinder::FIRST_CALL_TRANSACTION,
 };
 
 class BpMediaAnalyticsService: public BpInterface<IMediaAnalyticsService>
@@ -51,61 +46,27 @@
     {
     }
 
-    virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() {
-        Parcel data, reply;
-        status_t err;
-        MediaAnalyticsItem::SessionID_t sessionid =
-                        MediaAnalyticsItem::SessionIDInvalid;
-
-        data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
-        err = remote()->transact(GENERATE_UNIQUE_SESSIONID, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGW("bad response from service for generateSessionId, err=%d", err);
-            return MediaAnalyticsItem::SessionIDInvalid;
-        }
-        sessionid = reply.readInt64();
-        if (DEBUGGING_RETURNS) {
-            ALOGD("the caller gets a sessionid of %" PRId64 " back", sessionid);
-        }
-        return sessionid;
-    }
-
-    virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew)
+    status_t submit(MediaAnalyticsItem *item) override
     {
-        // have this record submit itself
-        // this will be a binder call with appropriate timing
-        // return value is the uuid that the system generated for it.
-        // the return value 0 and -1 are reserved.
-        // -1 to indicate that there was a problem recording...
-
-        Parcel data, reply;
-        status_t err;
-
-        if (item == NULL) {
-                return MediaAnalyticsItem::SessionIDInvalid;
+        if (item == nullptr) {
+            return BAD_VALUE;
         }
+        ALOGV("%s: (ONEWAY) item=%s", __func__, item->toString().c_str());
 
+        Parcel data;
         data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
-        if(DEBUGGING_FLOW) {
-            ALOGD("client offers record: %s", item->toString().c_str());
-        }
-        data.writeBool(forcenew);
-        item->writeToParcel(&data);
 
-        err = remote()->transact(SUBMIT_ITEM, data, &reply);
-        if (err != NO_ERROR) {
-            ALOGW("bad response from service for submit, err=%d", err);
-            return MediaAnalyticsItem::SessionIDInvalid;
+        status_t status = item->writeToParcel(&data);
+        if (status != NO_ERROR) { // assume failure logged in item
+            return status;
         }
 
-        // get an answer out of 'reply'
-        int64_t sessionid = reply.readInt64();
-        if (DEBUGGING_RETURNS) {
-            ALOGD("the caller gets sessionid=%" PRId64 "", sessionid);
-        }
-        return sessionid;
+        status = remote()->transact(
+                SUBMIT_ITEM_ONEWAY, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
+        ALOGW_IF(status != NO_ERROR, "%s: bad response from service for submit, status=%d",
+                __func__, status);
+        return status;
     }
-
 };
 
 IMPLEMENT_META_INTERFACE(MediaAnalyticsService, "android.media.IMediaAnalyticsService");
@@ -115,49 +76,26 @@
 status_t BnMediaAnalyticsService::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
-
-
-    // get calling pid/tid
-    IPCThreadState *ipc = IPCThreadState::self();
-    int clientPid = ipc->getCallingPid();
-    // permission checking
-
-    if(DEBUGGING_FLOW) {
-        ALOGD("running in service, code %d, pid %d; called from pid %d",
-            code, getpid(), clientPid);
-    }
+    const int clientPid = IPCThreadState::self()->getCallingPid();
 
     switch (code) {
+    case SUBMIT_ITEM_ONEWAY: {
+        CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
 
-        case GENERATE_UNIQUE_SESSIONID: {
-            CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
+        MediaAnalyticsItem * const item = MediaAnalyticsItem::create();
+        status_t status = item->readFromParcel(data);
+        if (status != NO_ERROR) { // assume failure logged in item
+            return status;
+        }
+        // TODO: remove this setPid.
+        item->setPid(clientPid);
+        status = submitInternal(item, true /* release */);
+        // assume failure logged by submitInternal
+        return NO_ERROR;
+    } break;
 
-            MediaAnalyticsItem::SessionID_t sessionid = generateUniqueSessionID();
-            reply->writeInt64(sessionid);
-
-            return NO_ERROR;
-        } break;
-
-        case SUBMIT_ITEM: {
-            CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
-
-            bool forcenew;
-            MediaAnalyticsItem *item = MediaAnalyticsItem::create();
-
-            data.readBool(&forcenew);
-            item->readFromParcel(data);
-
-            item->setPid(clientPid);
-
-            // submit() takes over ownership of 'item'
-            MediaAnalyticsItem::SessionID_t sessionid = submit(item, forcenew);
-            reply->writeInt64(sessionid);
-
-            return NO_ERROR;
-        } break;
-
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
+    default:
+        return BBinder::onTransact(code, data, reply, flags);
     }
 }
 
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 02c23b1..14dce79 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#undef LOG_TAG
 #define LOG_TAG "MediaAnalyticsItem"
 
 #include <inttypes.h>
@@ -22,10 +21,12 @@
 #include <string.h>
 #include <sys/types.h>
 
+#include <mutex>
+#include <set>
+
 #include <binder/Parcel.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
-#include <utils/Mutex.h>
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
@@ -44,52 +45,14 @@
 // the service is off.
 #define SVC_TRIES               2
 
-// the few universal keys we have
-const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny  = "any";
-const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyNone  = "none";
-
-const char * const MediaAnalyticsItem::EnabledProperty  = "media.metrics.enabled";
-const char * const MediaAnalyticsItem::EnabledPropertyPersist  = "persist.media.metrics.enabled";
-const int MediaAnalyticsItem::EnabledProperty_default  = 1;
-
-// So caller doesn't need to know size of allocated space
-MediaAnalyticsItem *MediaAnalyticsItem::create()
-{
-    return MediaAnalyticsItem::create(kKeyNone);
-}
-
-MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
-{
-    MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
+MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
+    MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
     return item;
 }
 
-// access functions for the class
-MediaAnalyticsItem::MediaAnalyticsItem()
-    : mPid(-1),
-      mUid(-1),
-      mPkgVersionCode(0),
-      mSessionID(MediaAnalyticsItem::SessionIDNone),
-      mTimestamp(0),
-      mFinalized(1),
-      mPropCount(0), mPropSize(0), mProps(NULL)
-{
-    mKey = MediaAnalyticsItem::kKeyNone;
-}
-
-MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
-    : mPid(-1),
-      mUid(-1),
-      mPkgVersionCode(0),
-      mSessionID(MediaAnalyticsItem::SessionIDNone),
-      mTimestamp(0),
-      mFinalized(1),
-      mPropCount(0), mPropSize(0), mProps(NULL)
-{
-    if (DEBUG_ALLOCATIONS) {
-        ALOGD("Allocate MediaAnalyticsItem @ %p", this);
-    }
-    mKey = key;
+mediametrics_handle_t MediaAnalyticsItem::convert(MediaAnalyticsItem *item ) {
+    mediametrics_handle_t handle = (mediametrics_handle_t) item;
+    return handle;
 }
 
 MediaAnalyticsItem::~MediaAnalyticsItem() {
@@ -104,13 +67,10 @@
     // clean allocated storage from key
     mKey.clear();
 
-    // clean various major parameters
-    mSessionID = MediaAnalyticsItem::SessionIDNone;
-
     // clean attributes
     // contents of the attributes
     for (size_t i = 0 ; i < mPropCount; i++ ) {
-        clearProp(&mProps[i]);
+        mProps[i].clear();
     }
     // the attribute records themselves
     if (mProps != NULL) {
@@ -133,14 +93,12 @@
         dst->mUid = this->mUid;
         dst->mPkgName = this->mPkgName;
         dst->mPkgVersionCode = this->mPkgVersionCode;
-        dst->mSessionID = this->mSessionID;
         dst->mTimestamp = this->mTimestamp;
-        dst->mFinalized = this->mFinalized;
 
         // properties aka attributes
         dst->growProps(this->mPropCount);
         for(size_t i=0;i<mPropCount;i++) {
-            copyProp(&dst->mProps[i], &this->mProps[i]);
+            dst->mProps[i] = this->mProps[i];
         }
         dst->mPropCount = this->mPropCount;
     }
@@ -148,35 +106,6 @@
     return dst;
 }
 
-MediaAnalyticsItem &MediaAnalyticsItem::setSessionID(MediaAnalyticsItem::SessionID_t id) {
-    mSessionID = id;
-    return *this;
-}
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::getSessionID() const {
-    return mSessionID;
-}
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
-
-    if (mSessionID == SessionIDNone) {
-        // get one from the server
-        MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
-        sp<IMediaAnalyticsService> svc = getInstance();
-        if (svc != NULL) {
-            newid = svc->generateUniqueSessionID();
-        }
-        mSessionID = newid;
-    }
-
-    return mSessionID;
-}
-
-MediaAnalyticsItem &MediaAnalyticsItem::clearSessionID() {
-    mSessionID = MediaAnalyticsItem::SessionIDNone;
-    return *this;
-}
-
 MediaAnalyticsItem &MediaAnalyticsItem::setTimestamp(nsecs_t ts) {
     mTimestamp = ts;
     return *this;
@@ -218,91 +147,55 @@
     return mPkgVersionCode;
 }
 
-// this key is for the overall record -- "codec", "player", "drm", etc
-MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
-    mKey = key;
-    return *this;
-}
-
-MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
-    return mKey;
-}
-
-// number of attributes we have in this record
-int32_t MediaAnalyticsItem::count() const {
-    return mPropCount;
-}
 
 // find the proper entry in the list
-size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
+size_t MediaAnalyticsItem::findPropIndex(const char *name) const
 {
     size_t i = 0;
     for (; i < mPropCount; i++) {
-        Prop *prop = &mProps[i];
-        if (prop->mNameLen != len) {
-            continue;
-        }
-        if (memcmp(name, prop->mName, len) == 0) {
-            break;
-        }
+        if (mProps[i].isNamed(name)) break;
     }
     return i;
 }
 
-MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
-    size_t len = strlen(name);
-    size_t i = findPropIndex(name, len);
+MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) const {
+    const size_t i = findPropIndex(name);
     if (i < mPropCount) {
         return &mProps[i];
     }
-    return NULL;
-}
-
-void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
-    free((void *)mName);
-    mName = (const char *) malloc(len+1);
-    LOG_ALWAYS_FATAL_IF(mName == NULL,
-                        "failed malloc() for property '%s' (len %zu)",
-                        name, len);
-    memcpy ((void *)mName, name, len+1);
-    mNameLen = len;
+    return nullptr;
 }
 
 // consider this "find-or-allocate".
 // caller validates type and uses clearPropValue() accordingly
 MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
-    size_t len = strlen(name);
-    size_t i = findPropIndex(name, len);
-    Prop *prop;
-
+    const size_t i = findPropIndex(name);
     if (i < mPropCount) {
-        prop = &mProps[i];
-    } else {
-        if (i == mPropSize) {
-            if (growProps() == false) {
-                ALOGE("failed allocation for new props");
-                return NULL;
-            }
-        }
-        i = mPropCount++;
-        prop = &mProps[i];
-        prop->setName(name, len);
+        return &mProps[i]; // already have it, return
     }
 
+    Prop *prop = allocateProp(); // get a new prop
+    if (prop == nullptr) return nullptr;
+    prop->setName(name);
     return prop;
 }
 
+MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp() {
+    if (mPropCount == mPropSize && growProps() == false) {
+        ALOGE("%s: failed allocation for new properties", __func__);
+        return nullptr;
+    }
+    return &mProps[mPropCount++];
+}
+
 // used within the summarizers; return whether property existed
 bool MediaAnalyticsItem::removeProp(const char *name) {
-    size_t len = strlen(name);
-    size_t i = findPropIndex(name, len);
+    const size_t i = findPropIndex(name);
     if (i < mPropCount) {
-        Prop *prop = &mProps[i];
-        clearProp(prop);
+        mProps[i].clear();
         if (i != mPropCount-1) {
             // in the middle, bring last one down to fill gap
-            copyProp(prop, &mProps[mPropCount-1]);
-            clearProp(&mProps[mPropCount-1]);
+            mProps[i].swap(mProps[mPropCount-1]);
         }
         mPropCount--;
         return true;
@@ -310,229 +203,25 @@
     return false;
 }
 
-// set the values
-void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
-    Prop *prop = allocateProp(name);
-    if (prop != NULL) {
-        clearPropValue(prop);
-        prop->mType = kTypeInt32;
-        prop->u.int32Value = value;
-    }
-}
-
-void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
-    Prop *prop = allocateProp(name);
-    if (prop != NULL) {
-        clearPropValue(prop);
-        prop->mType = kTypeInt64;
-        prop->u.int64Value = value;
-    }
-}
-
-void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
-    Prop *prop = allocateProp(name);
-    if (prop != NULL) {
-        clearPropValue(prop);
-        prop->mType = kTypeDouble;
-        prop->u.doubleValue = value;
-    }
-}
-
-void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
-
-    Prop *prop = allocateProp(name);
-    // any old value will be gone
-    if (prop != NULL) {
-        clearPropValue(prop);
-        prop->mType = kTypeCString;
-        prop->u.CStringValue = strdup(value);
-    }
-}
-
-void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
-    Prop *prop = allocateProp(name);
-    if (prop != NULL) {
-        clearPropValue(prop);
-        prop->mType = kTypeRate;
-        prop->u.rate.count = count;
-        prop->u.rate.duration = duration;
-    }
-}
-
-
-// find/add/set fused into a single operation
-void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
-    Prop *prop = allocateProp(name);
-    if (prop == NULL) {
-        return;
-    }
-    switch (prop->mType) {
-        case kTypeInt32:
-            prop->u.int32Value += value;
-            break;
-        default:
-            clearPropValue(prop);
-            prop->mType = kTypeInt32;
-            prop->u.int32Value = value;
-            break;
-    }
-}
-
-void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
-    Prop *prop = allocateProp(name);
-    if (prop == NULL) {
-        return;
-    }
-    switch (prop->mType) {
-        case kTypeInt64:
-            prop->u.int64Value += value;
-            break;
-        default:
-            clearPropValue(prop);
-            prop->mType = kTypeInt64;
-            prop->u.int64Value = value;
-            break;
-    }
-}
-
-void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
-    Prop *prop = allocateProp(name);
-    if (prop == NULL) {
-        return;
-    }
-    switch (prop->mType) {
-        case kTypeRate:
-            prop->u.rate.count += count;
-            prop->u.rate.duration += duration;
-            break;
-        default:
-            clearPropValue(prop);
-            prop->mType = kTypeRate;
-            prop->u.rate.count = count;
-            prop->u.rate.duration = duration;
-            break;
-    }
-}
-
-void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
-    Prop *prop = allocateProp(name);
-    if (prop == NULL) {
-        return;
-    }
-    switch (prop->mType) {
-        case kTypeDouble:
-            prop->u.doubleValue += value;
-            break;
-        default:
-            clearPropValue(prop);
-            prop->mType = kTypeDouble;
-            prop->u.doubleValue = value;
-            break;
-    }
-}
-
-// find & extract values
-bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
-    Prop *prop = findProp(name);
-    if (prop == NULL || prop->mType != kTypeInt32) {
-        return false;
-    }
-    if (value != NULL) {
-        *value = prop->u.int32Value;
-    }
-    return true;
-}
-
-bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
-    Prop *prop = findProp(name);
-    if (prop == NULL || prop->mType != kTypeInt64) {
-        return false;
-    }
-    if (value != NULL) {
-        *value = prop->u.int64Value;
-    }
-    return true;
-}
-
-bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
-    Prop *prop = findProp(name);
-    if (prop == NULL || prop->mType != kTypeRate) {
-        return false;
-    }
-    if (count != NULL) {
-        *count = prop->u.rate.count;
-    }
-    if (duration != NULL) {
-        *duration = prop->u.rate.duration;
-    }
-    if (rate != NULL) {
-        double r = 0.0;
-        if (prop->u.rate.duration != 0) {
-            r = prop->u.rate.count / (double) prop->u.rate.duration;
-        }
-        *rate = r;
-    }
-    return true;
-}
-
-bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
-    Prop *prop = findProp(name);
-    if (prop == NULL || prop->mType != kTypeDouble) {
-        return false;
-    }
-    if (value != NULL) {
-        *value = prop->u.doubleValue;
-    }
-    return true;
-}
-
-// caller responsible for the returned string
-bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
-    Prop *prop = findProp(name);
-    if (prop == NULL || prop->mType != kTypeCString) {
-        return false;
-    }
-    if (value != NULL) {
-        *value = strdup(prop->u.CStringValue);
-    }
-    return true;
-}
-
-bool MediaAnalyticsItem::getString(MediaAnalyticsItem::Attr name, std::string *value) {
-    Prop *prop = findProp(name);
-    if (prop == NULL || prop->mType != kTypeCString) {
-        return false;
-    }
-    if (value != NULL) {
-        // std::string makes a copy for us
-        *value = prop->u.CStringValue;
-    }
-    return true;
-}
-
 // remove indicated keys and their values
 // return value is # keys removed
-int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
-    int zapped = 0;
-    if (attrs == NULL || n <= 0) {
-        return -1;
-    }
-    for (ssize_t i = 0 ; i < n ;  i++) {
+size_t MediaAnalyticsItem::filter(size_t n, const char *attrs[]) {
+    size_t zapped = 0;
+    for (size_t i = 0; i < n; ++i) {
         const char *name = attrs[i];
-        size_t len = strlen(name);
-        size_t j = findPropIndex(name, len);
+        size_t j = findPropIndex(name);
         if (j >= mPropCount) {
             // not there
             continue;
-        } else if (j+1 == mPropCount) {
+        } else if (j + 1 == mPropCount) {
             // last one, shorten
             zapped++;
-            clearProp(&mProps[j]);
+            mProps[j].clear();
             mPropCount--;
         } else {
             // in the middle, bring last one down and shorten
             zapped++;
-            clearProp(&mProps[j]);
+            mProps[j].clear();
             mProps[j] = mProps[mPropCount-1];
             mPropCount--;
         }
@@ -542,92 +231,31 @@
 
 // remove any keys NOT in the provided list
 // return value is # keys removed
-int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
-    int zapped = 0;
-    if (attrs == NULL || n <= 0) {
-        return -1;
-    }
-    for (ssize_t i = mPropCount-1 ; i >=0 ;  i--) {
-        Prop *prop = &mProps[i];
-        for (ssize_t j = 0; j < n ; j++) {
-            if (strcmp(prop->mName, attrs[j]) == 0) {
-                clearProp(prop);
-                zapped++;
-                if (i != (ssize_t)(mPropCount-1)) {
-                    *prop = mProps[mPropCount-1];
-                }
-                initProp(&mProps[mPropCount-1]);
-                mPropCount--;
-                break;
-            }
+size_t MediaAnalyticsItem::filterNot(size_t n, const char *attrs[]) {
+    std::set<std::string> check(attrs, attrs + n);
+    size_t zapped = 0;
+    for (size_t j = 0; j < mPropCount;) {
+        if (check.find(mProps[j].getName()) != check.end()) {
+            ++j;
+            continue;
+        }
+        if (j + 1 == mPropCount) {
+            // last one, shorten
+            zapped++;
+            mProps[j].clear();
+            mPropCount--;
+            break;
+        } else {
+            // in the middle, bring last one down and shorten
+            zapped++;
+            mProps[j].clear();
+            mProps[j] = mProps[mPropCount-1];
+            mPropCount--;
         }
     }
     return zapped;
 }
 
-// remove a single key
-// return value is 0 (not found) or 1 (found and removed)
-int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
-    return filter(1, &name);
-}
-
-// handle individual items/properties stored within the class
-//
-
-void MediaAnalyticsItem::initProp(Prop *prop) {
-    if (prop != NULL) {
-        prop->mName = NULL;
-        prop->mNameLen = 0;
-
-        prop->mType = kTypeNone;
-    }
-}
-
-void MediaAnalyticsItem::clearProp(Prop *prop)
-{
-    if (prop != NULL) {
-        if (prop->mName != NULL) {
-            free((void *)prop->mName);
-            prop->mName = NULL;
-            prop->mNameLen = 0;
-        }
-
-        clearPropValue(prop);
-    }
-}
-
-void MediaAnalyticsItem::clearPropValue(Prop *prop)
-{
-    if (prop != NULL) {
-        if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
-            free(prop->u.CStringValue);
-            prop->u.CStringValue = NULL;
-        }
-        prop->mType = kTypeNone;
-    }
-}
-
-void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
-{
-    // get rid of any pointers in the dst
-    clearProp(dst);
-
-    *dst = *src;
-
-    // fix any pointers that we blindly copied, so we have our own copies
-    if (dst->mName) {
-        void *p =  malloc(dst->mNameLen + 1);
-        LOG_ALWAYS_FATAL_IF(p == NULL,
-                            "failed malloc() duping property '%s' (len %zu)",
-                            dst->mName, dst->mNameLen);
-        memcpy (p, src->mName, dst->mNameLen + 1);
-        dst->mName = (const char *) p;
-    }
-    if (dst->mType == kTypeCString) {
-        dst->u.CStringValue = strdup(src->u.CStringValue);
-    }
-}
-
 bool MediaAnalyticsItem::growProps(int increment)
 {
     if (increment <= 0) {
@@ -638,7 +266,7 @@
 
     if (ni != NULL) {
         for (int i = mPropSize; i < nsize; i++) {
-            initProp(&ni[i]);
+            new (&ni[i]) Prop(); // placement new
         }
         mProps = ni;
         mPropSize = nsize;
@@ -652,128 +280,77 @@
 // Parcel / serialize things for binder calls
 //
 
-int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
-    int32_t version = data.readInt32();
+status_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
+    int32_t version;
+    status_t status = data.readInt32(&version);
+    if (status != NO_ERROR) return status;
 
-    switch(version) {
-        case 0:
-          return readFromParcel0(data);
-          break;
-        default:
-          ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
-          return -1;
+    switch (version) {
+    case 0:
+      return readFromParcel0(data);
+    default:
+      ALOGE("%s: unsupported parcel version: %d", __func__, version);
+      return INVALID_OPERATION;
     }
 }
 
-int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
-    // into 'this' object
-    // .. we make a copy of the string to put away.
-    mKey = data.readCString();
-    mPid = data.readInt32();
-    mUid = data.readInt32();
-    mPkgName = data.readCString();
-    mPkgVersionCode = data.readInt64();
-    mSessionID = data.readInt64();
-    // We no longer pay attention to user setting of finalized, BUT it's
-    // still part of the wire packet -- so read & discard.
-    mFinalized = data.readInt32();
-    mFinalized = 1;
-    mTimestamp = data.readInt64();
-
-    int count = data.readInt32();
+status_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
+    const char *s = data.readCString();
+    mKey = s == nullptr ? "" : s;
+    int32_t pid, uid;
+    status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
+    if (status != NO_ERROR) return status;
+    mPid = (pid_t)pid;
+    mUid = (uid_t)uid;
+    s = data.readCString();
+    mPkgName = s == nullptr ? "" : s;
+    int32_t count;
+    int64_t version, timestamp;
+    status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
+    if (status != NO_ERROR) return status;
+    if (count < 0) return BAD_VALUE;
+    mPkgVersionCode = version;
+    mTimestamp = timestamp;
     for (int i = 0; i < count ; i++) {
-            MediaAnalyticsItem::Attr attr = data.readCString();
-            int32_t ztype = data.readInt32();
-                switch (ztype) {
-                    case MediaAnalyticsItem::kTypeInt32:
-                            setInt32(attr, data.readInt32());
-                            break;
-                    case MediaAnalyticsItem::kTypeInt64:
-                            setInt64(attr, data.readInt64());
-                            break;
-                    case MediaAnalyticsItem::kTypeDouble:
-                            setDouble(attr, data.readDouble());
-                            break;
-                    case MediaAnalyticsItem::kTypeCString:
-                            setCString(attr, data.readCString());
-                            break;
-                    case MediaAnalyticsItem::kTypeRate:
-                            {
-                                int64_t count = data.readInt64();
-                                int64_t duration = data.readInt64();
-                                setRate(attr, count, duration);
-                            }
-                            break;
-                    default:
-                            ALOGE("reading bad item type: %d, idx %d",
-                                  ztype, i);
-                            return -1;
-                }
+        Prop *prop = allocateProp();
+        status_t status = prop->readFromParcel(data);
+        if (status != NO_ERROR) return status;
     }
-
-    return 0;
+    return NO_ERROR;
 }
 
-int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
+status_t MediaAnalyticsItem::writeToParcel(Parcel *data) const {
+    if (data == nullptr) return BAD_VALUE;
 
-    if (data == NULL) return -1;
+    const int32_t version = 0;
+    status_t status = data->writeInt32(version);
+    if (status != NO_ERROR) return status;
 
-    int32_t version = 0;
-    data->writeInt32(version);
-
-    switch(version) {
-        case 0:
-          return writeToParcel0(data);
-          break;
-        default:
-          ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
-          return -1;
+    switch (version) {
+    case 0:
+      return writeToParcel0(data);
+    default:
+      ALOGE("%s: unsupported parcel version: %d", __func__, version);
+      return INVALID_OPERATION;
     }
 }
 
-int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
+status_t MediaAnalyticsItem::writeToParcel0(Parcel *data) const {
+    status_t status =
+        data->writeCString(mKey.c_str())
+        ?: data->writeInt32(mPid)
+        ?: data->writeInt32(mUid)
+        ?: data->writeCString(mPkgName.c_str())
+        ?: data->writeInt64(mPkgVersionCode)
+        ?: data->writeInt64(mTimestamp);
+    if (status != NO_ERROR) return status;
 
-    data->writeCString(mKey.c_str());
-    data->writeInt32(mPid);
-    data->writeInt32(mUid);
-    data->writeCString(mPkgName.c_str());
-    data->writeInt64(mPkgVersionCode);
-    data->writeInt64(mSessionID);
-    data->writeInt32(mFinalized);
-    data->writeInt64(mTimestamp);
-
-    // set of items
-    int count = mPropCount;
-    data->writeInt32(count);
-    for (int i = 0 ; i < count; i++ ) {
-            Prop *prop = &mProps[i];
-            data->writeCString(prop->mName);
-            data->writeInt32(prop->mType);
-            switch (prop->mType) {
-                case MediaAnalyticsItem::kTypeInt32:
-                        data->writeInt32(prop->u.int32Value);
-                        break;
-                case MediaAnalyticsItem::kTypeInt64:
-                        data->writeInt64(prop->u.int64Value);
-                        break;
-                case MediaAnalyticsItem::kTypeDouble:
-                        data->writeDouble(prop->u.doubleValue);
-                        break;
-                case MediaAnalyticsItem::kTypeRate:
-                        data->writeInt64(prop->u.rate.count);
-                        data->writeInt64(prop->u.rate.duration);
-                        break;
-                case MediaAnalyticsItem::kTypeCString:
-                        data->writeCString(prop->u.CStringValue);
-                        break;
-                default:
-                        ALOGE("found bad Prop type: %d, idx %d, name %s",
-                              prop->mType, i, prop->mName);
-                        break;
-            }
+    data->writeInt32((int32_t)mPropCount);
+    for (size_t i = 0 ; i < mPropCount; ++i) {
+        status = mProps[i].writeToParcel(data);
+        if (status != NO_ERROR) return status;
     }
-
-    return 0;
+    return NO_ERROR;
 }
 
 const char *MediaAnalyticsItem::toCString() {
@@ -785,11 +362,11 @@
     return strdup(val.c_str());
 }
 
-std::string MediaAnalyticsItem::toString() {
+std::string MediaAnalyticsItem::toString() const {
    return toString(PROTO_LAST);
 }
 
-std::string MediaAnalyticsItem::toString(int version) {
+std::string MediaAnalyticsItem::toString(int version) const {
 
     // v0 : released with 'o'
     // v1 : bug fix (missing pid/finalized separator),
@@ -815,9 +392,7 @@
     // same order as we spill into the parcel, although not required
     // key+session are our primary matching criteria
     result.append(mKey.c_str());
-    result.append(":");
-    snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
-    result.append(buffer);
+    result.append(":0:"); // sessionID
 
     snprintf(buffer, sizeof(buffer), "%d:", mUid);
     result.append(buffer);
@@ -836,7 +411,7 @@
     }
     result.append(buffer);
 
-    snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
+    snprintf(buffer, sizeof(buffer), "%d:", 0 /* finalized */); // TODO: remove this.
     result.append(buffer);
     snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mTimestamp);
     result.append(buffer);
@@ -846,39 +421,8 @@
     snprintf(buffer, sizeof(buffer), "%d:", count);
     result.append(buffer);
     for (int i = 0 ; i < count; i++ ) {
-            Prop *prop = &mProps[i];
-            switch (prop->mType) {
-                case MediaAnalyticsItem::kTypeInt32:
-                        snprintf(buffer,sizeof(buffer),
-                        "%s=%d:", prop->mName, prop->u.int32Value);
-                        break;
-                case MediaAnalyticsItem::kTypeInt64:
-                        snprintf(buffer,sizeof(buffer),
-                        "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
-                        break;
-                case MediaAnalyticsItem::kTypeDouble:
-                        snprintf(buffer,sizeof(buffer),
-                        "%s=%e:", prop->mName, prop->u.doubleValue);
-                        break;
-                case MediaAnalyticsItem::kTypeRate:
-                        snprintf(buffer,sizeof(buffer),
-                        "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
-                        prop->u.rate.count, prop->u.rate.duration);
-                        break;
-                case MediaAnalyticsItem::kTypeCString:
-                        snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
-                        result.append(buffer);
-                        // XXX: sanitize string for ':' '='
-                        result.append(prop->u.CStringValue);
-                        buffer[0] = ':';
-                        buffer[1] = '\0';
-                        break;
-                default:
-                        ALOGE("to_String bad item type: %d for %s",
-                              prop->mType, prop->mName);
-                        break;
-            }
-            result.append(buffer);
+        mProps[i].toString(buffer, sizeof(buffer));
+        result.append(buffer);
     }
 
     if (version == PROTO_V0) {
@@ -893,23 +437,12 @@
 // for the lazy, we offer methods that finds the service and
 // calls the appropriate daemon
 bool MediaAnalyticsItem::selfrecord() {
-    return selfrecord(false);
-}
-
-bool MediaAnalyticsItem::selfrecord(bool forcenew) {
-
-    if (DEBUG_API) {
-        std::string p = this->toString();
-        ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
-    }
-
+    ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
     sp<IMediaAnalyticsService> svc = getInstance();
-
     if (svc != NULL) {
-        MediaAnalyticsItem::SessionID_t newid = svc->submit(this, forcenew);
-        if (newid == SessionIDInvalid) {
-            std::string p = this->toString();
-            ALOGW("Failed to record: %s [forcenew=%d]", p.c_str(), forcenew);
+        status_t status = svc->submit(this);
+        if (status != NO_ERROR) {
+            ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
             return false;
         }
         return true;
@@ -918,29 +451,32 @@
     }
 }
 
-// get a connection we can reuse for most of our lifetime
-// static
-sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
-static Mutex sInitMutex;
-static int remainingBindAttempts = SVC_TRIES;
-
 //static
 bool MediaAnalyticsItem::isEnabled() {
-    int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
+    // completely skip logging from certain UIDs. We do this here
+    // to avoid the multi-second timeouts while we learn that
+    // sepolicy will not let us find the service.
+    // We do this only for a select set of UIDs
+    // The sepolicy protection is still in place, we just want a faster
+    // response from this specific, small set of uids.
 
+    // This is checked only once in the lifetime of the process.
+    const uid_t uid = getuid();
+    switch (uid) {
+    case AID_RADIO:     // telephony subsystem, RIL
+        return false;
+    }
+
+    int enabled = property_get_int32(MediaAnalyticsItem::EnabledProperty, -1);
     if (enabled == -1) {
         enabled = property_get_int32(MediaAnalyticsItem::EnabledPropertyPersist, -1);
     }
     if (enabled == -1) {
         enabled = MediaAnalyticsItem::EnabledProperty_default;
     }
-    if (enabled <= 0) {
-        return false;
-    }
-    return true;
+    return enabled > 0;
 }
 
-
 // monitor health of our connection to the metrics service
 class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
         virtual void binderDied(const wp<IBinder> &) {
@@ -949,83 +485,56 @@
         }
 };
 
-static sp<MediaMetricsDeathNotifier> sNotifier = NULL;
+static sp<MediaMetricsDeathNotifier> sNotifier;
+// static
+sp<IMediaAnalyticsService> MediaAnalyticsItem::sAnalyticsService;
+static std::mutex sServiceMutex;
+static int sRemainingBindAttempts = SVC_TRIES;
 
 // static
 void MediaAnalyticsItem::dropInstance() {
-    Mutex::Autolock _l(sInitMutex);
-    remainingBindAttempts = SVC_TRIES;
-    sAnalyticsService = NULL;
+    std::lock_guard  _l(sServiceMutex);
+    sRemainingBindAttempts = SVC_TRIES;
+    sAnalyticsService = nullptr;
 }
 
 //static
 sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
-
     static const char *servicename = "media.metrics";
-    int enabled = isEnabled();
+    static const bool enabled = isEnabled(); // singleton initialized
 
     if (enabled == false) {
-        if (DEBUG_SERVICEACCESS) {
-                ALOGD("disabled");
-        }
-        return NULL;
+        ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
+        return nullptr;
     }
-
-    // completely skip logging from certain UIDs. We do this here
-    // to avoid the multi-second timeouts while we learn that
-    // sepolicy will not let us find the service.
-    // We do this only for a select set of UIDs
-    // The sepolicy protection is still in place, we just want a faster
-    // response from this specific, small set of uids.
-    {
-        uid_t uid = getuid();
-        switch (uid) {
-            case AID_RADIO:     // telephony subsystem, RIL
-                return NULL;
-                break;
-            default:
-                // let sepolicy deny access if appropriate
-                break;
-        }
-    }
-
-    {
-        Mutex::Autolock _l(sInitMutex);
+    std::lock_guard _l(sServiceMutex);
+    // think of remainingBindAttempts as telling us whether service == nullptr because
+    // (1) we haven't tried to initialize it yet
+    // (2) we've tried to initialize it, but failed.
+    if (sAnalyticsService == nullptr && sRemainingBindAttempts > 0) {
         const char *badness = "";
-
-        // think of remainingBindAttempts as telling us whether service==NULL because
-        // (1) we haven't tried to initialize it yet
-        // (2) we've tried to initialize it, but failed.
-        if (sAnalyticsService == NULL && remainingBindAttempts > 0) {
-            sp<IServiceManager> sm = defaultServiceManager();
-            if (sm != NULL) {
-                sp<IBinder> binder = sm->getService(String16(servicename));
-                if (binder != NULL) {
-                    sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
-                    if (sNotifier != NULL) {
-                        sNotifier = NULL;
-                    }
-                    sNotifier = new MediaMetricsDeathNotifier();
-                    binder->linkToDeath(sNotifier);
-                } else {
-                    badness = "did not find service";
-                }
+        sp<IServiceManager> sm = defaultServiceManager();
+        if (sm != nullptr) {
+            sp<IBinder> binder = sm->getService(String16(servicename));
+            if (binder != nullptr) {
+                sAnalyticsService = interface_cast<IMediaAnalyticsService>(binder);
+                sNotifier = new MediaMetricsDeathNotifier();
+                binder->linkToDeath(sNotifier);
             } else {
-                badness = "No Service Manager access";
+                badness = "did not find service";
             }
-
-            if (sAnalyticsService == NULL) {
-                if (remainingBindAttempts > 0) {
-                    remainingBindAttempts--;
-                }
-                if (DEBUG_SERVICEACCESS) {
-                    ALOGD("Unable to bind to service %s: %s", servicename, badness);
-                }
-            }
+        } else {
+            badness = "No Service Manager access";
         }
-
-        return sAnalyticsService;
+        if (sAnalyticsService == nullptr) {
+            if (sRemainingBindAttempts > 0) {
+                sRemainingBindAttempts--;
+            }
+            ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
+                    __func__, servicename, badness);
+        }
     }
+    return sAnalyticsService;
 }
 
 // merge the info from 'incoming' into this record.
@@ -1036,8 +545,6 @@
     // 'this' should never be missing both of them...
     if (mKey.empty()) {
         mKey = incoming->mKey;
-    } else if (mSessionID == 0) {
-        mSessionID = incoming->mSessionID;
     }
 
     // for each attribute from 'incoming', resolve appropriately
@@ -1058,12 +565,12 @@
             // no oprop, so we insert the new one
             oprop = allocateProp(p);
             if (oprop != NULL) {
-                copyProp(oprop, iprop);
+                *oprop = *iprop;
             } else {
                 ALOGW("dropped property '%s'", iprop->mName);
             }
         } else {
-            copyProp(oprop, iprop);
+            *oprop = *iprop;
         }
     }
 
@@ -1071,170 +578,469 @@
     return true;
 }
 
-// a byte array; contents are
-// overall length (uint32) including the length field itself
-// encoding version (uint32)
-// count of properties (uint32)
-// N copies of:
-//     property name as length(int16), bytes
-//         the bytes WILL include the null terminator of the name
-//     type (uint8 -- 1 byte)
-//     size of value field (int16 -- 2 bytes)
-//     value (size based on type)
-//       int32, int64, double -- little endian 4/8/8 bytes respectively
-//       cstring -- N bytes of value [WITH terminator]
+namespace {
 
-enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
-
-bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
-
-    char *build = NULL;
-
-    if (pbuffer == NULL || plength == NULL)
-        return false;
-
-    // consistency for the caller, who owns whatever comes back in this pointer.
-    *pbuffer = NULL;
-
-    // first, let's calculate sizes
-    int32_t goal = 0;
-    int32_t version = 0;
-
-    goal += sizeof(uint32_t);   // overall length, including the length field
-    goal += sizeof(uint32_t);   // encoding version
-    goal += sizeof(uint32_t);   // # properties
-
-    int32_t count = mPropCount;
-    for (int i = 0 ; i < count; i++ ) {
-        Prop *prop = &mProps[i];
-        goal += sizeof(uint16_t);           // name length
-        goal += strlen(prop->mName) + 1;    // string + null
-        goal += sizeof(uint8_t);            // type
-        goal += sizeof(uint16_t);           // size of value
-        switch (prop->mType) {
-            case MediaAnalyticsItem::kTypeInt32:
-                    goal += sizeof(uint32_t);
-                    break;
-            case MediaAnalyticsItem::kTypeInt64:
-                    goal += sizeof(uint64_t);
-                    break;
-            case MediaAnalyticsItem::kTypeDouble:
-                    goal += sizeof(double);
-                    break;
-            case MediaAnalyticsItem::kTypeRate:
-                    goal += 2 * sizeof(uint64_t);
-                    break;
-            case MediaAnalyticsItem::kTypeCString:
-                    // length + actual string + null
-                    goal += strlen(prop->u.CStringValue) + 1;
-                    break;
-            default:
-                    ALOGE("found bad Prop type: %d, idx %d, name %s",
-                          prop->mType, i, prop->mName);
-                    return false;
-        }
+template <typename T>
+status_t insert(const T& val, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t size = sizeof(val);
+    if (*bufferpptr + size > bufferptrmax) {
+        ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+        return BAD_VALUE;
     }
+    memcpy(*bufferpptr, &val, size);
+    *bufferpptr += size;
+    return NO_ERROR;
+}
+
+template <>
+status_t insert(const char * const& val, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t size = strlen(val) + 1;
+    if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
+        ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+        return BAD_VALUE;
+    }
+    memcpy(*bufferpptr, val, size);
+    *bufferpptr += size;
+    return NO_ERROR;
+}
+
+template <>
+ __unused
+status_t insert(char * const& val, char **bufferpptr, char *bufferptrmax)
+{
+    return insert((const char *)val, bufferpptr, bufferptrmax);
+}
+
+template <typename T>
+status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax)
+{
+    const size_t size = sizeof(*val);
+    if (*bufferpptr + size > bufferptrmax) {
+        ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+        return BAD_VALUE;
+    }
+    memcpy(val, *bufferpptr, size);
+    *bufferpptr += size;
+    return NO_ERROR;
+}
+
+template <>
+status_t extract(char **val, const char **bufferpptr, const char *bufferptrmax)
+{
+    const char *ptr = *bufferpptr;
+    while (*ptr != 0) {
+        if (ptr >= bufferptrmax) {
+            ALOGE("%s: buffer exceeded", __func__);
+        }
+        ++ptr;
+    }
+    const size_t size = (ptr - *bufferpptr) + 1;
+    *val = (char *)malloc(size);
+    memcpy(*val, *bufferpptr, size);
+    *bufferpptr += size;
+    return NO_ERROR;
+}
+
+} // namespace
+
+status_t MediaAnalyticsItem::writeToByteString(char **pbuffer, size_t *plength) const
+{
+    if (pbuffer == nullptr || plength == nullptr)
+        return BAD_VALUE;
+
+    // get size
+    const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
+    if (keySizeZeroTerminated > UINT16_MAX) {
+        ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
+        return INVALID_OPERATION;
+    }
+    const uint16_t version = 0;
+    const uint32_t header_len =
+        sizeof(uint32_t)     // overall length
+        + sizeof(header_len) // header length
+        + sizeof(version)    // encoding version
+        + sizeof(uint16_t)   // key length
+        + keySizeZeroTerminated // key, zero terminated
+        + sizeof(int32_t)    // pid
+        + sizeof(int32_t)    // uid
+        + sizeof(int64_t)    // timestamp
+        ;
+
+    uint32_t len = header_len
+        + sizeof(uint32_t) // # properties
+        ;
+    for (size_t i = 0 ; i < mPropCount; ++i) {
+        const size_t size = mProps[i].getByteStringSize();
+        if (size > UINT_MAX - 1) {
+            ALOGW("%s: prop %zu has size %zu", __func__, i, size);
+            return INVALID_OPERATION;
+        }
+        len += size;
+    }
+
+    // TODO: consider package information and timestamp.
 
     // now that we have a size... let's allocate and fill
-    build = (char *)malloc(goal);
-    if (build == NULL)
-        return false;
-
-    memset(build, 0, goal);
+    char *build = (char *)calloc(1 /* nmemb */, len);
+    if (build == nullptr) return NO_MEMORY;
 
     char *filling = build;
-
-#define _INSERT(val, size) \
-    { memcpy(filling, &(val), (size)); filling += (size);}
-#define _INSERTSTRING(val, size) \
-    { memcpy(filling, (val), (size)); filling += (size);}
-
-    _INSERT(goal, sizeof(int32_t));
-    _INSERT(version, sizeof(int32_t));
-    _INSERT(count, sizeof(int32_t));
-
-    for (int i = 0 ; i < count; i++ ) {
-        Prop *prop = &mProps[i];
-        int16_t attrNameLen = strlen(prop->mName) + 1;
-        _INSERT(attrNameLen, sizeof(int16_t));
-        _INSERTSTRING(prop->mName, attrNameLen);    // termination included
-        int8_t elemtype;
-        int16_t elemsize;
-        switch (prop->mType) {
-            case MediaAnalyticsItem::kTypeInt32:
-                {
-                    elemtype = kInt32;
-                    _INSERT(elemtype, sizeof(int8_t));
-                    elemsize = sizeof(int32_t);
-                    _INSERT(elemsize, sizeof(int16_t));
-
-                    _INSERT(prop->u.int32Value, sizeof(int32_t));
-                    break;
-                }
-            case MediaAnalyticsItem::kTypeInt64:
-                {
-                    elemtype = kInt64;
-                    _INSERT(elemtype, sizeof(int8_t));
-                    elemsize = sizeof(int64_t);
-                    _INSERT(elemsize, sizeof(int16_t));
-
-                    _INSERT(prop->u.int64Value, sizeof(int64_t));
-                    break;
-                }
-            case MediaAnalyticsItem::kTypeDouble:
-                {
-                    elemtype = kDouble;
-                    _INSERT(elemtype, sizeof(int8_t));
-                    elemsize = sizeof(double);
-                    _INSERT(elemsize, sizeof(int16_t));
-
-                    _INSERT(prop->u.doubleValue, sizeof(double));
-                    break;
-                }
-            case MediaAnalyticsItem::kTypeRate:
-                {
-                    elemtype = kRate;
-                    _INSERT(elemtype, sizeof(int8_t));
-                    elemsize = 2 * sizeof(uint64_t);
-                    _INSERT(elemsize, sizeof(int16_t));
-
-                    _INSERT(prop->u.rate.count, sizeof(uint64_t));
-                    _INSERT(prop->u.rate.duration, sizeof(uint64_t));
-                    break;
-                }
-            case MediaAnalyticsItem::kTypeCString:
-                {
-                    elemtype = kCString;
-                    _INSERT(elemtype, sizeof(int8_t));
-                    elemsize = strlen(prop->u.CStringValue) + 1;
-                    _INSERT(elemsize, sizeof(int16_t));
-
-                    _INSERTSTRING(prop->u.CStringValue, elemsize);
-                    break;
-                }
-            default:
-                    // error if can't encode; warning if can't decode
-                    ALOGE("found bad Prop type: %d, idx %d, name %s",
-                          prop->mType, i, prop->mName);
-                    goto badness;
+    char *buildmax = build + len;
+    if (insert(len, &filling, buildmax) != NO_ERROR
+            || insert(header_len, &filling, buildmax) != NO_ERROR
+            || insert(version, &filling, buildmax) != NO_ERROR
+            || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
+            || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
+            || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
+            || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
+            || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
+            || insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) {
+        ALOGD("%s:could not write header", __func__);
+        free(build);
+        return INVALID_OPERATION;
+    }
+    for (size_t i = 0 ; i < mPropCount; ++i) {
+        if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) {
+            free(build);
+            ALOGD("%s:could not write prop %zu of %zu", __func__, i, mPropCount);
+            return INVALID_OPERATION;
         }
     }
 
-    if (build + goal != filling) {
+    if (filling != buildmax) {
         ALOGE("problems populating; wrote=%d planned=%d",
-              (int)(filling-build), goal);
-        goto badness;
+              (int)(filling - build), len);
+        free(build);
+        return INVALID_OPERATION;
     }
-
     *pbuffer = build;
-    *plength = goal;
+    *plength = len;
+    return NO_ERROR;
+}
 
-    return true;
+status_t MediaAnalyticsItem::readFromByteString(const char *bufferptr, size_t length)
+{
+    if (bufferptr == nullptr) return BAD_VALUE;
 
-  badness:
-    free(build);
-    return false;
+    const char *read = bufferptr;
+    const char *readend = bufferptr + length;
+
+    uint32_t len;
+    uint32_t header_len;
+    int16_t version;
+    int16_t key_len;
+    char *key = nullptr;
+    int32_t pid;
+    int32_t uid;
+    int64_t timestamp;
+    uint32_t propCount;
+    if (extract(&len, &read, readend) != NO_ERROR
+            || extract(&header_len, &read, readend) != NO_ERROR
+            || extract(&version, &read, readend) != NO_ERROR
+            || extract(&key_len, &read, readend) != NO_ERROR
+            || extract(&key, &read, readend) != NO_ERROR
+            || extract(&pid, &read, readend) != NO_ERROR
+            || extract(&uid, &read, readend) != NO_ERROR
+            || extract(&timestamp, &read, readend) != NO_ERROR
+            || len > length
+            || header_len > len) {
+        free(key);
+        ALOGD("%s: invalid header", __func__);
+        return INVALID_OPERATION;
+    }
+    mKey = key;
+    free(key);
+    const size_t pos = read - bufferptr;
+    if (pos > header_len) {
+        ALOGD("%s: invalid header pos:%zu > header_len:%u",
+                __func__, pos, header_len);
+        return INVALID_OPERATION;
+    } else if (pos < header_len) {
+        ALOGD("%s: mismatched header pos:%zu < header_len:%u, advancing",
+                __func__, pos, header_len);
+        read += (header_len - pos);
+    }
+    if (extract(&propCount, &read, readend) != NO_ERROR) {
+        ALOGD("%s: cannot read prop count", __func__);
+        return INVALID_OPERATION;
+    }
+    mPid = pid;
+    mUid = uid;
+    mTimestamp = timestamp;
+    for (size_t i = 0; i < propCount; ++i) {
+        Prop *prop = allocateProp();
+        if (prop->readFromByteString(&read, readend) != NO_ERROR) {
+            ALOGD("%s: cannot read prop %zu", __func__, i);
+            return INVALID_OPERATION;
+        }
+    }
+    return NO_ERROR;
+}
+
+status_t MediaAnalyticsItem::Prop::writeToParcel(Parcel *data) const
+{
+   switch (mType) {
+   case kTypeInt32:
+       return data->writeCString(mName)
+               ?: data->writeInt32(mType)
+               ?: data->writeInt32(u.int32Value);
+   case kTypeInt64:
+       return data->writeCString(mName)
+               ?: data->writeInt32(mType)
+               ?: data->writeInt64(u.int64Value);
+   case kTypeDouble:
+       return data->writeCString(mName)
+               ?: data->writeInt32(mType)
+               ?: data->writeDouble(u.doubleValue);
+   case kTypeRate:
+       return data->writeCString(mName)
+               ?: data->writeInt32(mType)
+               ?: data->writeInt64(u.rate.first)
+               ?: data->writeInt64(u.rate.second);
+   case kTypeCString:
+       return data->writeCString(mName)
+               ?: data->writeInt32(mType)
+               ?: data->writeCString(u.CStringValue);
+   default:
+       ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName);
+       return BAD_VALUE;
+   }
+}
+
+status_t MediaAnalyticsItem::Prop::readFromParcel(const Parcel& data)
+{
+    const char *key = data.readCString();
+    if (key == nullptr) return BAD_VALUE;
+    int32_t type;
+    status_t status = data.readInt32(&type);
+    if (status != NO_ERROR) return status;
+    switch (type) {
+    case kTypeInt32:
+        status = data.readInt32(&u.int32Value);
+        break;
+    case kTypeInt64:
+        status = data.readInt64(&u.int64Value);
+        break;
+    case kTypeDouble:
+        status = data.readDouble(&u.doubleValue);
+        break;
+    case kTypeCString: {
+        const char *s = data.readCString();
+        if (s == nullptr) return BAD_VALUE;
+        set(s);
+        break;
+        }
+    case kTypeRate: {
+        std::pair<int64_t, int64_t> rate;
+        status = data.readInt64(&rate.first)
+                ?: data.readInt64(&rate.second);
+        if (status == NO_ERROR) {
+            set(rate);
+        }
+        break;
+        }
+    default:
+        ALOGE("%s: reading bad item type: %d", __func__, mType);
+        return BAD_VALUE;
+    }
+    if (status == NO_ERROR) {
+        setName(key);
+        mType = (Type)type;
+    }
+    return status;
+}
+
+void MediaAnalyticsItem::Prop::toString(char *buffer, size_t length) const
+{
+    switch (mType) {
+    case kTypeInt32:
+        snprintf(buffer, length, "%s=%d:", mName, u.int32Value);
+        break;
+    case MediaAnalyticsItem::kTypeInt64:
+        snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value);
+        break;
+    case MediaAnalyticsItem::kTypeDouble:
+        snprintf(buffer, length, "%s=%e:", mName, u.doubleValue);
+        break;
+    case MediaAnalyticsItem::kTypeRate:
+        snprintf(buffer, length, "%s=%lld/%lld:",
+                mName, (long long)u.rate.first, (long long)u.rate.second);
+        break;
+    case MediaAnalyticsItem::kTypeCString:
+        // TODO sanitize string for ':' '='
+        snprintf(buffer, length, "%s=%s:", mName, u.CStringValue);
+        break;
+    default:
+        ALOGE("%s: bad item type: %d for %s", __func__, mType, mName);
+        if (length > 0) buffer[0] = 0;
+        break;
+    }
+}
+
+size_t MediaAnalyticsItem::Prop::getByteStringSize() const
+{
+    const size_t header =
+        sizeof(uint16_t)      // length
+        + sizeof(uint8_t)     // type
+        + strlen(mName) + 1;  // mName + 0 termination
+    size_t payload = 0;
+    switch (mType) {
+    case MediaAnalyticsItem::kTypeInt32:
+        payload = sizeof(u.int32Value);
+        break;
+    case MediaAnalyticsItem::kTypeInt64:
+        payload = sizeof(u.int64Value);
+        break;
+    case MediaAnalyticsItem::kTypeDouble:
+        payload = sizeof(u.doubleValue);
+        break;
+    case MediaAnalyticsItem::kTypeRate:
+        payload = sizeof(u.rate.first) + sizeof(u.rate.second);
+        break;
+    case MediaAnalyticsItem::kTypeCString:
+        payload = strlen(u.CStringValue) + 1;
+        break;
+    default:
+        ALOGE("%s: found bad prop type: %d, name %s",
+                __func__, mType, mName); // no payload computed
+        break;
+    }
+    return header + payload;
+}
+
+// TODO: fold into a template later.
+status_t MediaAnalyticsItem::writeToByteString(
+        const char *name, int32_t value, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
+    if (len > UINT16_MAX) return BAD_VALUE;
+    return insert((uint16_t)len, bufferpptr, bufferptrmax)
+            ?: insert((uint8_t)kTypeInt32, bufferpptr, bufferptrmax)
+            ?: insert(name, bufferpptr, bufferptrmax)
+            ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+        const char *name, int64_t value, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
+    if (len > UINT16_MAX) return BAD_VALUE;
+    return insert((uint16_t)len, bufferpptr, bufferptrmax)
+            ?: insert((uint8_t)kTypeInt64, bufferpptr, bufferptrmax)
+            ?: insert(name, bufferpptr, bufferptrmax)
+            ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+        const char *name, double value, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
+    if (len > UINT16_MAX) return BAD_VALUE;
+    return insert((uint16_t)len, bufferpptr, bufferptrmax)
+            ?: insert((uint8_t)kTypeDouble, bufferpptr, bufferptrmax)
+            ?: insert(name, bufferpptr, bufferptrmax)
+            ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+        const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8;
+    if (len > UINT16_MAX) return BAD_VALUE;
+    return insert((uint16_t)len, bufferpptr, bufferptrmax)
+            ?: insert((uint8_t)kTypeRate, bufferpptr, bufferptrmax)
+            ?: insert(name, bufferpptr, bufferptrmax)
+            ?: insert(value.first, bufferpptr, bufferptrmax)
+            ?: insert(value.second, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+        const char *name, char * const &value, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
+    if (len > UINT16_MAX) return BAD_VALUE;
+    return insert((uint16_t)len, bufferpptr, bufferptrmax)
+            ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
+            ?: insert(name, bufferpptr, bufferptrmax)
+            ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+        const char *name, const none_t &, char **bufferpptr, char *bufferptrmax)
+{
+    const size_t len = 2 + 1 + strlen(name) + 1;
+    if (len > UINT16_MAX) return BAD_VALUE;
+    return insert((uint16_t)len, bufferpptr, bufferptrmax)
+            ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
+            ?: insert(name, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::Prop::writeToByteString(
+        char **bufferpptr, char *bufferptrmax) const
+{
+    switch (mType) {
+    case kTypeInt32:
+        return MediaAnalyticsItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax);
+    case kTypeInt64:
+        return MediaAnalyticsItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax);
+    case kTypeDouble:
+        return MediaAnalyticsItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax);
+    case kTypeRate:
+        return MediaAnalyticsItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax);
+    case kTypeCString:
+        return MediaAnalyticsItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax);
+    case kTypeNone:
+        return MediaAnalyticsItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax);
+    default:
+        ALOGE("%s: found bad prop type: %d, name %s",
+                __func__, mType, mName);  // no payload sent
+        return BAD_VALUE;
+    }
+}
+
+status_t MediaAnalyticsItem::Prop::readFromByteString(
+        const char **bufferpptr, const char *bufferptrmax)
+{
+    uint16_t len;
+    char *name;
+    uint8_t type;
+    status_t status = extract(&len, bufferpptr, bufferptrmax)
+            ?: extract(&type, bufferpptr, bufferptrmax)
+            ?: extract(&name, bufferpptr, bufferptrmax);
+    if (status != NO_ERROR) return status;
+    if (mName != nullptr) {
+        free(mName);
+    }
+    mName = name;
+    if (mType == kTypeCString) {
+        free(u.CStringValue);
+        u.CStringValue = nullptr;
+    }
+    mType = (Type)type;
+    switch (mType) {
+    case kTypeInt32:
+        return extract(&u.int32Value, bufferpptr, bufferptrmax);
+    case kTypeInt64:
+        return extract(&u.int64Value, bufferpptr, bufferptrmax);
+    case kTypeDouble:
+        return extract(&u.doubleValue, bufferpptr, bufferptrmax);
+    case kTypeRate:
+        return extract(&u.rate.first, bufferpptr, bufferptrmax)
+                ?: extract(&u.rate.second, bufferpptr, bufferptrmax);
+    case kTypeCString:
+        status = extract(&u.CStringValue, bufferpptr, bufferptrmax);
+        if (status != NO_ERROR) mType = kTypeNone;
+        return status;
+    case kTypeNone:
+        return NO_ERROR;
+    default:
+        mType = kTypeNone;
+        ALOGE("%s: found bad prop type: %d, name %s",
+                __func__, mType, mName);  // no payload sent
+        return BAD_VALUE;
+    }
 }
 
 } // namespace android
-
diff --git a/media/libmediametrics/MediaMetrics.cpp b/media/libmediametrics/MediaMetrics.cpp
index 6109190..cf268e0 100644
--- a/media/libmediametrics/MediaMetrics.cpp
+++ b/media/libmediametrics/MediaMetrics.cpp
@@ -169,6 +169,11 @@
     return item->selfrecord();
 }
 
+mediametrics_handle_t mediametrics_dup(mediametrics_handle_t handle) {
+    android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
+    if (item == NULL) return android::MediaAnalyticsItem::convert(item);
+    return android::MediaAnalyticsItem::convert(item->dup());
+}
 
 const char *mediametrics_readable(mediametrics_handle_t handle) {
     android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
@@ -190,6 +195,6 @@
 bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length) {
     android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
     if (item == NULL) return false;
-    return item->dumpAttributes(buffer, length);
+    return item->writeToByteString(buffer, length) == android::NO_ERROR;
 
 }
diff --git a/media/libmediametrics/TEST_MAPPING b/media/libmediametrics/TEST_MAPPING
new file mode 100644
index 0000000..01e9e46
--- /dev/null
+++ b/media/libmediametrics/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+       "name": "mediametrics_tests"
+    },
+    {
+       "name": "CtsNativeMediaMetricsTestCases"
+    }
+  ]
+}
diff --git a/media/libmediametrics/include/IMediaAnalyticsService.h b/media/libmediametrics/include/IMediaAnalyticsService.h
index f635e94..1453b5f 100644
--- a/media/libmediametrics/include/IMediaAnalyticsService.h
+++ b/media/libmediametrics/include/IMediaAnalyticsService.h
@@ -39,19 +39,16 @@
 public:
     DECLARE_META_INTERFACE(MediaAnalyticsService);
 
-    // generate a unique sessionID to use across multiple requests
-    // 'unique' is within this device, since last reboot
-    virtual MediaAnalyticsItem::SessionID_t generateUniqueSessionID() = 0;
-
-    // submit the indicated record to the mediaanalytics service, where
-    // it will be merged (if appropriate) with incomplete records that
-    // share the same key and sessionid.
-    // 'forcenew' marks any matching incomplete record as complete before
-    // inserting this new record.
-    // returns the sessionID associated with that item.
-    // caller continues to own the passed item
-    virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew) = 0;
-
+    /**
+     * Submits the indicated record to the mediaanalytics service, where
+     * it will be merged (if appropriate) with incomplete records that
+     * share the same key and sessionID.
+     *
+     * \param item the item to submit.
+     * \return status which is negative if an error is detected (some errors
+               may be silent and return 0 - success).
+     */
+    virtual status_t submit(MediaAnalyticsItem *item) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -59,10 +56,15 @@
 class BnMediaAnalyticsService: public BnInterface<IMediaAnalyticsService>
 {
 public:
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
+    status_t onTransact(uint32_t code,
+                        const Parcel& data,
+                        Parcel* reply,
+                        uint32_t flags = 0) override;
+
+protected:
+    // Internal call where release is true if the service is to delete the item.
+    virtual status_t submitInternal(
+            MediaAnalyticsItem *item, bool release) = 0;
 };
 
 }; // namespace android
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 4a36f6a..5558211 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_MEDIA_MEDIAANALYTICSITEM_H
 #define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
 
+#include "MediaMetrics.h"
+
+#include <algorithm>
 #include <string>
 #include <sys/types.h>
 
@@ -32,18 +35,50 @@
 class IMediaAnalyticsService;
 class Parcel;
 
-// the class interface
-//
+/*
+ * Media Metrics
+ * Byte String format for communication of MediaAnalyticsItem.
+ *
+ * .... begin of item
+ * .... begin of header
+ * (uint32) length: including the length field itself
+ * (uint32) header length, including header_length and length fields.
+ * (uint16) version: 0
+ * (uint16) key length, including zero termination
+ * (int8)+ key string, including 0 termination
+ * (int32) pid
+ * (int32) uid
+ * (int64) timestamp
+ * .... end of header
+ * .... begin body
+ * (uint32) properties
+ * #properties of the following:
+ *     (uint16) property_length, including property_length field itself
+ *     (uint8) type of property
+ *     (int8)+ key string, including 0 termination
+ *      based on type of property (above), one of:
+ *       (int32)
+ *       (int64)
+ *       (double)
+ *       (int8)+ for cstring, including 0 termination
+ *       (int64, int64) for rate
+ * .... end body
+ * .... end of item
+ */
+
+/**
+ * Media Metrics MediaAnalyticsItem
+ *
+ * A mutable item representing an event or record that will be
+ * logged with the Media Metrics service.
+ *
+ */
 
 class MediaAnalyticsItem {
+    friend class MediaMetricsJNI;           // TODO: remove this access
+    friend class MediaMetricsDeathNotifier; // for dropInstance
 
-    friend class MediaAnalyticsService;
-    friend class IMediaAnalyticsService;
-    friend class MediaMetricsJNI;
-    friend class MetricsSummarizer;
-    friend class MediaMetricsDeathNotifier;
-
-    public:
+public:
 
             enum Type {
                 kTypeNone = 0,
@@ -54,26 +89,8 @@
                 kTypeRate = 5,
             };
 
-        // sessionid
-        // unique within device, within boot,
-        typedef int64_t SessionID_t;
-        static constexpr SessionID_t SessionIDInvalid = -1;
-        static constexpr SessionID_t SessionIDNone = 0;
-
-        // Key: the record descriminator
-        // values for the record discriminator
-        // values can be "component/component"
-        // basic values: "video", "audio", "drm"
-        // XXX: need to better define the format
-        typedef std::string Key;
-        static const Key kKeyNone;              // ""
-        static const Key kKeyAny;               // "*"
-
-        // Attr: names for attributes within a record
-        // format "prop1" or "prop/subprop"
-        // XXX: need to better define the format
-        typedef const char *Attr;
-
+    static constexpr const char * const kKeyNone = "none";
+    static constexpr const char * const kKeyAny = "any";
 
         enum {
             PROTO_V0 = 0,
@@ -82,82 +99,160 @@
             PROTO_LAST = PROTO_V1,
         };
 
-    private:
-        // use the ::create() method instead
-        MediaAnalyticsItem();
-        MediaAnalyticsItem(Key);
-        MediaAnalyticsItem(const MediaAnalyticsItem&);
-        MediaAnalyticsItem &operator=(const MediaAnalyticsItem&);
+    // T must be convertible to mKey
+    template <typename T>
+    explicit MediaAnalyticsItem(T key)
+        : mKey(key) { }
+    MediaAnalyticsItem() = default;
 
-    public:
+    MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
+    MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;
 
-        static MediaAnalyticsItem* create(Key key);
-        static MediaAnalyticsItem* create();
+    bool operator==(const MediaAnalyticsItem& other) const {
+        if (mPropCount != other.mPropCount
+            || mPid != other.mPid
+            || mUid != other.mUid
+            || mPkgName != other.mPkgName
+            || mPkgVersionCode != other.mPkgVersionCode
+            || mKey != other.mKey
+            || mTimestamp != other.mTimestamp) return false;
+         for (size_t i = 0; i < mPropCount; ++i) {
+             Prop *p = other.findProp(mProps[i].getName());
+             if (p == nullptr || mProps[i] != *p) return false;
+         }
+         return true;
+    }
+    bool operator!=(const MediaAnalyticsItem& other) const {
+        return !(*this == other);
+    }
+
+    template <typename T>
+    static MediaAnalyticsItem* create(T key) {
+        return new MediaAnalyticsItem(key);
+    }
+    static MediaAnalyticsItem* create() {
+        return new MediaAnalyticsItem();
+    }
+
+        static MediaAnalyticsItem* convert(mediametrics_handle_t);
+        static mediametrics_handle_t convert(MediaAnalyticsItem *);
 
         // access functions for the class
         ~MediaAnalyticsItem();
 
-        // SessionID ties multiple submissions for same key together
-        // so that if video "height" and "width" are known at one point
-        // and "framerate" is only known later, they can be be brought
-        // together.
-        MediaAnalyticsItem &setSessionID(SessionID_t);
-        MediaAnalyticsItem &clearSessionID();
-        SessionID_t getSessionID() const;
-        // generates and stores a new ID iff mSessionID == SessionIDNone
-        SessionID_t generateSessionID();
-
         // reset all contents, discarding any extra data
         void clear();
         MediaAnalyticsItem *dup();
 
-        // set the key discriminator for the record.
-        // most often initialized as part of the constructor
-        MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
-        MediaAnalyticsItem::Key getKey();
+    MediaAnalyticsItem &setKey(const char *key) {
+        mKey = key;
+        return *this;
+    }
+    const std::string& getKey() const { return mKey; }
 
-        // # of attributes in the record
-        int32_t count() const;
+    // # of properties in the record
+    size_t count() const { return mPropCount; }
 
-        // set values appropriately
-        void setInt32(Attr, int32_t value);
-        void setInt64(Attr, int64_t value);
-        void setDouble(Attr, double value);
-        void setRate(Attr, int64_t count, int64_t duration);
-        void setCString(Attr, const char *value);
+    template<typename S, typename T>
+    MediaAnalyticsItem &set(S key, T value) {
+        allocateProp(key)->set(value);
+        return *this;
+    }
 
-        // fused get/add/set; if attr wasn't there, it's a simple set.
-        // type-mismatch counts as "wasn't there".
-        void addInt32(Attr, int32_t value);
-        void addInt64(Attr, int64_t value);
-        void addDouble(Attr, double value);
-        void addRate(Attr, int64_t count, int64_t duration);
+    // set values appropriately
+    MediaAnalyticsItem &setInt32(const char *key, int32_t value) {
+        return set(key, value);
+    }
+    MediaAnalyticsItem &setInt64(const char *key, int64_t value) {
+        return set(key, value);
+    }
+    MediaAnalyticsItem &setDouble(const char *key, double value) {
+        return set(key, value);
+    }
+    MediaAnalyticsItem &setRate(const char *key, int64_t count, int64_t duration) {
+        return set(key, std::make_pair(count, duration));
+    }
+    MediaAnalyticsItem &setCString(const char *key, const char *value) {
+        return set(key, value);
+    }
 
-        // find & extract values
-        // return indicates whether attr exists (and thus value filled in)
-        // NULL parameter value suppresses storage of value.
-        bool getInt32(Attr, int32_t *value);
-        bool getInt64(Attr, int64_t *value);
-        bool getDouble(Attr, double *value);
-        bool getRate(Attr, int64_t *count, int64_t *duration, double *rate);
-        // Caller owns the returned string
-        bool getCString(Attr, char **value);
-        bool getString(Attr, std::string *value);
+    // fused get/add/set; if attr wasn't there, it's a simple set.
+    // type-mismatch counts as "wasn't there".
+    template<typename S, typename T>
+    MediaAnalyticsItem &add(S key, T value) {
+        allocateProp(key)->add(value);
+        return *this;
+    }
 
-        // parameter indicates whether to close any existing open
-        // record with same key before establishing a new record
-        // caller retains ownership of 'this'.
-        bool selfrecord(bool);
+    MediaAnalyticsItem &addInt32(const char *key, int32_t value) {
+        return add(key, value);
+    }
+    MediaAnalyticsItem &addInt64(const char *key, int64_t value) {
+        return add(key, value);
+    }
+    MediaAnalyticsItem &addDouble(const char *key, double value) {
+        return add(key, value);
+    }
+    MediaAnalyticsItem &addRate(const char *key, int64_t count, int64_t duration) {
+        return add(key, std::make_pair(count, duration));
+    }
+
+    // find & extract values
+    // return indicates whether attr exists (and thus value filled in)
+    // NULL parameter value suppresses storage of value.
+    template<typename S, typename T>
+    bool get(S key, T *value) const {
+        Prop *prop = findProp(key);
+        return prop != nullptr && prop->get(value);
+    }
+
+    bool getInt32(const char *key, int32_t *value) const {
+        return get(key, value);
+    }
+    bool getInt64(const char *key, int64_t *value) const {
+        return get(key, value);
+    }
+    bool getDouble(const char *key, double *value) const {
+        return get(key, value);
+    }
+    bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
+        std::pair<int64_t, int64_t> value;
+        if (!get(key, &value)) return false;
+        if (count != nullptr) *count = value.first;
+        if (duration != nullptr) *duration = value.second;
+        if (rate != nullptr) {
+            if (value.second != 0) {
+                *rate = (double)value.first / value.second;  // TODO: isn't INF OK?
+            } else {
+                *rate = 0.;
+            }
+        }
+        return true;
+    }
+    // Caller owns the returned string
+    bool getCString(const char *key, char **value) const {
+        const char *cs;
+        if (get(key, &cs)) {
+            *value = cs != nullptr ? strdup(cs) : nullptr;
+            return true;
+        }
+        return false;
+    }
+    bool getString(const char *key, std::string *value) const {
+        return get(key, value);
+    }
+
+        // Deliver the item to MediaMetrics
         bool selfrecord();
 
-        // remove indicated attributes and their values
-        // filterNot() could also be called keepOnly()
-        // return value is # attributes removed
-        // XXX: perhaps 'remove' instead of 'filter'
-        // XXX: filterNot would become 'keep'
-        int32_t filter(int count, Attr attrs[]);
-        int32_t filterNot(int count, Attr attrs[]);
-        int32_t filter(Attr attr);
+    // remove indicated attributes and their values
+    // filterNot() could also be called keepOnly()
+    // return value is # attributes removed
+    // XXX: perhaps 'remove' instead of 'filter'
+    // XXX: filterNot would become 'keep'
+    size_t filter(size_t count, const char *attrs[]);
+    size_t filterNot(size_t count, const char *attrs[]);
+    size_t filter(const char *attr) { return filter(1, &attr); }
 
         // below here are used on server side or to talk to server
         // clients need not worry about these.
@@ -179,26 +274,35 @@
         MediaAnalyticsItem &setPkgVersionCode(int64_t);
         int64_t getPkgVersionCode() const;
 
-        // our serialization code for binder calls
-        int32_t writeToParcel(Parcel *);
-        int32_t readFromParcel(const Parcel&);
+    // our serialization code for binder calls
+    status_t writeToParcel(Parcel *) const;
+    status_t readFromParcel(const Parcel&);
 
-        // supports the stable interface
-        bool dumpAttributes(char **pbuffer, size_t *plength);
+    status_t writeToByteString(char **bufferptr, size_t *length) const;
+    status_t readFromByteString(const char *bufferptr, size_t length);
 
-        std::string toString();
-        std::string toString(int version);
+    static status_t writeToByteString(
+            const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
+    static status_t writeToByteString(
+            const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
+    static status_t writeToByteString(
+            const char *name, double value, char **bufferpptr, char *bufferptrmax);
+    static status_t writeToByteString(
+            const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax);
+    static status_t writeToByteString(
+            const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
+    struct none_t {}; // for kTypeNone
+    static status_t writeToByteString(
+            const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
+
+        std::string toString() const;
+        std::string toString(int version) const;
         const char *toCString();
         const char *toCString(int version);
 
         // are we collecting analytics data
         static bool isEnabled();
 
-    private:
-        // handle Parcel version 0
-        int32_t writeToParcel0(Parcel *);
-        int32_t readFromParcel0(const Parcel&);
-
     protected:
 
         // merge fields from arg into this
@@ -207,64 +311,337 @@
         // caller continues to own 'incoming'
         bool merge(MediaAnalyticsItem *incoming);
 
-        // enabled 1, disabled 0
-        static const char * const EnabledProperty;
-        static const char * const EnabledPropertyPersist;
-        static const int   EnabledProperty_default;
+private:
+    // handle Parcel version 0
+    int32_t writeToParcel0(Parcel *) const;
+    int32_t readFromParcel0(const Parcel&);
+
+    // enabled 1, disabled 0
+    static constexpr const char * const EnabledProperty = "media.metrics.enabled";
+    static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
+    static const int EnabledProperty_default = 1;
+
+    // let's reuse a binder connection
+    static sp<IMediaAnalyticsService> sAnalyticsService;
+    static sp<IMediaAnalyticsService> getInstance();
+    static void dropInstance();
+
+    // checks equality even with nullptr.
+    static bool stringEquals(const char *a, const char *b) {
+        if (a == nullptr) {
+            return b == nullptr;
+        } else {
+            return b != nullptr && strcmp(a, b) == 0;
+        }
+    }
+
+public:
+
+    class Prop {
+    friend class MediaMetricsJNI;           // TODO: remove this access
+    public:
+        Prop() = default;
+        Prop(const Prop& other) {
+           *this = other;
+        }
+        Prop& operator=(const Prop& other) {
+            if (other.mName != nullptr) {
+                mName = strdup(other.mName);
+            } else {
+                mName = nullptr;
+            }
+            mType = other.mType;
+            switch (mType) {
+            case kTypeInt32:
+                u.int32Value = other.u.int32Value;
+                break;
+            case kTypeInt64:
+                u.int64Value = other.u.int64Value;
+                break;
+            case kTypeDouble:
+                u.doubleValue = other.u.doubleValue;
+                break;
+            case kTypeCString:
+                u.CStringValue = strdup(other.u.CStringValue);
+                break;
+            case kTypeRate:
+                u.rate = other.u.rate;
+                break;
+            case kTypeNone:
+                break;
+            default:
+                // abort?
+                break;
+            }
+            return *this;
+        }
+        bool operator==(const Prop& other) const {
+            if (!stringEquals(mName, other.mName)
+                    || mType != other.mType) return false;
+            switch (mType) {
+            case kTypeInt32:
+                return u.int32Value == other.u.int32Value;
+            case kTypeInt64:
+                return u.int64Value == other.u.int64Value;
+            case kTypeDouble:
+                return u.doubleValue == other.u.doubleValue;
+            case kTypeCString:
+                return stringEquals(u.CStringValue, other.u.CStringValue);
+            case kTypeRate:
+                return u.rate == other.u.rate;
+            case kTypeNone:
+            default:
+                return true;
+            }
+        }
+        bool operator!=(const Prop& other) const {
+            return !(*this == other);
+        }
+
+        void clear() {
+            free(mName);
+            mName = nullptr;
+            clearValue();
+        }
+        void clearValue() {
+            if (mType == kTypeCString) {
+                free(u.CStringValue);
+                u.CStringValue = nullptr;
+            }
+            mType = kTypeNone;
+        }
+
+        Type getType() const {
+            return mType;
+        }
+
+        const char *getName() const {
+            return mName;
+        }
+
+        void swap(Prop& other) {
+            std::swap(mName, other.mName);
+            std::swap(mType, other.mType);
+            std::swap(u, other.u);
+        }
+
+        void setName(const char *name) {
+            free(mName);
+            if (name != nullptr) {
+                mName = strdup(name);
+            } else {
+                mName = nullptr;
+            }
+        }
+
+        bool isNamed(const char *name) const {
+            return strcmp(name, mName) == 0;
+        }
+
+        template <typename T> bool get(T *value) const = delete;
+        template <>
+        bool get(int32_t *value) const {
+           if (mType != kTypeInt32) return false;
+           if (value != nullptr) *value = u.int32Value;
+           return true;
+        }
+        template <>
+        bool get(int64_t *value) const {
+           if (mType != kTypeInt64) return false;
+           if (value != nullptr) *value = u.int64Value;
+           return true;
+        }
+        template <>
+        bool get(double *value) const {
+           if (mType != kTypeDouble) return false;
+           if (value != nullptr) *value = u.doubleValue;
+           return true;
+        }
+        template <>
+        bool get(const char** value) const {
+            if (mType != kTypeCString) return false;
+            if (value != nullptr) *value = u.CStringValue;
+            return true;
+        }
+        template <>
+        bool get(std::string* value) const {
+            if (mType != kTypeCString) return false;
+            if (value != nullptr) *value = u.CStringValue;
+            return true;
+        }
+        template <>
+        bool get(std::pair<int64_t, int64_t> *value) const {
+           if (mType != kTypeRate) return false;
+           if (value != nullptr) {
+               *value = u.rate;
+           }
+           return true;
+        }
+
+        template <typename T> void set(const T& value) = delete;
+        template <>
+        void set(const int32_t& value) {
+            mType = kTypeInt32;
+            u.int32Value = value;
+        }
+        template <>
+        void set(const int64_t& value) {
+            mType = kTypeInt64;
+            u.int64Value = value;
+        }
+        template <>
+        void set(const double& value) {
+            mType = kTypeDouble;
+            u.doubleValue = value;
+        }
+        template <>
+        void set(const char* const& value) {
+            if (mType == kTypeCString) {
+                free(u.CStringValue);
+            } else {
+                mType = kTypeCString;
+            }
+            if (value == nullptr) {
+                u.CStringValue = nullptr;
+            } else {
+                size_t len = strlen(value);
+                if (len > UINT16_MAX - 1) {
+                    len = UINT16_MAX - 1;
+                }
+                u.CStringValue = (char *)malloc(len + 1);
+                strncpy(u.CStringValue, value, len);
+                u.CStringValue[len] = 0;
+            }
+        }
+        template <>
+        void set(const std::pair<int64_t, int64_t> &value) {
+            mType = kTypeRate;
+            u.rate = {value.first, value.second};
+        }
+
+        template <typename T> void add(const T& value) = delete;
+        template <>
+        void add(const int32_t& value) {
+            if (mType == kTypeInt32) {
+                u.int32Value += value;
+            } else {
+                mType = kTypeInt32;
+                u.int32Value = value;
+            }
+        }
+        template <>
+        void add(const int64_t& value) {
+            if (mType == kTypeInt64) {
+                u.int64Value += value;
+            } else {
+                mType = kTypeInt64;
+                u.int64Value = value;
+            }
+        }
+        template <>
+        void add(const double& value) {
+            if (mType == kTypeDouble) {
+                u.doubleValue += value;
+            } else {
+                mType = kTypeDouble;
+                u.doubleValue = value;
+            }
+        }
+        template <>
+        void add(const std::pair<int64_t, int64_t>& value) {
+            if (mType == kTypeRate) {
+                u.rate.first += value.first;
+                u.rate.second += value.second;
+            } else {
+                mType = kTypeRate;
+                u.rate = value;
+            }
+        }
+
+        status_t writeToParcel(Parcel *data) const;
+        status_t readFromParcel(const Parcel& data);
+        void toString(char *buffer, size_t length) const;
+        size_t getByteStringSize() const;
+        status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
+        status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
+
+    // TODO: make private (and consider converting to std::variant)
+    // private:
+        char *mName = nullptr;
+        Type mType = kTypeNone;
+        union u__ {
+            u__() { zero(); }
+            u__(u__ &&other) {
+                *this = std::move(other);
+            }
+            u__& operator=(u__ &&other) {
+                memcpy(this, &other, sizeof(*this));
+                other.zero();
+                return *this;
+            }
+            void zero() { memset(this, 0, sizeof(*this)); }
+
+            int32_t int32Value;
+            int64_t int64Value;
+            double doubleValue;
+            char *CStringValue;
+            std::pair<int64_t, int64_t> rate;
+        } u;
+    };
+
+    class iterator {
+    public:
+       iterator(size_t pos, const MediaAnalyticsItem &_item)
+           : i(std::min(pos, _item.count()))
+           , item(_item) { }
+       iterator &operator++() {
+           i = std::min(i + 1, item.count());
+           return *this;
+       }
+       bool operator!=(iterator &other) const {
+           return i != other.i;
+       }
+       Prop &operator*() const {
+           return item.mProps[i];
+       }
 
     private:
+      size_t i;
+      const MediaAnalyticsItem &item;
+    };
 
-        // to help validate that A doesn't mess with B's records
-        pid_t     mPid;
-        uid_t     mUid;
-        std::string   mPkgName;
-        int64_t   mPkgVersionCode;
+    iterator begin() const {
+        return iterator(0, *this);
+    }
+    iterator end() const {
+        return iterator(SIZE_MAX, *this);
+    }
 
-        // let's reuse a binder connection
-        static sp<IMediaAnalyticsService> sAnalyticsService;
-        static sp<IMediaAnalyticsService> getInstance();
-        static void dropInstance();
+private:
 
-        // tracking information
-        SessionID_t mSessionID;         // grouping similar records
-        nsecs_t mTimestamp;             // ns, system_time_monotonic
+    // TODO: make prop management class
+    size_t findPropIndex(const char *name) const;
+    Prop *findProp(const char *name) const;
+    Prop *allocateProp();
 
-        // will this record accept further updates
-        bool mFinalized;
-
-        Key mKey;
-
-        struct Prop {
-
-            Type mType;
-            const char *mName;
-            size_t mNameLen;    // the strlen(), doesn't include the null
-            union {
-                    int32_t int32Value;
-                    int64_t int64Value;
-                    double doubleValue;
-                    char *CStringValue;
-                    struct { int64_t count, duration; } rate;
-            } u;
-            void setName(const char *name, size_t len);
-        };
-
-        void initProp(Prop *item);
-        void clearProp(Prop *item);
-        void clearPropValue(Prop *item);
-        void copyProp(Prop *dst, const Prop *src);
         enum {
             kGrowProps = 10
         };
         bool growProps(int increment = kGrowProps);
-        size_t findPropIndex(const char *name, size_t len);
-        Prop *findProp(const char *name);
         Prop *allocateProp(const char *name);
         bool removeProp(const char *name);
+    Prop *allocateProp(const std::string& name) { return allocateProp(name.c_str()); }
 
-        size_t mPropCount;
-        size_t mPropSize;
-        Prop *mProps;
+        size_t mPropCount = 0;
+        size_t mPropSize = 0;
+        Prop *mProps = nullptr;
+
+    pid_t         mPid = -1;
+    uid_t         mUid = -1;
+    std::string   mPkgName;
+    int64_t       mPkgVersionCode = 0;
+    std::string   mKey{kKeyNone};
+    nsecs_t       mTimestamp = 0;
 };
 
 } // namespace android
diff --git a/media/libmediametrics/include/MediaMetrics.h b/media/libmediametrics/include/MediaMetrics.h
index a4e1ed2..29fb241 100644
--- a/media/libmediametrics/include/MediaMetrics.h
+++ b/media/libmediametrics/include/MediaMetrics.h
@@ -79,6 +79,7 @@
 // # of attributes set within this record.
 int32_t mediametrics_count(mediametrics_handle_t handle);
 
+mediametrics_handle_t mediametrics_dup(mediametrics_handle_t handle);
 bool mediametrics_selfRecord(mediametrics_handle_t handle);
 
 const char *mediametrics_readable(mediametrics_handle_t handle);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 5301f5c..762ed19 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -39,6 +39,7 @@
         "libpowermanager",
         "libstagefright",
         "libstagefright_foundation",
+        "libstagefright_framecapture_utils",
         "libstagefright_httplive",
         "libutils",
     ],
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 46c130f..f2a38dd 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -58,7 +58,9 @@
 #include <media/Metadata.h>
 #include <media/AudioTrack.h>
 #include <media/MemoryLeakTrackUtil.h>
+#include <media/stagefright/FrameCaptureProcessor.h>
 #include <media/stagefright/InterfaceUtils.h>
+#include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
@@ -265,6 +267,172 @@
     return ok;
 }
 
+static void dumpCodecDetails(int fd, const sp<IMediaCodecList> &codecList, bool queryDecoders) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    const char *codecType = queryDecoders? "Decoder" : "Encoder";
+    snprintf(buffer, SIZE - 1, "\n%s infos by media types:\n"
+             "=============================\n", codecType);
+    result.append(buffer);
+
+    size_t numCodecs = codecList->countCodecs();
+
+    // gather all media types supported by codec class, and link to codecs that support them
+    KeyedVector<AString, Vector<sp<MediaCodecInfo>>> allMediaTypes;
+    for (size_t codec_ix = 0; codec_ix < numCodecs; ++codec_ix) {
+        sp<MediaCodecInfo> info = codecList->getCodecInfo(codec_ix);
+        if (info->isEncoder() == !queryDecoders) {
+            Vector<AString> supportedMediaTypes;
+            info->getSupportedMediaTypes(&supportedMediaTypes);
+            if (!supportedMediaTypes.size()) {
+                snprintf(buffer, SIZE - 1, "warning: %s does not support any media types\n",
+                        info->getCodecName());
+                result.append(buffer);
+            } else {
+                for (const AString &mediaType : supportedMediaTypes) {
+                    if (allMediaTypes.indexOfKey(mediaType) < 0) {
+                        allMediaTypes.add(mediaType, Vector<sp<MediaCodecInfo>>());
+                    }
+                    allMediaTypes.editValueFor(mediaType).add(info);
+                }
+            }
+        }
+    }
+
+    KeyedVector<AString, bool> visitedCodecs;
+    for (size_t type_ix = 0; type_ix < allMediaTypes.size(); ++type_ix) {
+        const AString &mediaType = allMediaTypes.keyAt(type_ix);
+        snprintf(buffer, SIZE - 1, "\nMedia type '%s':\n", mediaType.c_str());
+        result.append(buffer);
+
+        for (const sp<MediaCodecInfo> &info : allMediaTypes.valueAt(type_ix)) {
+            sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mediaType.c_str());
+            if (caps == NULL) {
+                snprintf(buffer, SIZE - 1, "warning: %s does not have capabilities for type %s\n",
+                        info->getCodecName(), mediaType.c_str());
+                result.append(buffer);
+                continue;
+            }
+            snprintf(buffer, SIZE - 1, "  %s \"%s\" supports\n",
+                       codecType, info->getCodecName());
+            result.append(buffer);
+
+            auto printList = [&](const char *type, const Vector<AString> &values){
+                snprintf(buffer, SIZE - 1, "    %s: [", type);
+                result.append(buffer);
+                for (size_t j = 0; j < values.size(); ++j) {
+                    snprintf(buffer, SIZE - 1, "\n      %s%s", values[j].c_str(),
+                            j == values.size() - 1 ? " " : ",");
+                    result.append(buffer);
+                }
+                result.append("]\n");
+            };
+
+            if (visitedCodecs.indexOfKey(info->getCodecName()) < 0) {
+                visitedCodecs.add(info->getCodecName(), true);
+                {
+                    Vector<AString> aliases;
+                    info->getAliases(&aliases);
+                    // quote alias
+                    for (AString &alias : aliases) {
+                        alias.insert("\"", 1, 0);
+                        alias.append('"');
+                    }
+                    printList("aliases", aliases);
+                }
+                {
+                    uint32_t attrs = info->getAttributes();
+                    Vector<AString> list;
+                    list.add(AStringPrintf("encoder: %d",
+                                           !!(attrs & MediaCodecInfo::kFlagIsEncoder)));
+                    list.add(AStringPrintf("vendor: %d",
+                                           !!(attrs & MediaCodecInfo::kFlagIsVendor)));
+                    list.add(AStringPrintf("software-only: %d",
+                                           !!(attrs & MediaCodecInfo::kFlagIsSoftwareOnly)));
+                    list.add(AStringPrintf("hw-accelerated: %d",
+                                           !!(attrs & MediaCodecInfo::kFlagIsHardwareAccelerated)));
+                    printList(AStringPrintf("attributes: %#x", attrs).c_str(), list);
+                }
+
+                snprintf(buffer, SIZE - 1, "    owner: \"%s\"\n", info->getOwnerName());
+                result.append(buffer);
+                snprintf(buffer, SIZE - 1, "    rank: %u\n", info->getRank());
+                result.append(buffer);
+            } else {
+                result.append("    aliases, attributes, owner, rank: see above\n");
+            }
+
+            {
+                Vector<AString> list;
+                Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+                caps->getSupportedProfileLevels(&profileLevels);
+                for (const MediaCodecInfo::ProfileLevel &pl : profileLevels) {
+                    const char *niceProfile =
+                        mediaType.equalsIgnoreCase(MIMETYPE_AUDIO_AAC)
+                            ? asString_AACObject(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2)
+                            ? asString_MPEG2Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263)
+                            ? asString_H263Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4)
+                            ? asString_MPEG4Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC)
+                            ? asString_AVCProfile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8)
+                            ? asString_VP8Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC)
+                            ? asString_HEVCProfile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9)
+                            ? asString_VP9Profile(pl.mProfile) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1)
+                            ? asString_AV1Profile(pl.mProfile) : "??";
+                    const char *niceLevel =
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2)
+                            ? asString_MPEG2Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263)
+                            ? asString_H263Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4)
+                            ? asString_MPEG4Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC)
+                            ? asString_AVCLevel(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8)
+                            ? asString_VP8Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC)
+                            ? asString_HEVCTierLevel(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9)
+                            ? asString_VP9Level(pl.mLevel) :
+                        mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1)
+                            ? asString_AV1Level(pl.mLevel) : "??";
+
+                    list.add(AStringPrintf("% 5u/% 5u (%s/%s)",
+                            pl.mProfile, pl.mLevel, niceProfile, niceLevel));
+                }
+                printList("profile/levels", list);
+            }
+
+            {
+                Vector<AString> list;
+                Vector<uint32_t> colors;
+                caps->getSupportedColorFormats(&colors);
+                for (uint32_t color : colors) {
+                    list.add(AStringPrintf("%#x (%s)", color,
+                            asString_ColorFormat((int32_t)color)));
+                }
+                printList("colors", list);
+            }
+
+            result.append("    details: ");
+            result.append(caps->getDetails()->debugString(6).c_str());
+            result.append("\n");
+        }
+    }
+    result.append("\n");
+    ::write(fd, result.string(), result.size());
+}
+
+
 // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
 /* static */ int MediaPlayerService::AudioOutput::mMinBufferCount = 4;
 /* static */ bool MediaPlayerService::AudioOutput::mIsOnEmulator = false;
@@ -280,6 +448,8 @@
     mNextConnId = 1;
 
     MediaPlayerFactory::registerBuiltinFactories();
+    // initialize the frame capture utilities
+    (void)FrameCaptureProcessor::getInstance();
 }
 
 MediaPlayerService::~MediaPlayerService()
@@ -424,7 +594,7 @@
     SortedVector< sp<MediaRecorderClient> > mediaRecorderClients;
 
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: "
+        snprintf(buffer, SIZE - 1, "Permission Denial: "
                 "can't dump MediaPlayerService from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
@@ -453,11 +623,11 @@
         }
 
         result.append(" Files opened and/or mapped:\n");
-        snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
+        snprintf(buffer, SIZE - 1, "/proc/%d/maps", getpid());
         FILE *f = fopen(buffer, "r");
         if (f) {
             while (!feof(f)) {
-                fgets(buffer, SIZE, f);
+                fgets(buffer, SIZE - 1, f);
                 if (strstr(buffer, " /storage/") ||
                     strstr(buffer, " /system/sounds/") ||
                     strstr(buffer, " /data/") ||
@@ -473,13 +643,13 @@
             result.append("\n");
         }
 
-        snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
+        snprintf(buffer, SIZE - 1, "/proc/%d/fd", getpid());
         DIR *d = opendir(buffer);
         if (d) {
             struct dirent *ent;
             while((ent = readdir(d)) != NULL) {
                 if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
-                    snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
+                    snprintf(buffer, SIZE - 1, "/proc/%d/fd/%s", getpid(), ent->d_name);
                     struct stat s;
                     if (lstat(buffer, &s) == 0) {
                         if ((s.st_mode & S_IFMT) == S_IFLNK) {
@@ -522,6 +692,10 @@
 
         gLooperRoster.dump(fd, args);
 
+        sp<IMediaCodecList> codecList = getCodecList();
+        dumpCodecDetails(fd, codecList, true /* decoders */);
+        dumpCodecDetails(fd, codecList, false /* !decoders */);
+
         bool dumpMem = false;
         bool unreachableMemory = false;
         for (size_t i = 0; i < args.size(); i++) {
@@ -544,6 +718,7 @@
         }
     }
     write(fd, result.string(), result.size());
+
     return NO_ERROR;
 }
 
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 703da4b..c61ed1b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -32,6 +32,7 @@
 #include <cutils/atomic.h>
 #include <cutils/properties.h> // for property_get
 #include <gui/IGraphicBufferProducer.h>
+#include <mediautils/ServiceUtilities.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <system/audio.h>
@@ -44,7 +45,6 @@
 namespace android {
 
 const char* cameraPermission = "android.permission.CAMERA";
-const char* recordAudioPermission = "android.permission.RECORD_AUDIO";
 
 static bool checkPermission(const char* permissionString) {
     if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
@@ -118,7 +118,16 @@
 status_t MediaRecorderClient::setAudioSource(int as)
 {
     ALOGV("setAudioSource(%d)", as);
-    if (!checkPermission(recordAudioPermission)) {
+    if (as < AUDIO_SOURCE_DEFAULT
+            || (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
+        ALOGE("Invalid audio source: %d", as);
+        return BAD_VALUE;
+    }
+    pid_t pid = IPCThreadState::self()->getCallingPid();
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+
+    if ((as == AUDIO_SOURCE_FM_TUNER && !captureAudioOutputAllowed(pid, uid))
+            || !recordingAllowed(String16(""), pid, uid)) {
         return PERMISSION_DENIED;
     }
     Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 4dbab0a..fb228ca 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -243,31 +243,27 @@
     sp<IMemory> frame = mRetriever->getImageRectAtIndex(
             index, colorFormat, left, top, right, bottom);
     if (frame == NULL) {
-        ALOGE("failed to extract image");
-        return NULL;
+        ALOGE("failed to extract image at index %d", index);
     }
     return frame;
 }
 
-status_t MetadataRetrieverClient::getFrameAtIndex(
-            std::vector<sp<IMemory> > *frames,
-            int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
-    ALOGV("getFrameAtIndex: frameIndex(%d), numFrames(%d), colorFormat(%d), metaOnly(%d)",
-            frameIndex, numFrames, colorFormat, metaOnly);
+sp<IMemory> MetadataRetrieverClient::getFrameAtIndex(
+            int index, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: index(%d), colorFormat(%d), metaOnly(%d)",
+            index, colorFormat, metaOnly);
     Mutex::Autolock lock(mLock);
     Mutex::Autolock glock(sLock);
     if (mRetriever == NULL) {
         ALOGE("retriever is not initialized");
-        return INVALID_OPERATION;
+        return NULL;
     }
 
-    status_t err = mRetriever->getFrameAtIndex(
-            frames, frameIndex, numFrames, colorFormat, metaOnly);
-    if (err != OK) {
-        frames->clear();
-        return err;
+    sp<IMemory> frame = mRetriever->getFrameAtIndex(index, colorFormat, metaOnly);
+    if (frame == NULL) {
+        ALOGE("failed to extract frame at index %d", index);
     }
-    return OK;
+    return frame;
 }
 
 sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
@@ -297,7 +293,7 @@
         delete albumArt;
         return NULL;
     }
-    MediaAlbumArt::init((MediaAlbumArt *) mAlbumArt->pointer(),
+    MediaAlbumArt::init((MediaAlbumArt *) mAlbumArt->unsecurePointer(),
                         albumArt->size(), albumArt->data());
     delete albumArt;  // We've taken our copy.
     return mAlbumArt;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 272d093..8020441 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -56,9 +56,8 @@
             int index, int colorFormat, bool metaOnly, bool thumbnail);
     virtual sp<IMemory>             getImageRectAtIndex(
             int index, int colorFormat, int left, int top, int right, int bottom);
-    virtual status_t getFrameAtIndex(
-                std::vector<sp<IMemory> > *frames,
-                int frameIndex, int numFrames, int colorFormat, bool metaOnly);
+    virtual sp<IMemory>             getFrameAtIndex(
+            int index, int colorFormat, bool metaOnly);
     virtual sp<IMemory>             extractAlbumArt();
     virtual const char*             extractMetadata(int keyCode);
 
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 1aae241..41b6f72 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -44,7 +44,7 @@
 StagefrightMetadataRetriever::StagefrightMetadataRetriever()
     : mParsedMetaData(false),
       mAlbumArt(NULL),
-      mLastImageIndex(-1) {
+      mLastDecodedIndex(-1) {
     ALOGV("StagefrightMetadataRetriever()");
 }
 
@@ -144,8 +144,8 @@
 
     FrameRect rect = {left, top, right, bottom};
 
-    if (mImageDecoder != NULL && index == mLastImageIndex) {
-        return mImageDecoder->extractFrame(&rect);
+    if (mDecoder != NULL && index == mLastDecodedIndex) {
+        return mDecoder->extractFrame(&rect);
     }
 
     return getImageInternal(
@@ -154,6 +154,8 @@
 
 sp<IMemory> StagefrightMetadataRetriever::getImageInternal(
         int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect) {
+    mDecoder.clear();
+    mLastDecodedIndex = -1;
 
     if (mExtractor.get() == NULL) {
         ALOGE("no extractor.");
@@ -228,14 +230,14 @@
         const AString &componentName = matchingCodecs[i];
         sp<ImageDecoder> decoder = new ImageDecoder(componentName, trackMeta, source);
         int64_t frameTimeUs = thumbnail ? -1 : 0;
-        if (decoder->init(frameTimeUs, 1 /*numFrames*/, 0 /*option*/, colorFormat) == OK) {
+        if (decoder->init(frameTimeUs, 0 /*option*/, colorFormat) == OK) {
             sp<IMemory> frame = decoder->extractFrame(rect);
 
             if (frame != NULL) {
                 if (rect != NULL) {
                     // keep the decoder if slice decoding
-                    mImageDecoder = decoder;
-                    mLastImageIndex = index;
+                    mDecoder = decoder;
+                    mLastDecodedIndex = index;
                 }
                 return frame;
             }
@@ -243,6 +245,7 @@
         ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName.c_str());
     }
 
+    ALOGE("all codecs failed to extract frame.");
     return NULL;
 }
 
@@ -251,36 +254,40 @@
     ALOGV("getFrameAtTime: %" PRId64 " us option: %d colorFormat: %d, metaOnly: %d",
             timeUs, option, colorFormat, metaOnly);
 
-    sp<IMemory> frame;
-    status_t err = getFrameInternal(
-            timeUs, 1, option, colorFormat, metaOnly, &frame, NULL /*outFrames*/);
-    return (err == OK) ? frame : NULL;
+    return getFrameInternal(timeUs, option, colorFormat, metaOnly);
 }
 
-status_t StagefrightMetadataRetriever::getFrameAtIndex(
-        std::vector<sp<IMemory> >* frames,
-        int frameIndex, int numFrames, int colorFormat, bool metaOnly) {
-    ALOGV("getFrameAtIndex: frameIndex %d, numFrames %d, colorFormat: %d, metaOnly: %d",
-            frameIndex, numFrames, colorFormat, metaOnly);
+sp<IMemory> StagefrightMetadataRetriever::getFrameAtIndex(
+        int frameIndex, int colorFormat, bool metaOnly) {
+    ALOGV("getFrameAtIndex: frameIndex %d, colorFormat: %d, metaOnly: %d",
+            frameIndex, colorFormat, metaOnly);
+    if (mDecoder != NULL && frameIndex == mLastDecodedIndex + 1) {
+        sp<IMemory> frame = mDecoder->extractFrame();
+        if (frame != nullptr) {
+            mLastDecodedIndex = frameIndex;
+        }
+        return frame;
+    }
 
-    return getFrameInternal(
-            frameIndex, numFrames, MediaSource::ReadOptions::SEEK_FRAME_INDEX,
-            colorFormat, metaOnly, NULL /*outFrame*/, frames);
+    return getFrameInternal(frameIndex,
+            MediaSource::ReadOptions::SEEK_FRAME_INDEX, colorFormat, metaOnly);
 }
 
-status_t StagefrightMetadataRetriever::getFrameInternal(
-        int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
-        sp<IMemory>* outFrame, std::vector<sp<IMemory> >* outFrames) {
+sp<IMemory> StagefrightMetadataRetriever::getFrameInternal(
+        int64_t timeUs, int option, int colorFormat, bool metaOnly) {
+    mDecoder.clear();
+    mLastDecodedIndex = -1;
+
     if (mExtractor.get() == NULL) {
         ALOGE("no extractor.");
-        return NO_INIT;
+        return NULL;
     }
 
     sp<MetaData> fileMeta = mExtractor->getMetaData();
 
     if (fileMeta == NULL) {
         ALOGE("extractor doesn't publish metadata, failed to initialize?");
-        return NO_INIT;
+        return NULL;
     }
 
     size_t n = mExtractor->countTracks();
@@ -301,30 +308,24 @@
 
     if (i == n) {
         ALOGE("no video track found.");
-        return INVALID_OPERATION;
+        return NULL;
     }
 
     sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
             i, MediaExtractor::kIncludeExtensiveMetaData);
     if (!trackMeta) {
-        return UNKNOWN_ERROR;
+        return NULL;
     }
 
     if (metaOnly) {
-        if (outFrame != NULL) {
-            *outFrame = FrameDecoder::getMetadataOnly(trackMeta, colorFormat);
-            if (*outFrame != NULL) {
-                return OK;
-            }
-        }
-        return UNKNOWN_ERROR;
+        return FrameDecoder::getMetadataOnly(trackMeta, colorFormat);
     }
 
     sp<IMediaSource> source = mExtractor->getTrack(i);
 
     if (source.get() == NULL) {
         ALOGV("unable to instantiate video track.");
-        return UNKNOWN_ERROR;
+        return NULL;
     }
 
     const void *data;
@@ -351,24 +352,22 @@
     for (size_t i = 0; i < matchingCodecs.size(); ++i) {
         const AString &componentName = matchingCodecs[i];
         sp<VideoFrameDecoder> decoder = new VideoFrameDecoder(componentName, trackMeta, source);
-        if (decoder->init(timeUs, numFrames, option, colorFormat) == OK) {
-            if (outFrame != NULL) {
-                *outFrame = decoder->extractFrame();
-                if (*outFrame != NULL) {
-                    return OK;
+        if (decoder->init(timeUs, option, colorFormat) == OK) {
+            sp<IMemory> frame = decoder->extractFrame();
+            if (frame != nullptr) {
+                // keep the decoder if seeking by frame index
+                if (option == MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
+                    mDecoder = decoder;
+                    mLastDecodedIndex = timeUs;
                 }
-            } else if (outFrames != NULL) {
-                status_t err = decoder->extractFrames(outFrames);
-                if (err == OK) {
-                    return OK;
-                }
+                return frame;
             }
         }
         ALOGV("%s failed to extract frame, trying next decoder.", componentName.c_str());
     }
 
     ALOGE("all codecs failed to extract frame.");
-    return UNKNOWN_ERROR;
+    return NULL;
 }
 
 MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.h b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
index c50677a..ee51290 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.h
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
@@ -26,7 +26,7 @@
 namespace android {
 
 class DataSource;
-struct ImageDecoder;
+struct FrameDecoder;
 struct FrameRect;
 
 struct StagefrightMetadataRetriever : public MediaMetadataRetrieverBase {
@@ -47,9 +47,8 @@
             int index, int colorFormat, bool metaOnly, bool thumbnail);
     virtual sp<IMemory> getImageRectAtIndex(
             int index, int colorFormat, int left, int top, int right, int bottom);
-    virtual status_t getFrameAtIndex(
-            std::vector<sp<IMemory> >* frames,
-            int frameIndex, int numFrames, int colorFormat, bool metaOnly);
+    virtual sp<IMemory> getFrameAtIndex(
+            int index, int colorFormat, bool metaOnly);
 
     virtual MediaAlbumArt *extractAlbumArt();
     virtual const char *extractMetadata(int keyCode);
@@ -62,17 +61,17 @@
     KeyedVector<int, String8> mMetaData;
     MediaAlbumArt *mAlbumArt;
 
-    sp<ImageDecoder> mImageDecoder;
-    int mLastImageIndex;
+    sp<FrameDecoder> mDecoder;
+    int mLastDecodedIndex;
     void parseMetaData();
     void parseColorAspects(const sp<MetaData>& meta);
     // Delete album art and clear metadata.
     void clearMetadata();
 
-    status_t getFrameInternal(
-            int64_t timeUs, int numFrames, int option, int colorFormat, bool metaOnly,
-            sp<IMemory>* outFrame, std::vector<sp<IMemory> >* outFrames);
-    virtual sp<IMemory> getImageInternal(
+    sp<IMemory> getFrameInternal(
+            int64_t timeUs, int option, int colorFormat, bool metaOnly);
+
+    sp<IMemory> getImageInternal(
             int index, int colorFormat, bool metaOnly, bool thumbnail, FrameRect* rect);
 
     StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 63681fa..954ccc9 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -232,11 +232,6 @@
 
 status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
     ALOGV("setAudioSource: %d", as);
-    if (as < AUDIO_SOURCE_DEFAULT ||
-        (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
-        ALOGE("Invalid audio source: %d", as);
-        return BAD_VALUE;
-    }
 
     if (as == AUDIO_SOURCE_DEFAULT) {
         mAudioSource = AUDIO_SOURCE_MIC;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index bd2b884..f734439 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -106,16 +106,17 @@
     releaseAndResetMediaBuffers();
 }
 
-sp<AMessage> NuPlayer::Decoder::getStats() const {
+sp<AMessage> NuPlayer::Decoder::getStats() {
 
+    Mutex::Autolock autolock(mStatsLock);
     mStats->setInt64("frames-total", mNumFramesTotal);
     mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
     mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
     mStats->setFloat("frame-rate-total", mFrameRateTotal);
 
-    // i'm mutexed right now.
     // make our own copy, so we aren't victim to any later changes.
     sp<AMessage> copiedStats = mStats->dup();
+
     return copiedStats;
 }
 
@@ -362,13 +363,17 @@
     CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
     CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
 
-    mStats->setString("mime", mime.c_str());
-    mStats->setString("component-name", mComponentName.c_str());
+    {
+        Mutex::Autolock autolock(mStatsLock);
+        mStats->setString("mime", mime.c_str());
+        mStats->setString("component-name", mComponentName.c_str());
+    }
 
     if (!mIsAudio) {
         int32_t width, height;
         if (mOutputFormat->findInt32("width", &width)
                 && mOutputFormat->findInt32("height", &height)) {
+            Mutex::Autolock autolock(mStatsLock);
             mStats->setInt32("width", width);
             mStats->setInt32("height", height);
         }
@@ -799,6 +804,7 @@
         int32_t width, height;
         if (format->findInt32("width", &width)
                 && format->findInt32("height", &height)) {
+            Mutex::Autolock autolock(mStatsLock);
             mStats->setInt32("width", width);
             mStats->setInt32("height", height);
         }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 3da2f0b..4a52b0c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -34,7 +34,7 @@
             const sp<Surface> &surface = NULL,
             const sp<CCDecoder> &ccDecoder = NULL);
 
-    virtual sp<AMessage> getStats() const;
+    virtual sp<AMessage> getStats();
 
     // sets the output surface of video decoders.
     virtual status_t setVideoSurface(const sp<Surface> &surface);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index d44c396..a3e0046 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -47,7 +47,7 @@
     void signalResume(bool notifyComplete);
     void initiateShutdown();
 
-    virtual sp<AMessage> getStats() const {
+    virtual sp<AMessage> getStats() {
         return mStats;
     }
 
@@ -88,6 +88,7 @@
     int32_t mBufferGeneration;
     bool mPaused;
     sp<AMessage> mStats;
+    Mutex mStatsLock;
 
 private:
     enum {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 95c973a..4d9872a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -641,7 +641,7 @@
             mAnalyticsItem->setUid(mClientUid);
         }
     } else {
-        ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count());
+        ALOGV("nothing to record (only %zu fields)", mAnalyticsItem->count());
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index 2d0c9e0..6788b56 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -19,8 +19,7 @@
 
 #include "NuPlayerDrm.h"
 
-#include <binder/IServiceManager.h>
-#include <mediadrm/IMediaDrmService.h>
+#include <mediadrm/DrmUtils.h>
 #include <utils/Log.h>
 
 
@@ -30,60 +29,13 @@
 
 sp<IDrm> NuPlayerDrm::CreateDrm(status_t *pstatus)
 {
-    status_t &status = *pstatus;
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.drm"));
-    ALOGV("CreateDrm binder %p", (binder != NULL ? binder.get() : 0));
-
-    sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
-    if (service == NULL) {
-        ALOGE("CreateDrm failed at IMediaDrmService");
-        return NULL;
-    }
-
-    sp<IDrm> drm = service->makeDrm();
-    if (drm == NULL) {
-        ALOGE("CreateDrm failed at makeDrm");
-        return NULL;
-    }
-
-    // this is before plugin creation so NO_INIT is fine
-    status = drm->initCheck();
-    if (status != OK && status != NO_INIT) {
-        ALOGE("CreateDrm failed drm->initCheck(): %d", status);
-        return NULL;
-    }
-    return drm;
+    return DrmUtils::MakeDrm(pstatus);
 }
 
 sp<ICrypto> NuPlayerDrm::createCrypto(status_t *pstatus)
 {
-    status_t &status = *pstatus;
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.drm"));
 
-    sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
-    if (service == NULL) {
-        status = UNKNOWN_ERROR;
-        ALOGE("CreateCrypto failed at IMediaDrmService");
-        return NULL;
-    }
-
-    sp<ICrypto> crypto = service->makeCrypto();
-    if (crypto == NULL) {
-        status = UNKNOWN_ERROR;
-        ALOGE("createCrypto failed");
-        return NULL;
-    }
-
-    // this is before plugin creation so NO_INIT is fine
-    status = crypto->initCheck();
-    if (status != OK && status != NO_INIT) {
-        ALOGE("createCrypto failed crypto->initCheck(): %d", status);
-        return NULL;
-    }
-
-    return crypto;
+    return DrmUtils::MakeCrypto(pstatus);
 }
 
 Vector<DrmUUID> NuPlayerDrm::parsePSSH(const void *pssh, size_t psshsize)
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 39be40d..c30f048 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -33,6 +33,7 @@
 #include <media/stagefright/Utils.h>
 #include <media/stagefright/VideoFrameScheduler.h>
 #include <media/MediaCodecBuffer.h>
+#include <utils/SystemClock.h>
 
 #include <inttypes.h>
 
@@ -156,6 +157,7 @@
     CHECK(mediaClock != NULL);
     mPlaybackRate = mPlaybackSettings.mSpeed;
     mMediaClock->setPlaybackRate(mPlaybackRate);
+    (void)mSyncFlag.test_and_set();
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -326,9 +328,27 @@
         mSyncQueues = false;
     }
 
+    // Wait until the current job in the message queue is done, to make sure
+    // buffer processing from the old generation is finished. After the current
+    // job is finished, access to buffers are protected by generation.
+    Mutex::Autolock syncLock(mSyncLock);
+    int64_t syncCount = mSyncCount;
+    mSyncFlag.clear();
+
+    // Make sure message queue is not empty after mSyncFlag is cleared.
     sp<AMessage> msg = new AMessage(kWhatFlush, this);
     msg->setInt32("audio", static_cast<int32_t>(audio));
     msg->post();
+
+    int64_t uptimeMs = uptimeMillis();
+    while (mSyncCount == syncCount) {
+        (void)mSyncCondition.waitRelative(mSyncLock, ms2ns(1000));
+        if (uptimeMillis() - uptimeMs > 1000) {
+            ALOGW("flush(): no wake-up from sync point for 1s; stop waiting to "
+                  "prevent being stuck indefinitely.");
+            break;
+        }
+    }
 }
 
 void NuPlayer::Renderer::signalTimeDiscontinuity() {
@@ -781,6 +801,11 @@
             TRESPASS();
             break;
     }
+    if (!mSyncFlag.test_and_set()) {
+        Mutex::Autolock syncLock(mSyncLock);
+        ++mSyncCount;
+        mSyncCondition.broadcast();
+    }
 }
 
 void NuPlayer::Renderer::postDrainAudioQueue_l(int64_t delayUs) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index a521f62..3d2b033 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -18,6 +18,8 @@
 
 #define NUPLAYER_RENDERER_H_
 
+#include <atomic>
+
 #include <media/AudioResamplerPublic.h>
 #include <media/AVSyncSettings.h>
 
@@ -220,6 +222,11 @@
 
     sp<AWakeLock> mWakeLock;
 
+    std::atomic_flag mSyncFlag = ATOMIC_FLAG_INIT;
+    Mutex mSyncLock;
+    Condition mSyncCondition;
+    int64_t mSyncCount{0};
+
     status_t getCurrentPositionOnLooper(int64_t *mediaUs);
     status_t getCurrentPositionOnLooper(
             int64_t *mediaUs, int64_t nowUs, bool allowPastQueuedVideo = false);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
index ee70306..b5142ed 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
@@ -154,7 +154,7 @@
     }
 
     memcpy(data,
-           (const uint8_t *)mem->pointer()
+           (const uint8_t *)mem->unsecurePointer()
             + entry->mOffset,
            copy);
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index bf14ec2..83da092 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -144,6 +144,10 @@
     if (mLooper == NULL) {
         return;
     }
+
+    // Close socket before posting message to RTSPSource message handler.
+    close(mHandler->getARTSPConnection()->getSocket());
+
     sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
 
     sp<AMessage> dummy;
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index afdcd37..f21d2b3 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -130,29 +130,32 @@
         } else if (n < 0) {
             break;
         } else {
-            if (buffer[0] == 0x00) {
+            if (buffer[0] == 0x00) { // OK to access buffer[0] since n must be > 0 here
                 // XXX legacy
 
                 if (extra == NULL) {
                     extra = new AMessage;
                 }
 
-                uint8_t type = buffer[1];
+                uint8_t type = 0;
+                if (n > 1) {
+                    type = buffer[1];
 
-                if (type & 2) {
-                    int64_t mediaTimeUs;
-                    memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
+                    if ((type & 2) && (n >= 2 + sizeof(int64_t))) {
+                        int64_t mediaTimeUs;
+                        memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs));
 
-                    extra->setInt64(kATSParserKeyMediaTimeUs, mediaTimeUs);
+                        extra->setInt64(kATSParserKeyMediaTimeUs, mediaTimeUs);
+                    }
                 }
 
                 mTSParser->signalDiscontinuity(
                         ((type & 1) == 0)
-                            ? ATSParser::DISCONTINUITY_TIME
-                            : ATSParser::DISCONTINUITY_FORMATCHANGE,
+                                ? ATSParser::DISCONTINUITY_TIME
+                                : ATSParser::DISCONTINUITY_FORMATCHANGE,
                         extra);
             } else {
-                status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer));
+                status_t err = mTSParser->feedTSPacket(buffer, n);
 
                 if (err != OK) {
                     ALOGE("TS Parser returned error %d", err);
diff --git a/media/libmediaplayerservice/tests/Android.bp b/media/libmediaplayerservice/tests/Android.bp
index f8c89e5..e845c33 100644
--- a/media/libmediaplayerservice/tests/Android.bp
+++ b/media/libmediaplayerservice/tests/Android.bp
@@ -6,14 +6,27 @@
 
     shared_libs: [
         "liblog",
+        "libbinder",
+        "libbinder_ndk",
+        "libmedia",
         "libmediaplayerservice",
         "libmediadrm",
+        "libresourcemanagerservice",
         "libutils",
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
         "android.hardware.drm@1.2",
     ],
 
+    static_libs: [
+        "resourcemanager_aidl_interface-ndk_platform",
+    ],
+
+    include_dirs: [
+        "frameworks/av/include",
+        "frameworks/av/services/mediaresourcemanager",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
diff --git a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index d81ee05..9a8ed8d 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -16,18 +16,140 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "DrmSessionManager_test"
+#include <android/binder_auto_utils.h>
 #include <utils/Log.h>
 
 #include <gtest/gtest.h>
 
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <aidl/android/media/BnResourceManagerService.h>
+#include <android/media/BnResourceManagerClient.h>
+
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/ProcessInfoInterface.h>
-#include <mediadrm/DrmHal.h>
-#include <mediadrm/DrmSessionClientInterface.h>
 #include <mediadrm/DrmSessionManager.h>
 
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include "ResourceManagerService.h"
+
 namespace android {
 
+using ::android::binder::Status;
+using ::android::media::ResourceManagerService;
+using ::ndk::ScopedAStatus;
+
+using NdkBnResourceManagerClient = ::aidl::android::media::BnResourceManagerClient;
+using NdkBnResourceManagerService = ::aidl::android::media::BnResourceManagerService;
+using NdkMediaResource = ::aidl::android::media::MediaResourceParcel;
+using NdkResourceManagerClient = ::aidl::android::media::IResourceManagerClient;
+
+using FwkBnResourceManagerClient = ::android::media::BnResourceManagerClient;
+using FwkMediaResource = ::android::media::MediaResourceParcel;
+
+namespace {
+
+struct FwkResourceManagerClientImpl : public FwkBnResourceManagerClient {
+    FwkResourceManagerClientImpl(const std::shared_ptr<NdkResourceManagerClient> &client)
+        : mClient(client) {
+    }
+
+    Status reclaimResource(bool* _aidl_return) override {
+        mClient->reclaimResource(_aidl_return);
+        return Status::ok();
+    }
+
+    Status getName(std::string* _aidl_return) override {
+        mClient->getName(_aidl_return);
+        return Status::ok();
+    }
+
+private:
+    std::shared_ptr<NdkResourceManagerClient> mClient;
+};
+
+FwkMediaResource NdkToFwkMediaResource(const NdkMediaResource &in) {
+    FwkMediaResource out{};
+    out.type = static_cast<decltype(out.type)>(in.type);
+    out.subType = static_cast<decltype(out.subType)>(in.subType);
+    auto v(reinterpret_cast<const uint8_t *>(in.id.data()));
+    out.id.assign(v, v + in.id.size());
+    out.value = in.value;
+    return out;
+}
+
+std::vector<FwkMediaResource> NdkToFwkMediaResourceVec(const std::vector<NdkMediaResource> &in) {
+    std::vector<FwkMediaResource> out;
+    for (auto e : in) {
+        out.push_back(NdkToFwkMediaResource(e));
+    }
+    return out;
+}
+
+ScopedAStatus FwkToNdkStatus(Status err) {
+    return ScopedAStatus(AStatus_fromExceptionCode(err.serviceSpecificErrorCode()));
+}
+
+struct NdkResourceManagerServiceImpl : public NdkBnResourceManagerService {
+    using NdkMediaResourcePolicy = ::aidl::android::media::MediaResourcePolicyParcel;
+
+    NdkResourceManagerServiceImpl(const sp<ResourceManagerService> &service)
+        : mService(service) {}
+
+    ScopedAStatus config(const std::vector<NdkMediaResourcePolicy>& in_policies) override {
+        (void)in_policies;
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus addResource(int32_t in_pid, int32_t in_uid, int64_t in_clientId,
+            const std::shared_ptr<NdkResourceManagerClient>& in_client,
+            const std::vector<NdkMediaResource>& in_resources) override {
+        sp<FwkBnResourceManagerClient> client(new FwkResourceManagerClientImpl(in_client));
+        std::vector<FwkMediaResource> resources(NdkToFwkMediaResourceVec(in_resources));
+        auto err = mService->addResource(in_pid, in_uid, in_clientId, client, resources);
+        return FwkToNdkStatus(err);
+    }
+
+    ScopedAStatus removeResource(int32_t in_pid, int64_t in_clientId,
+            const std::vector<NdkMediaResource>& in_resources) override {
+        std::vector<FwkMediaResource> resources(NdkToFwkMediaResourceVec(in_resources));
+        auto err = mService->removeResource(in_pid, in_clientId, resources);
+        return FwkToNdkStatus(err);
+    }
+
+    ScopedAStatus removeClient(int32_t in_pid, int64_t in_clientId) override{
+        auto err = mService->removeClient(in_pid, in_clientId);
+        return FwkToNdkStatus(err);
+    }
+
+    ScopedAStatus reclaimResource(int32_t in_callingPid,
+            const std::vector<NdkMediaResource>& in_resources, bool* _aidl_return) override {
+        std::vector<FwkMediaResource> resources(NdkToFwkMediaResourceVec(in_resources));
+        auto err = mService->reclaimResource(in_callingPid, resources, _aidl_return);
+        return FwkToNdkStatus(err);
+    }
+
+private:
+    sp<ResourceManagerService> mService;
+};
+
+template <typename Impl>
+std::shared_ptr<NdkResourceManagerClient> NdkImplToIface(const Impl &impl) {
+    return std::static_pointer_cast<NdkResourceManagerClient>(impl);
+}
+
+}
+
+static Vector<uint8_t> toAndroidVector(const std::vector<uint8_t> &vec) {
+    Vector<uint8_t> aVec;
+    for (auto b : vec) {
+        aVec.push_back(b);
+    }
+    return aVec;
+}
+
 struct FakeProcessInfo : public ProcessInfoInterface {
     FakeProcessInfo() {}
     virtual ~FakeProcessInfo() {}
@@ -47,173 +169,125 @@
     DISALLOW_EVIL_CONSTRUCTORS(FakeProcessInfo);
 };
 
-struct FakeDrm : public DrmSessionClientInterface {
-    FakeDrm() {}
-    virtual ~FakeDrm() {}
+struct FakeDrm : public NdkBnResourceManagerClient {
+    FakeDrm(const std::vector<uint8_t>& sessionId, const sp<DrmSessionManager>& manager)
+        : mSessionId(toAndroidVector(sessionId)),
+          mReclaimed(false),
+          mDrmSessionManager(manager) {}
 
-    virtual bool reclaimSession(const Vector<uint8_t>& sessionId) {
-        mReclaimedSessions.push_back(sessionId);
-        return true;
+    ScopedAStatus reclaimResource(bool* _aidl_return) {
+        mReclaimed = true;
+        mDrmSessionManager->removeSession(mSessionId);
+        *_aidl_return = true;
+        return ScopedAStatus::ok();
     }
 
-    const Vector<Vector<uint8_t> >& reclaimedSessions() const {
-        return mReclaimedSessions;
+    ScopedAStatus getName(::std::string* _aidl_return) {
+        String8 name("FakeDrm[");
+        for (size_t i = 0; i < mSessionId.size(); ++i) {
+            name.appendFormat("%02x", mSessionId[i]);
+        }
+        name.append("]");
+        *_aidl_return = name;
+        return ScopedAStatus::ok();
     }
 
+    bool isReclaimed() const {
+        return mReclaimed;
+    }
+
+    const Vector<uint8_t> mSessionId;
+
 private:
-    Vector<Vector<uint8_t> > mReclaimedSessions;
+    bool mReclaimed;
+    const sp<DrmSessionManager> mDrmSessionManager;
 
     DISALLOW_EVIL_CONSTRUCTORS(FakeDrm);
 };
 
+struct FakeSystemCallback :
+        public ResourceManagerService::SystemCallbackInterface {
+    FakeSystemCallback() {}
+
+    virtual void noteStartVideo(int /*uid*/) override {}
+
+    virtual void noteStopVideo(int /*uid*/) override {}
+
+    virtual void noteResetVideo() override {}
+
+    virtual bool requestCpusetBoost(
+            bool /*enable*/, const sp<IInterface> &/*client*/) override {
+        return true;
+    }
+
+protected:
+    virtual ~FakeSystemCallback() {}
+
+private:
+
+    DISALLOW_EVIL_CONSTRUCTORS(FakeSystemCallback);
+};
+
 static const int kTestPid1 = 30;
 static const int kTestPid2 = 20;
-static const uint8_t kTestSessionId1[] = {1, 2, 3};
-static const uint8_t kTestSessionId2[] = {4, 5, 6, 7, 8};
-static const uint8_t kTestSessionId3[] = {9, 0};
+static const std::vector<uint8_t> kTestSessionId1{1, 2, 3};
+static const std::vector<uint8_t> kTestSessionId2{4, 5, 6, 7, 8};
+static const std::vector<uint8_t> kTestSessionId3{9, 0};
 
 class DrmSessionManagerTest : public ::testing::Test {
 public:
     DrmSessionManagerTest()
-        : mDrmSessionManager(new DrmSessionManager(new FakeProcessInfo())),
-          mTestDrm1(new FakeDrm()),
-          mTestDrm2(new FakeDrm()) {
-        GetSessionId(kTestSessionId1, ARRAY_SIZE(kTestSessionId1), &mSessionId1);
-        GetSessionId(kTestSessionId2, ARRAY_SIZE(kTestSessionId2), &mSessionId2);
-        GetSessionId(kTestSessionId3, ARRAY_SIZE(kTestSessionId3), &mSessionId3);
+        : mService(new ResourceManagerService(new FakeProcessInfo(), new FakeSystemCallback())),
+          mDrmSessionManager(new DrmSessionManager(std::shared_ptr<NdkBnResourceManagerService>(new NdkResourceManagerServiceImpl(mService)))),
+          mTestDrm1(new FakeDrm(kTestSessionId1, mDrmSessionManager)),
+          mTestDrm2(new FakeDrm(kTestSessionId2, mDrmSessionManager)),
+          mTestDrm3(new FakeDrm(kTestSessionId3, mDrmSessionManager)) {
     }
 
 protected:
-    static void GetSessionId(const uint8_t* ids, size_t num, Vector<uint8_t>* sessionId) {
-        for (size_t i = 0; i < num; ++i) {
-            sessionId->push_back(ids[i]);
-        }
-    }
-
-    static void ExpectEqSessionInfo(const SessionInfo& info, sp<DrmSessionClientInterface> drm,
-            const Vector<uint8_t>& sessionId, int64_t timeStamp) {
-        EXPECT_EQ(drm, info.drm);
-        EXPECT_TRUE(isEqualSessionId(sessionId, info.sessionId));
-        EXPECT_EQ(timeStamp, info.timeStamp);
-    }
-
     void addSession() {
-        mDrmSessionManager->addSession(kTestPid1, mTestDrm1, mSessionId1);
-        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId2);
-        mDrmSessionManager->addSession(kTestPid2, mTestDrm2, mSessionId3);
-        const PidSessionInfosMap& map = sessionMap();
-        EXPECT_EQ(2u, map.size());
-        ssize_t index1 = map.indexOfKey(kTestPid1);
-        ASSERT_GE(index1, 0);
-        const SessionInfos& infos1 = map[index1];
-        EXPECT_EQ(1u, infos1.size());
-        ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 0);
-
-        ssize_t index2 = map.indexOfKey(kTestPid2);
-        ASSERT_GE(index2, 0);
-        const SessionInfos& infos2 = map[index2];
-        EXPECT_EQ(2u, infos2.size());
-        ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId2, 1);
-        ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 2);
+        mDrmSessionManager->addSession(kTestPid1, NdkImplToIface(mTestDrm1), mTestDrm1->mSessionId);
+        mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm2), mTestDrm2->mSessionId);
+        mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm3), mTestDrm3->mSessionId);
     }
 
-    const PidSessionInfosMap& sessionMap() {
-        return mDrmSessionManager->mSessionMap;
-    }
-
-    void testGetLowestPriority() {
-        int pid;
-        int priority;
-        EXPECT_FALSE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
-        addSession();
-        EXPECT_TRUE(mDrmSessionManager->getLowestPriority_l(&pid, &priority));
-
-        EXPECT_EQ(kTestPid1, pid);
-        FakeProcessInfo processInfo;
-        int priority1;
-        processInfo.getPriority(kTestPid1, &priority1);
-        EXPECT_EQ(priority1, priority);
-    }
-
-    void testGetLeastUsedSession() {
-        sp<DrmSessionClientInterface> drm;
-        Vector<uint8_t> sessionId;
-        EXPECT_FALSE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-
-        addSession();
-
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid1, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm1, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId1, sessionId));
-
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm2, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId2, sessionId));
-
-        // mSessionId2 is no longer the least used session.
-        mDrmSessionManager->useSession(mSessionId2);
-        EXPECT_TRUE(mDrmSessionManager->getLeastUsedSession_l(kTestPid2, &drm, &sessionId));
-        EXPECT_EQ(mTestDrm2, drm);
-        EXPECT_TRUE(isEqualSessionId(mSessionId3, sessionId));
-    }
-
+    sp<ResourceManagerService> mService;
     sp<DrmSessionManager> mDrmSessionManager;
-    sp<FakeDrm> mTestDrm1;
-    sp<FakeDrm> mTestDrm2;
-    Vector<uint8_t> mSessionId1;
-    Vector<uint8_t> mSessionId2;
-    Vector<uint8_t> mSessionId3;
+    std::shared_ptr<FakeDrm> mTestDrm1;
+    std::shared_ptr<FakeDrm> mTestDrm2;
+    std::shared_ptr<FakeDrm> mTestDrm3;
 };
 
 TEST_F(DrmSessionManagerTest, addSession) {
     addSession();
+
+    EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 TEST_F(DrmSessionManagerTest, useSession) {
     addSession();
 
-    mDrmSessionManager->useSession(mSessionId1);
-    mDrmSessionManager->useSession(mSessionId3);
+    mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+    mDrmSessionManager->useSession(mTestDrm3->mSessionId);
 
-    const PidSessionInfosMap& map = sessionMap();
-    const SessionInfos& infos1 = map.valueFor(kTestPid1);
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    ExpectEqSessionInfo(infos1[0], mTestDrm1, mSessionId1, 3);
-    ExpectEqSessionInfo(infos2[1], mTestDrm2, mSessionId3, 4);
+    EXPECT_EQ(3u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 TEST_F(DrmSessionManagerTest, removeSession) {
     addSession();
 
-    mDrmSessionManager->removeSession(mSessionId2);
+    mDrmSessionManager->removeSession(mTestDrm2->mSessionId);
 
-    const PidSessionInfosMap& map = sessionMap();
-    EXPECT_EQ(2u, map.size());
-    const SessionInfos& infos1 = map.valueFor(kTestPid1);
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    EXPECT_EQ(1u, infos1.size());
-    EXPECT_EQ(1u, infos2.size());
-    // mSessionId2 has been removed.
-    ExpectEqSessionInfo(infos2[0], mTestDrm2, mSessionId3, 2);
-}
-
-TEST_F(DrmSessionManagerTest, removeDrm) {
-    addSession();
-
-    sp<FakeDrm> drm = new FakeDrm;
-    const uint8_t ids[] = {123};
-    Vector<uint8_t> sessionId;
-    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
-    mDrmSessionManager->addSession(kTestPid2, drm, sessionId);
-
-    mDrmSessionManager->removeDrm(mTestDrm2);
-
-    const PidSessionInfosMap& map = sessionMap();
-    const SessionInfos& infos2 = map.valueFor(kTestPid2);
-    EXPECT_EQ(1u, infos2.size());
-    // mTestDrm2 has been removed.
-    ExpectEqSessionInfo(infos2[0], drm, sessionId, 3);
+    EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 TEST_F(DrmSessionManagerTest, reclaimSession) {
@@ -224,30 +298,63 @@
     EXPECT_FALSE(mDrmSessionManager->reclaimSession(50));
 
     EXPECT_TRUE(mDrmSessionManager->reclaimSession(10));
-    EXPECT_EQ(1u, mTestDrm1->reclaimedSessions().size());
-    EXPECT_TRUE(isEqualSessionId(mSessionId1, mTestDrm1->reclaimedSessions()[0]));
-
-    mDrmSessionManager->removeSession(mSessionId1);
+    EXPECT_TRUE(mTestDrm1->isReclaimed());
 
     // add a session from a higher priority process.
-    sp<FakeDrm> drm = new FakeDrm;
-    const uint8_t ids[] = {1, 3, 5};
-    Vector<uint8_t> sessionId;
-    GetSessionId(ids, ARRAY_SIZE(ids), &sessionId);
-    mDrmSessionManager->addSession(15, drm, sessionId);
+    const std::vector<uint8_t> sid{1, 3, 5};
+    std::shared_ptr<FakeDrm> drm(new FakeDrm(sid, mDrmSessionManager));
+    mDrmSessionManager->addSession(15, NdkImplToIface(drm), drm->mSessionId);
 
+    // make sure mTestDrm2 is reclaimed next instead of mTestDrm3
+    mDrmSessionManager->useSession(mTestDrm3->mSessionId);
     EXPECT_TRUE(mDrmSessionManager->reclaimSession(18));
-    EXPECT_EQ(1u, mTestDrm2->reclaimedSessions().size());
-    // mSessionId2 is reclaimed.
-    EXPECT_TRUE(isEqualSessionId(mSessionId2, mTestDrm2->reclaimedSessions()[0]));
+    EXPECT_TRUE(mTestDrm2->isReclaimed());
+
+    EXPECT_EQ(2u, mDrmSessionManager->getSessionCount());
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
+    EXPECT_TRUE(mDrmSessionManager->containsSession(drm->mSessionId));
 }
 
-TEST_F(DrmSessionManagerTest, getLowestPriority) {
-    testGetLowestPriority();
-}
+TEST_F(DrmSessionManagerTest, reclaimAfterUse) {
+    // nothing to reclaim yet
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid1));
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(kTestPid2));
 
-TEST_F(DrmSessionManagerTest, getLeastUsedSession_l) {
-    testGetLeastUsedSession();
+    // add sessions from same pid
+    mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm1), mTestDrm1->mSessionId);
+    mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm2), mTestDrm2->mSessionId);
+    mDrmSessionManager->addSession(kTestPid2, NdkImplToIface(mTestDrm3), mTestDrm3->mSessionId);
+
+    // use some but not all sessions
+    mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+    mDrmSessionManager->useSession(mTestDrm1->mSessionId);
+    mDrmSessionManager->useSession(mTestDrm2->mSessionId);
+
+    // calling pid priority is too low
+    int lowPriorityPid = kTestPid2 + 1;
+    EXPECT_FALSE(mDrmSessionManager->reclaimSession(lowPriorityPid));
+
+    // unused session is reclaimed first
+    int highPriorityPid = kTestPid2 - 1;
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+    EXPECT_FALSE(mTestDrm1->isReclaimed());
+    EXPECT_FALSE(mTestDrm2->isReclaimed());
+    EXPECT_TRUE(mTestDrm3->isReclaimed());
+    mDrmSessionManager->removeSession(mTestDrm3->mSessionId);
+
+    // less-used session is reclaimed next
+    EXPECT_TRUE(mDrmSessionManager->reclaimSession(highPriorityPid));
+    EXPECT_FALSE(mTestDrm1->isReclaimed());
+    EXPECT_TRUE(mTestDrm2->isReclaimed());
+    EXPECT_TRUE(mTestDrm3->isReclaimed());
+
+    // most-used session still open
+    EXPECT_EQ(1u, mDrmSessionManager->getSessionCount());
+    EXPECT_TRUE(mDrmSessionManager->containsSession(mTestDrm1->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm2->mSessionId));
+    EXPECT_FALSE(mDrmSessionManager->containsSession(mTestDrm3->mSessionId));
 }
 
 } // namespace android
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
index f556e37..67d028d 100644
--- a/media/libnblog/Reader.cpp
+++ b/media/libnblog/Reader.cpp
@@ -45,7 +45,12 @@
 }
 
 Reader::Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
-    : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size, name)
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    : Reader(iMemory != 0 ? (Shared *) iMemory->unsecurePointer() : NULL, size,
+             name)
 {
     mIMemory = iMemory;
 }
@@ -156,7 +161,8 @@
 
 bool Reader::isIMemory(const sp<IMemory>& iMemory) const
 {
-    return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
+    return iMemory != 0 && mIMemory != 0 &&
+           iMemory->unsecurePointer() == mIMemory->unsecurePointer();
 }
 
 // We make a set of the invalid types rather than the valid types when aligning
diff --git a/media/libnblog/Writer.cpp b/media/libnblog/Writer.cpp
index da3bd52..86d3b98 100644
--- a/media/libnblog/Writer.cpp
+++ b/media/libnblog/Writer.cpp
@@ -56,7 +56,11 @@
 }
 
 Writer::Writer(const sp<IMemory>& iMemory, size_t size)
-    : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    : Writer(iMemory != 0 ? (Shared *) iMemory->unsecurePointer() : NULL, size)
 {
     mIMemory = iMemory;
 }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index eacaea8..ef9d253 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -24,6 +24,8 @@
 #include <inttypes.h>
 #include <utils/Trace.h>
 
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
+
 #include <gui/Surface.h>
 
 #include <media/stagefright/ACodec.h>
@@ -45,6 +47,7 @@
 #include <media/hardware/HardwareAPI.h>
 #include <media/MediaBufferHolder.h>
 #include <media/OMXBuffer.h>
+#include <media/omx/1.0/Conversion.h>
 #include <media/omx/1.0/WOmxNode.h>
 
 #include <hidlmemory/mapping.h>
@@ -63,7 +66,9 @@
 
 namespace android {
 
-using binder::Status;
+typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource;
+
+using hardware::media::omx::V1_0::Status;
 
 enum {
     kMaxIndicesToCheck = 32, // used when enumerating supported formats and profiles
@@ -98,16 +103,11 @@
     }
 }
 
-static inline status_t statusFromBinderStatus(const Status &status) {
+static inline status_t statusFromBinderStatus(hardware::Return<Status> &&status) {
     if (status.isOk()) {
-        return OK;
-    }
-    status_t err;
-    if ((err = status.serviceSpecificErrorCode()) != OK) {
-        return err;
-    }
-    if ((err = status.transactionError()) != OK) {
-        return err;
+        return static_cast<status_t>(status.withDefault(Status::UNKNOWN_ERROR));
+    } else if (status.isDeadObject()) {
+        return DEAD_OBJECT;
     }
     // Other exception
     return UNKNOWN_ERROR;
@@ -1780,6 +1780,14 @@
         }
     }
 
+    int32_t lowLatency = 0;
+    if (msg->findInt32("low-latency", &lowLatency)) {
+        err = setLowLatency(lowLatency);
+        if (err != OK) {
+            return err;
+        }
+    }
+
     int32_t prependSPSPPS = 0;
     if (encoder && mIsVideo
             && msg->findInt32("prepend-sps-pps-to-idr-frames", &prependSPSPPS)
@@ -2348,6 +2356,24 @@
     return err;
 }
 
+status_t ACodec::setLowLatency(int32_t lowLatency) {
+    if (mIsEncoder) {
+        ALOGE("encoder does not support low-latency");
+        return BAD_VALUE;
+    }
+
+    OMX_CONFIG_BOOLEANTYPE config;
+    InitOMXParams(&config);
+    config.bEnabled = (OMX_BOOL)(lowLatency != 0);
+    status_t err = mOMXNode->setConfig(
+            (OMX_INDEXTYPE)OMX_IndexConfigLowLatency,
+            &config, sizeof(config));
+    if (err != OK) {
+        ALOGE("decoder can not set low-latency to %d (err %d)", lowLatency, err);
+    }
+    return err;
+}
+
 status_t ACodec::setLatency(uint32_t latency) {
     OMX_PARAM_U32TYPE config;
     InitOMXParams(&config);
@@ -2410,7 +2436,7 @@
         }
         rate = (OMX_U32)(rateFloat * 65536.0f + 0.5f);
     } else {
-        if (rateFloat > static_cast<float>(UINT_MAX)) {
+        if (rateFloat > (float)UINT_MAX) {
             return BAD_VALUE;
         }
         rate = (OMX_U32)(rateFloat);
@@ -6881,8 +6907,11 @@
         return err;
     }
 
+    using hardware::media::omx::V1_0::utils::TWOmxNode;
     err = statusFromBinderStatus(
-            mCodec->mGraphicBufferSource->configure(mCodec->mOMXNode, dataSpace));
+            mCodec->mGraphicBufferSource->configure(
+                    new TWOmxNode(mCodec->mOMXNode),
+                    static_cast<hardware::graphics::common::V1_0::Dataspace>(dataSpace)));
     if (err != OK) {
         ALOGE("[%s] Unable to configure for node (err %d)",
               mCodec->mComponentName.c_str(), err);
@@ -6968,8 +6997,9 @@
         }
 
         err = statusFromBinderStatus(
-                mCodec->mGraphicBufferSource->setColorAspects(ColorUtils::packToU32(
-                        *(ColorAspects *)colorAspectsBuffer->base())));
+                mCodec->mGraphicBufferSource->setColorAspects(
+                        hardware::media::omx::V1_0::utils::toHardwareColorAspects(
+                                *(ColorAspects *)colorAspectsBuffer->base())));
 
         if (err != OK) {
             ALOGE("[%s] Unable to configure color aspects (err %d)",
@@ -6985,8 +7015,10 @@
     ALOGV("onCreateInputSurface");
 
     sp<IGraphicBufferProducer> bufferProducer;
+    sp<HGraphicBufferSource> bufferSource;
     status_t err = mCodec->mOMX->createInputSurface(
-            &bufferProducer, &mCodec->mGraphicBufferSource);
+            &bufferProducer, &bufferSource);
+    mCodec->mGraphicBufferSource = bufferSource;
 
     if (err == OK) {
         err = setupInputSurface();
@@ -7019,8 +7051,12 @@
     }
 
     sp<PersistentSurface> surface = static_cast<PersistentSurface *>(obj.get());
-    mCodec->mGraphicBufferSource = surface->getBufferSource();
-    status_t err = setupInputSurface();
+    sp<HGraphicBufferSource> hgbs = HGraphicBufferSource::castFrom(surface->getHidlTarget());
+    status_t err = BAD_VALUE;
+    if (hgbs) {
+        mCodec->mGraphicBufferSource = hgbs;
+        err = setupInputSurface();
+    }
 
     if (err == OK) {
         mCodec->mCallback->onInputSurfaceAccepted(
@@ -7539,8 +7575,14 @@
         }
 
         int64_t stopTimeOffsetUs;
-        err = statusFromBinderStatus(
-                mGraphicBufferSource->getStopTimeOffsetUs(&stopTimeOffsetUs));
+        hardware::Return<void> trans = mGraphicBufferSource->getStopTimeOffsetUs(
+                [&err, &stopTimeOffsetUs](auto status, auto result) {
+                    err = static_cast<status_t>(status);
+                    stopTimeOffsetUs = result;
+                });
+        if (!trans.isOk()) {
+            err = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR;
+        }
 
         if (err != OK) {
             ALOGE("Failed to get stop time offset (err %d)", err);
@@ -7583,6 +7625,14 @@
         }
     }
 
+    int32_t lowLatency = 0;
+    if (params->findInt32("low-latency", &lowLatency)) {
+        status_t err = setLowLatency(lowLatency);
+        if (err != OK) {
+            return err;
+        }
+    }
+
     int32_t latency = 0;
     if (params->findInt32("latency", &latency) && latency > 0) {
         status_t err = setLatency(latency);
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 266a240..aa4c22a 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -21,6 +21,7 @@
 #include <numeric>
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/drm/1.0/types.h>
 #include <binder/MemoryDealer.h>
 #include <hidlmemory/FrameworkUtils.h>
 #include <media/openmax/OMX_Core.h>
@@ -41,6 +42,7 @@
 using hardware::hidl_vec;
 using namespace hardware::cas::V1_0;
 using namespace hardware::cas::native::V1_0;
+using DrmBufferType = hardware::drm::V1_0::BufferType;
 using BufferInfo = ACodecBufferChannel::BufferInfo;
 using BufferInfoIterator = std::vector<const BufferInfo>::const_iterator;
 
@@ -131,18 +133,18 @@
     ssize_t result = -1;
     ssize_t codecDataOffset = 0;
     if (mCrypto != NULL) {
-        ICrypto::DestinationBuffer destination;
+        hardware::drm::V1_0::DestinationBuffer destination;
         if (secure) {
-            destination.mType = ICrypto::kDestinationTypeNativeHandle;
-            destination.mHandle = secureHandle;
+            destination.type = DrmBufferType::NATIVE_HANDLE;
+            destination.secureMemory = hidl_handle(secureHandle);
         } else {
-            destination.mType = ICrypto::kDestinationTypeSharedMemory;
-            destination.mSharedMemory = mDecryptDestination;
+            destination.type = DrmBufferType::SHARED_MEMORY;
+            IMemoryToSharedBuffer(
+                    mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
         }
 
-        ICrypto::SourceBuffer source;
-        source.mSharedMemory = it->mSharedEncryptedBuffer;
-        source.mHeapSeqNum = mHeapSeqNum;
+        hardware::drm::V1_0::SharedBuffer source;
+        IMemoryToSharedBuffer(it->mSharedEncryptedBuffer, mHeapSeqNum, &source);
 
         result = mCrypto->decrypt(key, iv, mode, pattern,
                 source, it->mClientBuffer->offset(),
@@ -152,8 +154,8 @@
             return result;
         }
 
-        if (destination.mType == ICrypto::kDestinationTypeSharedMemory) {
-            memcpy(it->mCodecBuffer->base(), destination.mSharedMemory->pointer(), result);
+        if (destination.type == DrmBufferType::SHARED_MEMORY) {
+            memcpy(it->mCodecBuffer->base(), mDecryptDestination->unsecurePointer(), result);
         }
     } else {
         // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
@@ -219,7 +221,8 @@
 
         if (dstBuffer.type == BufferType::SHARED_MEMORY) {
             memcpy(it->mCodecBuffer->base(),
-                    (uint8_t*)it->mSharedEncryptedBuffer->pointer(), result);
+                    (uint8_t*)it->mSharedEncryptedBuffer->unsecurePointer(),
+                    result);
         }
     }
 
@@ -313,7 +316,8 @@
     }
     dealer = new MemoryDealer(heapSize, "ACodecBufferChannel");
     if (mCrypto != nullptr) {
-        int32_t seqNum = mCrypto->setHeap(dealer->getMemoryHeap());
+        sp<HidlMemory> hHeap = fromHeap(dealer->getMemoryHeap());
+        int32_t seqNum = mCrypto->setHeap(hHeap);
         if (seqNum >= 0) {
             mHeapSeqNum = seqNum;
             ALOGV("setHeap returned mHeapSeqNum=%d", mHeapSeqNum);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 59cc24b..76eadf7 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -66,12 +66,14 @@
 
     shared_libs: [
         "libgui",
+        "libhidlallocatorutils",
         "liblog",
         "libmedia_codeclist",
         "libstagefright_foundation",
         "libui",
         "libutils",
         "android.hardware.cas.native@1.0",
+        "android.hardware.drm@1.0",
     ],
 
     sanitize: {
@@ -102,6 +104,10 @@
         "include",
     ],
 
+    header_libs: [
+        "libmedia_helper_headers",
+    ],
+
     cflags: [
         "-Wno-multichar",
         "-Werror",
@@ -118,6 +124,53 @@
     },
 }
 
+cc_library_shared {
+    name: "libstagefright_framecapture_utils",
+
+    srcs: [
+        "FrameCaptureLayer.cpp",
+        "FrameCaptureProcessor.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
+        "libgui",
+        "liblog",
+        "libprocessgroup",
+        "libstagefright_foundation",
+        "libsync",
+        "libui",
+        "libutils",
+    ],
+
+    static_libs: [
+        "librenderengine",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        // TODO: re-enabled cfi for this lib after b/139945549 fixed
+        cfi: false,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
 cc_library {
     name: "libstagefright",
 
@@ -170,6 +223,7 @@
     ],
 
     shared_libs: [
+        "libstagefright_framecapture_utils",
         "libaudioutils",
         "libbase",
         "libbinder",
@@ -186,7 +240,6 @@
         "libmedia_omx_client",
         "libaudioclient",
         "libmediametrics",
-        "libmediautils",
         "libui",
         "libutils",
         "libmedia_helper",
@@ -199,6 +252,7 @@
         "libhidlmemory",
         "android.hidl.allocator@1.0",
         "android.hardware.cas.native@1.0",
+        "android.hardware.drm@1.0",
         "android.hardware.media.omx@1.0",
     ],
 
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index f73b625..b097324 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -32,7 +32,11 @@
 // SharedMemoryBuffer
 
 SharedMemoryBuffer::SharedMemoryBuffer(const sp<AMessage> &format, const sp<IMemory> &mem)
-    : MediaCodecBuffer(format, new ABuffer(mem->pointer(), mem->size())),
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
+    : MediaCodecBuffer(format, new ABuffer(mem->unsecurePointer(), mem->size())),
       mMemory(mem) {
 }
 
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 265f21b..dea83d4 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -81,7 +81,8 @@
             return ERROR_OUT_OF_RANGE;
         }
         CHECK(numRead >= 0 && (size_t)numRead <= bufferSize);
-        memcpy(((uint8_t*)data) + totalNumRead, mMemory->pointer(), numRead);
+        memcpy(((uint8_t*)data) + totalNumRead, mMemory->unsecurePointer(),
+            numRead);
         numLeft -= numRead;
         totalNumRead += numRead;
     }
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 41f5db0..9b3f420 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -89,7 +89,7 @@
 void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
                                     camera_frame_metadata_t * /* metadata */) {
     ALOGV("postData(%d, ptr:%p, size:%zu)",
-         msgType, dataPtr->pointer(), dataPtr->size());
+         msgType, dataPtr->unsecurePointer(), dataPtr->size());
 
     sp<CameraSource> source = mSource.promote();
     if (source.get() != NULL) {
@@ -966,8 +966,12 @@
 
         // Check if frame contains a VideoNativeHandleMetadata.
         if (frame->size() == sizeof(VideoNativeHandleMetadata)) {
-            VideoNativeHandleMetadata *metadata =
-                (VideoNativeHandleMetadata*)(frame->pointer());
+          // TODO: Using unsecurePointer() has some associated security pitfalls
+          //       (see declaration for details).
+          //       Either document why it is safe in this case or address the
+          //       issue (e.g. by copying).
+           VideoNativeHandleMetadata *metadata =
+                (VideoNativeHandleMetadata*)(frame->unsecurePointer());
             if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
                 handle = metadata->pHandle;
             }
@@ -1047,7 +1051,7 @@
     Mutex::Autolock autoLock(mLock);
     for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
          it != mFramesBeingEncoded.end(); ++it) {
-        if ((*it)->pointer() ==  buffer->data()) {
+        if ((*it)->unsecurePointer() ==  buffer->data()) {
             releaseOneRecordingFrame((*it));
             mFramesBeingEncoded.erase(it);
             ++mNumFramesEncoded;
@@ -1102,7 +1106,11 @@
         frameTime = *mFrameTimes.begin();
         mFrameTimes.erase(mFrameTimes.begin());
         mFramesBeingEncoded.push_back(frame);
-        *buffer = new MediaBuffer(frame->pointer(), frame->size());
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        *buffer = new MediaBuffer(frame->unsecurePointer(), frame->size());
         (*buffer)->setObserver(this);
         (*buffer)->add_ref();
         (*buffer)->meta_data().setInt64(kKeyTime, frameTime);
@@ -1248,7 +1256,7 @@
     mMemoryBases.erase(mMemoryBases.begin());
 
     // Wrap native handle in sp<IMemory> so it can be pushed to mFramesReceived.
-    VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->pointer());
+    VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->unsecurePointer());
     metadata->eType = kMetadataBufferTypeNativeHandleSource;
     metadata->pHandle = handle;
 
@@ -1296,7 +1304,11 @@
         mMemoryBases.erase(mMemoryBases.begin());
 
         // Wrap native handle in sp<IMemory> so it can be pushed to mFramesReceived.
-        VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->pointer());
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(data->unsecurePointer());
         metadata->eType = kMetadataBufferTypeNativeHandleSource;
         metadata->pHandle = handle;
 
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 2a819ad..e0a6eb3 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -245,11 +245,11 @@
 
     ALOGV("createIMemoryCopy");
     size_t source_size = source_data->size();
-    void* source_pointer = source_data->pointer();
+    void* source_pointer = source_data->unsecurePointer();
 
     sp<MemoryHeapBase> newMemoryHeap = new MemoryHeapBase(source_size);
     sp<MemoryBase> newMemory = new MemoryBase(newMemoryHeap, 0, source_size);
-    memcpy(newMemory->pointer(), source_pointer, source_size);
+    memcpy(newMemory->unsecurePointer(), source_pointer, source_size);
     return newMemory;
 }
 
diff --git a/media/libstagefright/CodecBase.cpp b/media/libstagefright/CodecBase.cpp
index 97f38f8..5765883 100644
--- a/media/libstagefright/CodecBase.cpp
+++ b/media/libstagefright/CodecBase.cpp
@@ -18,6 +18,8 @@
 #define LOG_TAG "CodecBase"
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <hidlmemory/FrameworkUtils.h>
 #include <mediadrm/ICrypto.h>
 #include <media/stagefright/CodecBase.h>
 #include <utils/Log.h>
@@ -32,4 +34,18 @@
     mDescrambler = descrambler;
 }
 
+void BufferChannelBase::IMemoryToSharedBuffer(
+        const sp<IMemory> &memory,
+        int32_t heapSeqNum,
+        hardware::drm::V1_0::SharedBuffer *buf) {
+    ssize_t offset;
+    size_t size;
+
+    sp<hardware::HidlMemory> hidlMemory;
+    hidlMemory = hardware::fromHeap(memory->getMemory(&offset, &size));
+    buf->bufferId = static_cast<uint32_t>(heapSeqNum);
+    buf->offset = offset >= 0 ? offset : 0;
+    buf->size = size;
+}
+
 } // namespace android
diff --git a/media/libstagefright/FrameCaptureLayer.cpp b/media/libstagefright/FrameCaptureLayer.cpp
new file mode 100644
index 0000000..29642be
--- /dev/null
+++ b/media/libstagefright/FrameCaptureLayer.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FrameCaptureLayer"
+
+#include <include/FrameCaptureLayer.h>
+#include <media/stagefright/FrameCaptureProcessor.h>
+#include <gui/BufferQueue.h>
+#include <gui/GLConsumer.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/Surface.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <renderengine/RenderEngine.h>
+#include <utils/Log.h>
+
+namespace android {
+
+static const int64_t kAcquireBufferTimeoutNs = 100000000LL;
+
+ui::Dataspace translateDataspace(ui::Dataspace dataspace) {
+    ui::Dataspace updatedDataspace = dataspace;
+    // translate legacy dataspaces to modern dataspaces
+    switch (dataspace) {
+        case ui::Dataspace::SRGB:
+            updatedDataspace = ui::Dataspace::V0_SRGB;
+            break;
+        case ui::Dataspace::SRGB_LINEAR:
+            updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+            break;
+        case ui::Dataspace::JFIF:
+            updatedDataspace = ui::Dataspace::V0_JFIF;
+            break;
+        case ui::Dataspace::BT601_625:
+            updatedDataspace = ui::Dataspace::V0_BT601_625;
+            break;
+        case ui::Dataspace::BT601_525:
+            updatedDataspace = ui::Dataspace::V0_BT601_525;
+            break;
+        case ui::Dataspace::BT709:
+            updatedDataspace = ui::Dataspace::V0_BT709;
+            break;
+        default:
+            break;
+    }
+
+    return updatedDataspace;
+}
+
+bool isHdrY410(const BufferItem &bi) {
+    ui::Dataspace dataspace = translateDataspace(static_cast<ui::Dataspace>(bi.mDataSpace));
+    // pixel format is HDR Y410 masquerading as RGBA_1010102
+    return (dataspace == ui::Dataspace::BT2020_ITU_PQ &&
+            bi.mGraphicBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
+}
+
+struct FrameCaptureLayer::BufferLayer : public FrameCaptureProcessor::Layer {
+    BufferLayer(const BufferItem &bi) : mBufferItem(bi) {}
+    void getLayerSettings(
+            const Rect &sourceCrop, uint32_t textureName,
+            renderengine::LayerSettings *layerSettings) override;
+    BufferItem mBufferItem;
+};
+
+void FrameCaptureLayer::BufferLayer::getLayerSettings(
+        const Rect &sourceCrop, uint32_t textureName,
+        renderengine::LayerSettings *layerSettings) {
+    layerSettings->geometry.boundaries = sourceCrop.toFloatRect();
+    layerSettings->alpha = 1.0f;
+
+    layerSettings->sourceDataspace = translateDataspace(
+            static_cast<ui::Dataspace>(mBufferItem.mDataSpace));
+
+    // from BufferLayer
+    layerSettings->source.buffer.buffer = mBufferItem.mGraphicBuffer;
+    layerSettings->source.buffer.isOpaque = true;
+    layerSettings->source.buffer.fence = mBufferItem.mFence;
+    layerSettings->source.buffer.textureName = textureName;
+    layerSettings->source.buffer.usePremultipliedAlpha = false;
+    layerSettings->source.buffer.isY410BT2020 = isHdrY410(mBufferItem);
+
+    // Set filtering to false since the capture itself doesn't involve
+    // any scaling, metadata retriever JNI is scaling the bitmap if
+    // display size is different from decoded size. If that scaling
+    // needs to be handled by server side, consider enable this based
+    // display size vs decoded size.
+    const bool useFiltering = false;
+    layerSettings->source.buffer.useTextureFiltering = useFiltering;
+
+    float textureMatrix[16];
+    GLConsumer::computeTransformMatrix(
+            textureMatrix, mBufferItem.mGraphicBuffer,
+            mBufferItem.mCrop, mBufferItem.mTransform, useFiltering);
+
+    // Flip y-coordinates because GLConsumer expects OpenGL convention.
+    mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) *
+            mat4::translate(vec4(-.5, -.5, 0, 1));
+
+    layerSettings->source.buffer.textureTransform =
+            mat4(static_cast<const float*>(textureMatrix)) * tr;
+}
+
+status_t FrameCaptureLayer::init() {
+    if (FrameCaptureProcessor::getInstance() == nullptr) {
+        ALOGE("failed to get capture processor");
+        return ERROR_UNSUPPORTED;
+    }
+
+    // Mimic surfaceflinger's BufferQueueLayer::onFirstRef() to create a
+    // BufferQueue for encoder output
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    // We don't need HW_COMPOSER usage since we're not using hwc to compose.
+    // The buffer is only used as a GL texture.
+    consumer->setConsumerUsageBits(GraphicBuffer::USAGE_HW_TEXTURE);
+    consumer->setConsumerName(String8("FrameDecoder"));
+
+    status_t err = consumer->consumerConnect(
+            new BufferQueue::ProxyConsumerListener(this), false);
+    if (NO_ERROR != err) {
+        ALOGE("Error connecting to BufferQueue: %s (%d)", strerror(-err), err);
+        return err;
+    }
+
+    mConsumer = consumer;
+    mSurface = new Surface(producer);
+
+    return OK;
+}
+
+status_t FrameCaptureLayer::capture(const ui::PixelFormat reqPixelFormat,
+        const Rect &sourceCrop, sp<GraphicBuffer> *outBuffer) {
+    ALOGV("capture: reqPixelFormat %d, crop {%d, %d, %d, %d}", reqPixelFormat,
+            sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom);
+
+    BufferItem bi;
+    status_t err = acquireBuffer(&bi);
+    if (err != OK) {
+        return err;
+    }
+
+    // create out buffer
+    const uint32_t usage =
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    sp<GraphicBuffer> buffer = new GraphicBuffer(
+            sourceCrop.getWidth(), sourceCrop.getHeight(),
+            static_cast<android_pixel_format>(reqPixelFormat),
+            1, usage, std::string("thumbnail"));
+
+    err = FrameCaptureProcessor::getInstance()->capture(
+            new BufferLayer(bi), sourceCrop, buffer);
+    if (err == OK) {
+        *outBuffer = buffer;
+    }
+
+    (void)releaseBuffer(bi);
+    return err;
+}
+
+FrameCaptureLayer::FrameCaptureLayer() : mFrameAvailable(false) {}
+
+void FrameCaptureLayer::onFrameAvailable(const BufferItem& /*item*/) {
+    ALOGV("onFrameAvailable");
+    Mutex::Autolock _lock(mLock);
+
+    mFrameAvailable = true;
+    mCondition.signal();
+}
+
+void FrameCaptureLayer::onBuffersReleased() {
+    ALOGV("onBuffersReleased");
+    Mutex::Autolock _lock(mLock);
+
+    uint64_t mask = 0;
+    mConsumer->getReleasedBuffers(&mask);
+    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        if (mask & (1ULL << i)) {
+            mSlotToBufferMap[i] = nullptr;
+        }
+    }
+}
+
+void FrameCaptureLayer::onSidebandStreamChanged() {
+    ALOGV("onSidebandStreamChanged");
+}
+
+status_t FrameCaptureLayer::acquireBuffer(BufferItem *bi) {
+    ALOGV("acquireBuffer");
+    Mutex::Autolock _lock(mLock);
+
+    if (!mFrameAvailable) {
+        // The output buffer is already released to the codec at this point.
+        // Use a small timeout of 100ms in case the buffer hasn't arrived
+        // at the consumer end of the output surface yet.
+        if (mCondition.waitRelative(mLock, kAcquireBufferTimeoutNs) != OK) {
+            ALOGE("wait for buffer timed out");
+            return TIMED_OUT;
+        }
+    }
+    mFrameAvailable = false;
+
+    status_t err = mConsumer->acquireBuffer(bi, 0);
+    if (err != OK) {
+        ALOGE("failed to acquire buffer!");
+        return err;
+    }
+
+    if (bi->mGraphicBuffer != nullptr) {
+        mSlotToBufferMap[bi->mSlot] = bi->mGraphicBuffer;
+    } else {
+        bi->mGraphicBuffer = mSlotToBufferMap[bi->mSlot];
+    }
+
+    if (bi->mGraphicBuffer == nullptr) {
+        ALOGE("acquired null buffer!");
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t FrameCaptureLayer::releaseBuffer(const BufferItem &bi) {
+    ALOGV("releaseBuffer");
+    Mutex::Autolock _lock(mLock);
+
+    return mConsumer->releaseBuffer(bi.mSlot, bi.mFrameNumber,
+            EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/FrameCaptureProcessor.cpp b/media/libstagefright/FrameCaptureProcessor.cpp
new file mode 100644
index 0000000..c517e33
--- /dev/null
+++ b/media/libstagefright/FrameCaptureProcessor.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FrameCaptureProcessor"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/FrameCaptureProcessor.h>
+#include <media/stagefright/MediaErrors.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/Fence.h>
+#include <ui/PixelFormat.h>
+#include <utils/Log.h>
+
+namespace android {
+
+//static
+Mutex FrameCaptureProcessor::sLock;
+//static
+sp<FrameCaptureProcessor> FrameCaptureProcessor::sInstance;
+
+//static
+sp<FrameCaptureProcessor> FrameCaptureProcessor::getInstance() {
+    Mutex::Autolock _l(sLock);
+    if (sInstance == nullptr) {
+        sInstance = new FrameCaptureProcessor();
+        sInstance->createRenderEngine();
+    }
+    // init only once, if failed nullptr will be returned afterwards.
+    return (sInstance->initCheck() == OK) ? sInstance : nullptr;
+}
+
+//static
+status_t FrameCaptureProcessor::PostAndAwaitResponse(
+        const sp<AMessage> &msg, sp<AMessage> *response) {
+    status_t err = msg->postAndAwaitResponse(response);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (!(*response)->findInt32("err", &err)) {
+        err = OK;
+    }
+
+    return err;
+}
+
+//static
+void FrameCaptureProcessor::PostReplyWithError(
+        const sp<AReplyToken> &replyID, status_t err) {
+    sp<AMessage> response = new AMessage;
+    if (err != OK) {
+        response->setInt32("err", err);
+    }
+    response->postReply(replyID);
+}
+
+FrameCaptureProcessor::FrameCaptureProcessor()
+    : mInitStatus(NO_INIT), mTextureName(0) {}
+
+FrameCaptureProcessor::~FrameCaptureProcessor() {
+    if (mLooper != nullptr) {
+        mLooper->unregisterHandler(id());
+        mLooper->stop();
+    }
+}
+
+void FrameCaptureProcessor::createRenderEngine() {
+    // this method should only be called once, immediately after ctor
+    CHECK(mInitStatus == NO_INIT);
+
+    mLooper = new ALooper();
+    mLooper->setName("capture_looper");
+    mLooper->start(); // default priority
+    mLooper->registerHandler(this);
+
+    sp<AMessage> response;
+    status_t err = PostAndAwaitResponse(new AMessage(kWhatCreate, this), &response);
+    if (err != OK) {
+        mInitStatus = ERROR_UNSUPPORTED;
+
+        mLooper->unregisterHandler(id());
+        mLooper->stop();
+        mLooper.clear();
+        return;
+    }
+
+    // only need one texture name
+    mRE->genTextures(1, &mTextureName);
+
+    mInitStatus = OK;
+}
+
+status_t FrameCaptureProcessor::capture(
+        const sp<Layer> &layer, const Rect &sourceCrop, const sp<GraphicBuffer> &buffer) {
+    sp<AMessage> msg = new AMessage(kWhatCapture, this);
+    msg->setObject("layer", layer);
+    msg->setRect("crop", sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom);
+    msg->setObject("buffer", buffer);
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
+status_t FrameCaptureProcessor::onCreate() {
+    mRE = renderengine::RenderEngine::create(
+            renderengine::RenderEngineCreationArgs::Builder()
+                .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+                .setImageCacheSize(2 /*maxFrameBufferAcquiredBuffers*/)
+                .setUseColorManagerment(true)
+                .setEnableProtectedContext(false)
+                .setPrecacheToneMapperShaderOnly(true)
+                .setContextPriority(renderengine::RenderEngine::ContextPriority::LOW)
+                .build());
+
+    if (mRE == nullptr) {
+        return ERROR_UNSUPPORTED;
+    }
+    return OK;
+}
+
+status_t FrameCaptureProcessor::onCapture(const sp<Layer> &layer,
+        const Rect &sourceCrop, const sp<GraphicBuffer> &buffer) {
+    renderengine::DisplaySettings clientCompositionDisplay;
+    std::vector<renderengine::LayerSettings> clientCompositionLayers;
+
+    clientCompositionDisplay.physicalDisplay = sourceCrop;
+    clientCompositionDisplay.clip = sourceCrop;
+
+    clientCompositionDisplay.outputDataspace = ui::Dataspace::V0_SRGB;
+    clientCompositionDisplay.maxLuminance = sDefaultMaxLumiance;
+    clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
+
+    // from Layer && BufferLayer
+    renderengine::LayerSettings layerSettings;
+
+    layer->getLayerSettings(sourceCrop, mTextureName, &layerSettings);
+
+    clientCompositionLayers.push_back(layerSettings);
+
+    // Use an empty fence for the buffer fence, since we just created the buffer so
+    // there is no need for synchronization with the GPU.
+    base::unique_fd bufferFence;
+    base::unique_fd drawFence;
+    mRE->useProtectedContext(false);
+    status_t err = mRE->drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer.get(),
+            /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
+
+    sp<Fence> fence = new Fence(std::move(drawFence));
+
+    if (err != OK) {
+        ALOGE("drawLayers returned err %d", err);
+        return err;
+    }
+
+    err = fence->wait(500);
+    if (err != OK) {
+        ALOGW("wait for fence returned err %d", err);
+    }
+    return OK;
+}
+
+void FrameCaptureProcessor::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatCreate:
+        {
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            status_t err = onCreate();
+
+            PostReplyWithError(replyID, err);
+            break;
+        }
+        case kWhatCapture:
+        {
+            sp<AReplyToken> replyID;
+            CHECK(msg->senderAwaitsResponse(&replyID));
+
+            sp<RefBase> layerObj, bufferObj;
+            int32_t left, top, right, bottom;
+            CHECK(msg->findObject("layer", &layerObj));
+            CHECK(msg->findRect("crop", &left, &top, &right, &bottom));
+            CHECK(msg->findObject("buffer", &bufferObj));
+
+            sp<GraphicBuffer> buffer = static_cast<GraphicBuffer*>(bufferObj.get());
+            sp<Layer> layer = static_cast<Layer*>(layerObj.get());
+
+            PostReplyWithError(replyID,
+                    onCapture(layer, Rect(left, top, right, bottom), buffer));
+
+            break;
+        }
+        default:
+            TRESPASS();
+    }
+}
+
+}  // namespace android
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 08f690b..d75b317 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "FrameDecoder"
 
 #include "include/FrameDecoder.h"
+#include "include/FrameCaptureLayer.h"
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
 #include <gui/Surface.h>
@@ -28,7 +29,9 @@
 #include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ColorUtils.h>
 #include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/FrameCaptureProcessor.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaDefs.h>
@@ -41,10 +44,11 @@
 
 static const int64_t kBufferTimeOutUs = 10000LL; // 10 msec
 static const size_t kRetryCount = 50; // must be >0
+static const int64_t kDefaultSampleDurationUs = 33333LL; // 33ms
 
 sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
         int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
-        int32_t dstBpp, bool metaOnly = false) {
+        int32_t dstBpp, bool allocRotated, bool metaOnly) {
     int32_t rotationAngle;
     if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
         rotationAngle = 0;  // By default, no rotation
@@ -74,6 +78,14 @@
         displayHeight = height;
     }
 
+    if (allocRotated && (rotationAngle == 90 || rotationAngle == 270)) {
+        int32_t tmp;
+        tmp = width; width = height; height = tmp;
+        tmp = displayWidth; displayWidth = displayHeight; displayHeight = tmp;
+        tmp = tileWidth; tileWidth = tileHeight; tileHeight = tmp;
+        rotationAngle = 0;
+    }
+
     VideoFrame frame(width, height, displayWidth, displayHeight,
             tileWidth, tileHeight, rotationAngle, dstBpp, !metaOnly, iccSize);
 
@@ -88,12 +100,26 @@
         ALOGE("not enough memory for VideoFrame size=%zu", size);
         return NULL;
     }
-    VideoFrame* frameCopy = static_cast<VideoFrame*>(frameMem->pointer());
+    VideoFrame* frameCopy = static_cast<VideoFrame*>(frameMem->unsecurePointer());
     frameCopy->init(frame, iccData, iccSize);
 
     return frameMem;
 }
 
+sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
+        int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
+        int32_t dstBpp, bool allocRotated = false) {
+    return allocVideoFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp,
+            allocRotated, false /*metaOnly*/);
+}
+
+sp<IMemory> allocMetaFrame(const sp<MetaData>& trackMeta,
+        int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
+        int32_t dstBpp) {
+    return allocVideoFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp,
+            false /*allocRotated*/, true /*metaOnly*/);
+}
+
 bool findThumbnailInfo(
         const sp<MetaData> &trackMeta, int32_t *width, int32_t *height,
         uint32_t *type = NULL, const void **data = NULL, size_t *size = NULL) {
@@ -117,23 +143,27 @@
 bool getDstColorFormat(
         android_pixel_format_t colorFormat,
         OMX_COLOR_FORMATTYPE *dstFormat,
+        ui::PixelFormat *captureFormat,
         int32_t *dstBpp) {
     switch (colorFormat) {
         case HAL_PIXEL_FORMAT_RGB_565:
         {
             *dstFormat = OMX_COLOR_Format16bitRGB565;
+            *captureFormat = ui::PixelFormat::RGB_565;
             *dstBpp = 2;
             return true;
         }
         case HAL_PIXEL_FORMAT_RGBA_8888:
         {
             *dstFormat = OMX_COLOR_Format32BitRGBA8888;
+            *captureFormat = ui::PixelFormat::RGBA_8888;
             *dstBpp = 4;
             return true;
         }
         case HAL_PIXEL_FORMAT_BGRA_8888:
         {
             *dstFormat = OMX_COLOR_Format32bitBGRA8888;
+            *captureFormat = ui::PixelFormat::BGRA_8888;
             *dstBpp = 4;
             return true;
         }
@@ -150,9 +180,10 @@
 sp<IMemory> FrameDecoder::getMetadataOnly(
         const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail) {
     OMX_COLOR_FORMATTYPE dstFormat;
+    ui::PixelFormat captureFormat;
     int32_t dstBpp;
-    if (!getDstColorFormat(
-            (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
+    if (!getDstColorFormat((android_pixel_format_t)colorFormat,
+            &dstFormat, &captureFormat, &dstBpp)) {
         return NULL;
     }
 
@@ -170,8 +201,19 @@
             tileWidth = tileHeight = 0;
         }
     }
-    return allocVideoFrame(trackMeta,
-            width, height, tileWidth, tileHeight, dstBpp, true /*metaOnly*/);
+
+    sp<IMemory> metaMem = allocMetaFrame(trackMeta, width, height, tileWidth, tileHeight, dstBpp);
+
+    // try to fill sequence meta's duration based on average frame rate,
+    // default to 33ms if frame rate is unavailable.
+    int32_t frameRate;
+    VideoFrame* meta = static_cast<VideoFrame*>(metaMem->unsecurePointer());
+    if (trackMeta->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
+        meta->mDurationUs = 1000000LL / frameRate;
+    } else {
+        meta->mDurationUs = kDefaultSampleDurationUs;
+    }
+    return metaMem;
 }
 
 FrameDecoder::FrameDecoder(
@@ -194,15 +236,30 @@
     }
 }
 
+bool isHDR(const sp<AMessage> &format) {
+    uint32_t standard, range, transfer;
+    if (!format->findInt32("color-standard", (int32_t*)&standard)) {
+        standard = 0;
+    }
+    if (!format->findInt32("color-range", (int32_t*)&range)) {
+        range = 0;
+    }
+    if (!format->findInt32("color-transfer", (int32_t*)&transfer)) {
+        transfer = 0;
+    }
+    return standard == ColorUtils::kColorStandardBT2020 &&
+            transfer == ColorUtils::kColorTransferST2084;
+}
+
 status_t FrameDecoder::init(
-        int64_t frameTimeUs, size_t numFrames, int option, int colorFormat) {
-    if (!getDstColorFormat(
-            (android_pixel_format_t)colorFormat, &mDstFormat, &mDstBpp)) {
+        int64_t frameTimeUs, int option, int colorFormat) {
+    if (!getDstColorFormat((android_pixel_format_t)colorFormat,
+            &mDstFormat, &mCaptureFormat, &mDstBpp)) {
         return ERROR_UNSUPPORTED;
     }
 
     sp<AMessage> videoFormat = onGetFormatAndSeekOptions(
-            frameTimeUs, numFrames, option, &mReadOptions);
+            frameTimeUs, option, &mReadOptions, &mSurface);
     if (videoFormat == NULL) {
         ALOGE("video format or seek mode not supported");
         return ERROR_UNSUPPORTED;
@@ -219,7 +276,7 @@
     }
 
     err = decoder->configure(
-            videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
+            videoFormat, mSurface, NULL /* crypto */, 0 /* flags */);
     if (err != OK) {
         ALOGW("configure returned error %d (%s)", err, asString(err));
         decoder->release();
@@ -253,19 +310,7 @@
         return NULL;
     }
 
-    return mFrames.size() > 0 ? mFrames[0] : NULL;
-}
-
-status_t FrameDecoder::extractFrames(std::vector<sp<IMemory> >* frames) {
-    status_t err = extractInternal();
-    if (err != OK) {
-        return err;
-    }
-
-    for (size_t i = 0; i < mFrames.size(); i++) {
-        frames->push_back(mFrames[i]);
-    }
-    return OK;
+    return mFrameMemory;
 }
 
 status_t FrameDecoder::extractInternal() {
@@ -379,8 +424,13 @@
                         ALOGE("failed to get output buffer %zu", index);
                         break;
                     }
-                    err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
-                    mDecoder->releaseOutputBuffer(index);
+                    if (mSurface != nullptr) {
+                        mDecoder->renderOutputBufferAndRelease(index);
+                        err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
+                    } else {
+                        err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
+                        mDecoder->releaseOutputBuffer(index);
+                    }
                 } else {
                     ALOGW("Received error %d (%s) instead of output", err, asString(err));
                     done = true;
@@ -404,22 +454,23 @@
         const sp<MetaData> &trackMeta,
         const sp<IMediaSource> &source)
     : FrameDecoder(componentName, trackMeta, source),
+      mFrame(NULL),
       mIsAvcOrHevc(false),
       mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
       mTargetTimeUs(-1LL),
-      mNumFrames(0),
-      mNumFramesDecoded(0) {
+      mDefaultSampleDurationUs(0) {
 }
 
 sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
-        int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
+        int64_t frameTimeUs, int seekMode,
+        MediaSource::ReadOptions *options,
+        sp<Surface> *window) {
     mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
     if (mSeekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
             mSeekMode > MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
         ALOGE("Unknown seek mode: %d", mSeekMode);
         return NULL;
     }
-    mNumFrames = numFrames;
 
     const char *mime;
     if (!trackMeta()->findCString(kKeyMIMEType, &mime)) {
@@ -460,6 +511,23 @@
         videoFormat->setInt32("android._num-input-buffers", 1);
         videoFormat->setInt32("android._num-output-buffers", 1);
     }
+
+    if (isHDR(videoFormat)) {
+        *window = initSurface();
+        if (*window == NULL) {
+            ALOGE("Failed to init surface control for HDR, fallback to non-hdr");
+        } else {
+            videoFormat->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque);
+        }
+    }
+
+    int32_t frameRate;
+    if (trackMeta()->findInt32(kKeyFrameRate, &frameRate) && frameRate > 0) {
+        mDefaultSampleDurationUs = 1000000LL / frameRate;
+    } else {
+        mDefaultSampleDurationUs = kDefaultSampleDurationUs;
+    }
+
     return videoFormat;
 }
 
@@ -480,6 +548,12 @@
         // option, in which case we need to actually decode to targetTimeUs.
         *flags |= MediaCodec::BUFFER_FLAG_EOS;
     }
+    int64_t durationUs;
+    if (sampleMeta.findInt64(kKeyDuration, &durationUs)) {
+        mSampleDurations.push_back(durationUs);
+    } else {
+        mSampleDurations.push_back(mDefaultSampleDurationUs);
+    }
     return OK;
 }
 
@@ -487,6 +561,11 @@
         const sp<MediaCodecBuffer> &videoFrameBuffer,
         const sp<AMessage> &outputFormat,
         int64_t timeUs, bool *done) {
+    int64_t durationUs = mDefaultSampleDurationUs;
+    if (!mSampleDurations.empty()) {
+        durationUs = *mSampleDurations.begin();
+        mSampleDurations.erase(mSampleDurations.begin());
+    }
     bool shouldOutput = (mTargetTimeUs < 0LL) || (timeUs >= mTargetTimeUs);
 
     // If this is not the target frame, skip color convert.
@@ -495,7 +574,7 @@
         return OK;
     }
 
-    *done = (++mNumFramesDecoded >= mNumFrames);
+    *done = true;
 
     if (outputFormat == NULL) {
         return ERROR_MALFORMED;
@@ -504,13 +583,22 @@
     int32_t width, height, stride, srcFormat;
     if (!outputFormat->findInt32("width", &width) ||
             !outputFormat->findInt32("height", &height) ||
-            !outputFormat->findInt32("stride", &stride) ||
             !outputFormat->findInt32("color-format", &srcFormat)) {
         ALOGE("format missing dimension or color: %s",
                 outputFormat->debugString().c_str());
         return ERROR_MALFORMED;
     }
 
+    if (!outputFormat->findInt32("stride", &stride)) {
+        if (mCaptureLayer == NULL) {
+            ALOGE("format must have stride for byte buffer mode: %s",
+                    outputFormat->debugString().c_str());
+            return ERROR_MALFORMED;
+        }
+        // for surface output, set stride to width, we don't actually need it.
+        stride = width;
+    }
+
     int32_t crop_left, crop_top, crop_right, crop_bottom;
     if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
         crop_left = crop_top = 0;
@@ -518,15 +606,25 @@
         crop_bottom = height - 1;
     }
 
-    sp<IMemory> frameMem = allocVideoFrame(
-            trackMeta(),
-            (crop_right - crop_left + 1),
-            (crop_bottom - crop_top + 1),
-            0,
-            0,
-            dstBpp());
-    addFrame(frameMem);
-    VideoFrame* frame = static_cast<VideoFrame*>(frameMem->pointer());
+    if (mFrame == NULL) {
+        sp<IMemory> frameMem = allocVideoFrame(
+                trackMeta(),
+                (crop_right - crop_left + 1),
+                (crop_bottom - crop_top + 1),
+                0,
+                0,
+                dstBpp(),
+                mCaptureLayer != nullptr /*allocRotated*/);
+        mFrame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
+
+        setFrame(frameMem);
+    }
+
+    mFrame->mDurationUs = durationUs;
+
+    if (mCaptureLayer != nullptr) {
+        return captureSurface();
+    }
 
     ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
 
@@ -547,8 +645,8 @@
                 (const uint8_t *)videoFrameBuffer->data(),
                 width, height, stride,
                 crop_left, crop_top, crop_right, crop_bottom,
-                frame->getFlattenedData(),
-                frame->mWidth, frame->mHeight, frame->mRowBytes,
+                mFrame->getFlattenedData(),
+                mFrame->mWidth, mFrame->mHeight, mFrame->mRowBytes,
                 crop_left, crop_top, crop_right, crop_bottom);
         return OK;
     }
@@ -558,6 +656,57 @@
     return ERROR_UNSUPPORTED;
 }
 
+sp<Surface> VideoFrameDecoder::initSurface() {
+    // create the consumer listener interface, and hold sp so that this
+    // interface lives as long as the GraphicBufferSource.
+    sp<FrameCaptureLayer> captureLayer = new FrameCaptureLayer();
+    if (captureLayer->init() != OK) {
+        ALOGE("failed to init capture layer");
+        return nullptr;
+    }
+    mCaptureLayer = captureLayer;
+
+    return captureLayer->getSurface();
+}
+
+status_t VideoFrameDecoder::captureSurface() {
+    sp<GraphicBuffer> outBuffer;
+    status_t err = mCaptureLayer->capture(
+            captureFormat(), Rect(0, 0, mFrame->mWidth, mFrame->mHeight), &outBuffer);
+
+    if (err != OK) {
+        ALOGE("failed to capture layer (err %d)", err);
+        return err;
+    }
+
+    ALOGV("capture: %dx%d, format %d, stride %d",
+            outBuffer->getWidth(),
+            outBuffer->getHeight(),
+            outBuffer->getPixelFormat(),
+            outBuffer->getStride());
+
+    uint8_t *base;
+    int32_t outBytesPerPixel, outBytesPerStride;
+    err = outBuffer->lock(
+            GraphicBuffer::USAGE_SW_READ_OFTEN,
+            reinterpret_cast<void**>(&base),
+            &outBytesPerPixel,
+            &outBytesPerStride);
+    if (err != OK) {
+        ALOGE("failed to lock graphic buffer: err %d", err);
+        return err;
+    }
+
+    uint8_t *dst = mFrame->getFlattenedData();
+    for (size_t y = 0 ; y < fmin(mFrame->mHeight, outBuffer->getHeight()) ; y++) {
+        memcpy(dst, base, fmin(mFrame->mWidth, outBuffer->getWidth()) * mFrame->mBytesPerPixel);
+        dst += mFrame->mRowBytes;
+        base += outBuffer->getStride() * mFrame->mBytesPerPixel;
+    }
+    outBuffer->unlock();
+    return OK;
+}
+
 ////////////////////////////////////////////////////////////////////////
 
 ImageDecoder::ImageDecoder(
@@ -577,8 +726,8 @@
 }
 
 sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
-        int64_t frameTimeUs, size_t /*numFrames*/,
-        int /*seekMode*/, MediaSource::ReadOptions *options) {
+        int64_t frameTimeUs, int /*seekMode*/,
+        MediaSource::ReadOptions *options, sp<Surface> * /*window*/) {
     sp<MetaData> overrideMeta;
     if (frameTimeUs < 0) {
         uint32_t type;
@@ -703,9 +852,9 @@
     if (mFrame == NULL) {
         sp<IMemory> frameMem = allocVideoFrame(
                 trackMeta(), mWidth, mHeight, mTileWidth, mTileHeight, dstBpp());
-        mFrame = static_cast<VideoFrame*>(frameMem->pointer());
+        mFrame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
 
-        addFrame(frameMem);
+        setFrame(frameMem);
     }
 
     int32_t srcFormat;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index f130c9b..bf4e7de 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2213,8 +2213,10 @@
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
                !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
         mMeta->findData(kKeyHVCC, &type, &data, &size);
-    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
-            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION)) {
+        mMeta->findData(kKeyDVCC, &type, &data, &size);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
+               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
             ESDS esds(data, size);
             if (esds.getCodecSpecificInfo(&data, &size) == OK &&
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 3d6ebc3..14564c9 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -21,13 +21,14 @@
 #include <inttypes.h>
 #include <stdlib.h>
 
-#include "include/SecureBuffer.h"
-#include "include/SharedMemoryBuffer.h"
 #include "include/SoftwareRenderer.h"
 #include "StagefrightPluginLoader.h"
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
+#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
+#include <android/media/BnResourceManagerClient.h>
+#include <android/media/IResourceManagerService.h>
 #include <binder/IMemory.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -37,9 +38,9 @@
 #include <gui/Surface.h>
 #include <mediadrm/ICrypto.h>
 #include <media/IOMX.h>
-#include <media/IResourceManagerService.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/MediaAnalyticsItem.h>
+#include <media/MediaResource.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -63,6 +64,10 @@
 
 namespace android {
 
+using ::android::binder::Status;
+using ::android::media::BnResourceManagerClient;
+using ::android::media::IResourceManagerService;
+
 // key for media statistics
 static const char *kCodecKeyName = "codec";
 // attrs for media statistics
@@ -123,11 +128,12 @@
 struct ResourceManagerClient : public BnResourceManagerClient {
     explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
 
-    virtual bool reclaimResource() {
+    Status reclaimResource(bool* _aidl_return) override {
         sp<MediaCodec> codec = mMediaCodec.promote();
         if (codec == NULL) {
             // codec is already gone.
-            return true;
+            *_aidl_return = true;
+            return Status::ok();
         }
         status_t err = codec->reclaim();
         if (err == WOULD_BLOCK) {
@@ -139,22 +145,23 @@
         if (err != OK) {
             ALOGW("ResourceManagerClient failed to release codec with err %d", err);
         }
-        return (err == OK);
+        *_aidl_return = (err == OK);
+        return Status::ok();
     }
 
-    virtual String8 getName() {
-        String8 ret;
+    Status getName(::std::string* _aidl_return) override {
+        _aidl_return->clear();
         sp<MediaCodec> codec = mMediaCodec.promote();
         if (codec == NULL) {
             // codec is already gone.
-            return ret;
+            return Status::ok();
         }
 
         AString name;
         if (codec->getName(&name) == OK) {
-            ret.setTo(name.c_str());
+            *_aidl_return = name.c_str();
         }
-        return ret;
+        return Status::ok();
     }
 
 protected:
@@ -166,6 +173,35 @@
     DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
 };
 
+struct MediaCodec::ResourceManagerServiceProxy : public IBinder::DeathRecipient {
+    ResourceManagerServiceProxy(pid_t pid, uid_t uid);
+    ~ResourceManagerServiceProxy();
+
+    void init();
+
+    // implements DeathRecipient
+    virtual void binderDied(const wp<IBinder>& /*who*/);
+
+    void addResource(
+            int64_t clientId,
+            const sp<IResourceManagerClient> &client,
+            const std::vector<MediaResourceParcel> &resources);
+
+    void removeResource(
+            int64_t clientId,
+            const std::vector<MediaResourceParcel> &resources);
+
+    void removeClient(int64_t clientId);
+
+    bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
+
+private:
+    Mutex mLock;
+    sp<android::media::IResourceManagerService> mService;
+    pid_t mPid;
+    uid_t mUid;
+};
+
 MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
         pid_t pid, uid_t uid)
         : mPid(pid), mUid(uid) {
@@ -200,7 +236,7 @@
 void MediaCodec::ResourceManagerServiceProxy::addResource(
         int64_t clientId,
         const sp<IResourceManagerClient> &client,
-        const Vector<MediaResource> &resources) {
+        const std::vector<MediaResourceParcel> &resources) {
     Mutex::Autolock _l(mLock);
     if (mService == NULL) {
         return;
@@ -210,7 +246,7 @@
 
 void MediaCodec::ResourceManagerServiceProxy::removeResource(
         int64_t clientId,
-        const Vector<MediaResource> &resources) {
+        const std::vector<MediaResourceParcel> &resources) {
     Mutex::Autolock _l(mLock);
     if (mService == NULL) {
         return;
@@ -227,12 +263,14 @@
 }
 
 bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
-        const Vector<MediaResource> &resources) {
+        const std::vector<MediaResourceParcel> &resources) {
     Mutex::Autolock _l(mLock);
     if (mService == NULL) {
         return false;
     }
-    return mService->reclaimResource(mPid, resources);
+    bool success;
+    Status status = mService->reclaimResource(mPid, resources, &success);
+    return status.isOk() && success;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -506,7 +544,7 @@
     sp<IOMX> omx = client.interface();
 
     sp<IGraphicBufferProducer> bufferProducer;
-    sp<IGraphicBufferSource> bufferSource;
+    sp<hardware::media::omx::V1_0::IGraphicBufferSource> bufferSource;
 
     status_t err = omx->createInputSurface(&bufferProducer, &bufferSource);
 
@@ -527,7 +565,7 @@
       mFlags(0),
       mStickyError(OK),
       mSoftRenderer(NULL),
-      mAnalyticsItem(NULL),
+      mMetricsHandle(0),
       mIsVideo(false),
       mVideoWidth(0),
       mVideoHeight(0),
@@ -548,19 +586,19 @@
     mResourceManagerClient = new ResourceManagerClient(this);
     mResourceManagerService = new ResourceManagerServiceProxy(pid, mUid);
 
-    initAnalyticsItem();
+    initMediametrics();
 }
 
 MediaCodec::~MediaCodec() {
     CHECK_EQ(mState, UNINITIALIZED);
     mResourceManagerService->removeClient(getId(mResourceManagerClient));
 
-    flushAnalyticsItem();
+    flushMediametrics();
 }
 
-void MediaCodec::initAnalyticsItem() {
-    if (mAnalyticsItem == NULL) {
-        mAnalyticsItem = MediaAnalyticsItem::create(kCodecKeyName);
+void MediaCodec::initMediametrics() {
+    if (mMetricsHandle == 0) {
+        mMetricsHandle = mediametrics_create(kCodecKeyName);
     }
 
     mLatencyHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
@@ -574,38 +612,39 @@
     }
 }
 
-void MediaCodec::updateAnalyticsItem() {
-    ALOGV("MediaCodec::updateAnalyticsItem");
-    if (mAnalyticsItem == NULL) {
+void MediaCodec::updateMediametrics() {
+    ALOGV("MediaCodec::updateMediametrics");
+    if (mMetricsHandle == 0) {
         return;
     }
 
+
     if (mLatencyHist.getCount() != 0 ) {
-        mAnalyticsItem->setInt64(kCodecLatencyMax, mLatencyHist.getMax());
-        mAnalyticsItem->setInt64(kCodecLatencyMin, mLatencyHist.getMin());
-        mAnalyticsItem->setInt64(kCodecLatencyAvg, mLatencyHist.getAvg());
-        mAnalyticsItem->setInt64(kCodecLatencyCount, mLatencyHist.getCount());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyMax, mLatencyHist.getMax());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyMin, mLatencyHist.getMin());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyAvg, mLatencyHist.getAvg());
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyCount, mLatencyHist.getCount());
 
         if (kEmitHistogram) {
             // and the histogram itself
             std::string hist = mLatencyHist.emit();
-            mAnalyticsItem->setCString(kCodecLatencyHist, hist.c_str());
+            mediametrics_setCString(mMetricsHandle, kCodecLatencyHist, hist.c_str());
         }
     }
     if (mLatencyUnknown > 0) {
-        mAnalyticsItem->setInt64(kCodecLatencyUnknown, mLatencyUnknown);
+        mediametrics_setInt64(mMetricsHandle, kCodecLatencyUnknown, mLatencyUnknown);
     }
 
 #if 0
     // enable for short term, only while debugging
-    updateEphemeralAnalytics(mAnalyticsItem);
+    updateEphemeralMediametrics(mMetricsHandle);
 #endif
 }
 
-void MediaCodec::updateEphemeralAnalytics(MediaAnalyticsItem *item) {
-    ALOGD("MediaCodec::updateEphemeralAnalytics()");
+void MediaCodec::updateEphemeralMediametrics(mediametrics_handle_t item) {
+    ALOGD("MediaCodec::updateEphemeralMediametrics()");
 
-    if (item == NULL) {
+    if (item == 0) {
         return;
     }
 
@@ -628,28 +667,27 @@
 
     // spit the data (if any) into the supplied analytics record
     if (recentHist.getCount()!= 0 ) {
-        item->setInt64(kCodecRecentLatencyMax, recentHist.getMax());
-        item->setInt64(kCodecRecentLatencyMin, recentHist.getMin());
-        item->setInt64(kCodecRecentLatencyAvg, recentHist.getAvg());
-        item->setInt64(kCodecRecentLatencyCount, recentHist.getCount());
+        mediametrics_setInt64(item, kCodecRecentLatencyMax, recentHist.getMax());
+        mediametrics_setInt64(item, kCodecRecentLatencyMin, recentHist.getMin());
+        mediametrics_setInt64(item, kCodecRecentLatencyAvg, recentHist.getAvg());
+        mediametrics_setInt64(item, kCodecRecentLatencyCount, recentHist.getCount());
 
         if (kEmitHistogram) {
             // and the histogram itself
             std::string hist = recentHist.emit();
-            item->setCString(kCodecRecentLatencyHist, hist.c_str());
+            mediametrics_setCString(item, kCodecRecentLatencyHist, hist.c_str());
         }
     }
 }
 
-void MediaCodec::flushAnalyticsItem() {
-    updateAnalyticsItem();
-    if (mAnalyticsItem != NULL) {
-        // don't log empty records
-        if (mAnalyticsItem->count() > 0) {
-            mAnalyticsItem->selfrecord();
+void MediaCodec::flushMediametrics() {
+    updateMediametrics();
+    if (mMetricsHandle != 0) {
+        if (mediametrics_count(mMetricsHandle) > 0) {
+            mediametrics_selfRecord(mMetricsHandle);
         }
-        delete mAnalyticsItem;
-        mAnalyticsItem = NULL;
+        mediametrics_delete(mMetricsHandle);
+        mMetricsHandle = 0;
     }
 }
 
@@ -754,7 +792,7 @@
 
     if (mBatteryChecker != nullptr) {
         mBatteryChecker->onCodecActivity([this] () {
-            addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+            addResource(MediaResource::VideoBatteryResource());
         });
     }
 
@@ -794,7 +832,7 @@
 
     if (mBatteryChecker != nullptr) {
         mBatteryChecker->onCodecActivity([this] () {
-            addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+            addResource(MediaResource::VideoBatteryResource());
         });
     }
 
@@ -981,9 +1019,10 @@
     // ".secure"
     msg->setString("name", name);
 
-    if (mAnalyticsItem != NULL) {
-        mAnalyticsItem->setCString(kCodecCodec, name.c_str());
-        mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
+    if (mMetricsHandle != 0) {
+        mediametrics_setCString(mMetricsHandle, kCodecCodec, name.c_str());
+        mediametrics_setCString(mMetricsHandle, kCodecMode,
+                                mIsVideo ? kCodecModeVideo : kCodecModeAudio);
     }
 
     if (mIsVideo) {
@@ -991,12 +1030,8 @@
     }
 
     status_t err;
-    Vector<MediaResource> resources;
-    MediaResource::Type type =
-            secureCodec ? MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
-    MediaResource::SubType subtype =
-            mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
-    resources.push_back(MediaResource(type, subtype, 1));
+    std::vector<MediaResourceParcel> resources;
+    resources.push_back(MediaResource::CodecResource(secureCodec, mIsVideo));
     for (int i = 0; i <= kMaxRetry; ++i) {
         if (i > 0) {
             // Don't try to reclaim resource for the first time.
@@ -1044,16 +1079,17 @@
         uint32_t flags) {
     sp<AMessage> msg = new AMessage(kWhatConfigure, this);
 
-    if (mAnalyticsItem != NULL) {
+    if (mMetricsHandle != 0) {
         int32_t profile = 0;
         if (format->findInt32("profile", &profile)) {
-            mAnalyticsItem->setInt32(kCodecProfile, profile);
+            mediametrics_setInt32(mMetricsHandle, kCodecProfile, profile);
         }
         int32_t level = 0;
         if (format->findInt32("level", &level)) {
-            mAnalyticsItem->setInt32(kCodecLevel, level);
+            mediametrics_setInt32(mMetricsHandle, kCodecLevel, level);
         }
-        mAnalyticsItem->setInt32(kCodecEncoder, (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
+        mediametrics_setInt32(mMetricsHandle, kCodecEncoder,
+                              (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
     }
 
     if (mIsVideo) {
@@ -1063,17 +1099,17 @@
             mRotationDegrees = 0;
         }
 
-        if (mAnalyticsItem != NULL) {
-            mAnalyticsItem->setInt32(kCodecWidth, mVideoWidth);
-            mAnalyticsItem->setInt32(kCodecHeight, mVideoHeight);
-            mAnalyticsItem->setInt32(kCodecRotation, mRotationDegrees);
+        if (mMetricsHandle != 0) {
+            mediametrics_setInt32(mMetricsHandle, kCodecWidth, mVideoWidth);
+            mediametrics_setInt32(mMetricsHandle, kCodecHeight, mVideoHeight);
+            mediametrics_setInt32(mMetricsHandle, kCodecRotation, mRotationDegrees);
             int32_t maxWidth = 0;
             if (format->findInt32("max-width", &maxWidth)) {
-                mAnalyticsItem->setInt32(kCodecMaxWidth, maxWidth);
+                mediametrics_setInt32(mMetricsHandle, kCodecMaxWidth, maxWidth);
             }
             int32_t maxHeight = 0;
             if (format->findInt32("max-height", &maxHeight)) {
-                mAnalyticsItem->setInt32(kCodecMaxHeight, maxHeight);
+                mediametrics_setInt32(mMetricsHandle, kCodecMaxHeight, maxHeight);
             }
         }
 
@@ -1095,8 +1131,8 @@
         } else {
             msg->setPointer("descrambler", descrambler.get());
         }
-        if (mAnalyticsItem != NULL) {
-            mAnalyticsItem->setInt32(kCodecCrypto, 1);
+        if (mMetricsHandle != 0) {
+            mediametrics_setInt32(mMetricsHandle, kCodecCrypto, 1);
         }
     } else if (mFlags & kFlagIsSecure) {
         ALOGW("Crypto or descrambler should be given for secure codec");
@@ -1106,15 +1142,11 @@
     mConfigureMsg = msg;
 
     status_t err;
-    Vector<MediaResource> resources;
-    MediaResource::Type type = (mFlags & kFlagIsSecure) ?
-            MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
-    MediaResource::SubType subtype =
-            mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
-    resources.push_back(MediaResource(type, subtype, 1));
+    std::vector<MediaResourceParcel> resources;
+    resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
     // Don't know the buffer size at this point, but it's fine to use 1 because
     // the reclaimResource call doesn't consider the requester's buffer size for now.
-    resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
+    resources.push_back(MediaResource::GraphicMemoryResource(1));
     for (int i = 0; i <= kMaxRetry; ++i) {
         if (i > 0) {
             // Don't try to reclaim resource for the first time.
@@ -1239,18 +1271,16 @@
     return size;
 }
 
-void MediaCodec::addResource(
-        MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
-    Vector<MediaResource> resources;
-    resources.push_back(MediaResource(type, subtype, value));
+void MediaCodec::addResource(const MediaResourceParcel &resource) {
+    std::vector<MediaResourceParcel> resources;
+    resources.push_back(resource);
     mResourceManagerService->addResource(
             getId(mResourceManagerClient), mResourceManagerClient, resources);
 }
 
-void MediaCodec::removeResource(
-        MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
-    Vector<MediaResource> resources;
-    resources.push_back(MediaResource(type, subtype, value));
+void MediaCodec::removeResource(const MediaResourceParcel &resource) {
+    std::vector<MediaResourceParcel> resources;
+    resources.push_back(resource);
     mResourceManagerService->removeResource(getId(mResourceManagerClient), resources);
 }
 
@@ -1258,15 +1288,11 @@
     sp<AMessage> msg = new AMessage(kWhatStart, this);
 
     status_t err;
-    Vector<MediaResource> resources;
-    MediaResource::Type type = (mFlags & kFlagIsSecure) ?
-            MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
-    MediaResource::SubType subtype =
-            mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
-    resources.push_back(MediaResource(type, subtype, 1));
+    std::vector<MediaResourceParcel> resources;
+    resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
     // Don't know the buffer size at this point, but it's fine to use 1 because
     // the reclaimResource call doesn't consider the requester's buffer size for now.
-    resources.push_back(MediaResource(MediaResource::kGraphicMemory, 1));
+    resources.push_back(MediaResource::GraphicMemoryResource(1));
     for (int i = 0; i <= kMaxRetry; ++i) {
         if (i > 0) {
             // Don't try to reclaim resource for the first time.
@@ -1561,22 +1587,22 @@
     return OK;
 }
 
-status_t MediaCodec::getMetrics(MediaAnalyticsItem * &reply) {
+status_t MediaCodec::getMetrics(mediametrics_handle_t &reply) {
 
-    reply = NULL;
+    reply = 0;
 
     // shouldn't happen, but be safe
-    if (mAnalyticsItem == NULL) {
+    if (mMetricsHandle == 0) {
         return UNKNOWN_ERROR;
     }
 
     // update any in-flight data that's not carried within the record
-    updateAnalyticsItem();
+    updateMediametrics();
 
     // send it back to the caller.
-    reply = mAnalyticsItem->dup();
+    reply = mediametrics_dup(mMetricsHandle);
 
-    updateEphemeralAnalytics(reply);
+    updateEphemeralMediametrics(reply);
 
     return OK;
 }
@@ -1708,8 +1734,7 @@
             totalPixel = width * height;
         }
         if (totalPixel >= 1920 * 1080) {
-            addResource(MediaResource::kCpuBoost,
-                    MediaResource::kUnspecifiedSubType, 1);
+            addResource(MediaResource::CpuBoostResource());
             mCpuBoostRequested = true;
         }
     }
@@ -1890,10 +1915,11 @@
                         case CONFIGURING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
                             }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : INITIALIZED);
@@ -1903,10 +1929,11 @@
                         case STARTING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
                             }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : CONFIGURED);
@@ -1944,10 +1971,11 @@
                         case FLUSHING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
 
                                 setState(UNINITIALIZED);
                             } else {
@@ -1977,10 +2005,11 @@
                                 setState(INITIALIZED);
                                 break;
                             default:
-                                mAnalyticsItem->setInt32(kCodecError, err);
-                                mAnalyticsItem->setCString(kCodecErrorState, stateString(mState).c_str());
-                                flushAnalyticsItem();
-                                initAnalyticsItem();
+                                mediametrics_setInt32(mMetricsHandle, kCodecError, err);
+                                mediametrics_setCString(mMetricsHandle, kCodecErrorState,
+                                                        stateString(mState).c_str());
+                                flushMediametrics();
+                                initMediametrics();
                                 setState(UNINITIALIZED);
                                 break;
                             }
@@ -2037,7 +2066,8 @@
                     CHECK(msg->findString("componentName", &mComponentName));
 
                     if (mComponentName.c_str()) {
-                        mAnalyticsItem->setCString(kCodecCodec, mComponentName.c_str());
+                        mediametrics_setCString(mMetricsHandle, kCodecCodec,
+                                                mComponentName.c_str());
                     }
 
                     const char *owner = mCodecInfo->getOwnerName();
@@ -2049,20 +2079,17 @@
                     }
                     mOwnerName = owner;
 
-                    MediaResource::Type resourceType;
                     if (mComponentName.endsWith(".secure")) {
                         mFlags |= kFlagIsSecure;
-                        resourceType = MediaResource::kSecureCodec;
-                        mAnalyticsItem->setInt32(kCodecSecure, 1);
+                        mediametrics_setInt32(mMetricsHandle, kCodecSecure, 1);
                     } else {
                         mFlags &= ~kFlagIsSecure;
-                        resourceType = MediaResource::kNonSecureCodec;
-                        mAnalyticsItem->setInt32(kCodecSecure, 0);
+                        mediametrics_setInt32(mMetricsHandle, kCodecSecure, 0);
                     }
 
                     if (mIsVideo) {
                         // audio codec is currently ignored.
-                        addResource(resourceType, MediaResource::kVideoCodec, 1);
+                        addResource(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));
                     }
 
                     (new AMessage)->postReply(mReplyID);
@@ -2105,14 +2132,15 @@
                     (new AMessage)->postReply(mReplyID);
 
                     // augment our media metrics info, now that we know more things
-                    if (mAnalyticsItem != NULL) {
+                    if (mMetricsHandle != 0) {
                         sp<AMessage> format;
                         if (mConfigureMsg != NULL &&
                             mConfigureMsg->findMessage("format", &format)) {
                                 // format includes: mime
                                 AString mime;
                                 if (format->findString("mime", &mime)) {
-                                    mAnalyticsItem->setCString(kCodecMime, mime.c_str());
+                                    mediametrics_setCString(mMetricsHandle, kCodecMime,
+                                                            mime.c_str());
                                 }
                             }
                     }
@@ -2182,10 +2210,8 @@
 
                     CHECK_EQ(mState, STARTING);
                     if (mIsVideo) {
-                        addResource(
-                                MediaResource::kGraphicMemory,
-                                MediaResource::kUnspecifiedSubType,
-                                getGraphicBufferSize());
+                        addResource(MediaResource::GraphicMemoryResource(
+                                getGraphicBufferSize()));
                     }
                     setState(STARTED);
                     (new AMessage)->postReply(mReplyID);
@@ -3124,7 +3150,7 @@
         {
             if (mBatteryChecker != nullptr) {
                 mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
-                    removeResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+                    removeResource(MediaResource::VideoBatteryResource());
                 });
             }
             break;
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index b027a97..6b5b50e 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -264,7 +264,9 @@
             }
         }
     }
-    global_results->add(kPolicySupportsMultipleSecureCodecs, supportMultipleSecureCodecs);
+    global_results->add(
+            MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs().c_str(),
+            supportMultipleSecureCodecs);
 }
 
 static AString globalResultsToXml(const CodecSettings &results) {
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index b809848..771dfea 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -36,7 +36,7 @@
 using namespace android;
 
 const int64_t kTimeoutWaitForOutputUs = 500000; // 0.5 seconds
-const int64_t kTimeoutWaitForInputUs = 5000; // 5 milliseconds
+const int64_t kTimeoutWaitForInputUs = 0; // don't wait
 const int kTimeoutMaxRetries = 20;
 
 //static
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index cf4edae..ce73676 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -158,7 +158,11 @@
     if (mRetriever->setDataSource(fd, 0, size) == OK) {
         sp<IMemory> mem = mRetriever->extractAlbumArt();
         if (mem != NULL) {
-            MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->pointer());
+            // TODO: Using unsecurePointer() has some associated security pitfalls
+            //       (see declaration for details).
+            //       Either document why it is safe in this case or address the
+            //       issue (e.g. by copying).
+            MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->unsecurePointer());
             return art->clone();
         }
     }
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 02e8ab5..a1e4d43 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -227,6 +227,68 @@
     }
 }
 
+static void parseDolbyVisionProfileLevelFromDvcc(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
+    // dv_major.dv_minor Should be 1.0 or 2.1
+    if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
+        ALOGV("Size %zu, dv_major %d, dv_minor %d", size, ptr[0], ptr[1]);
+        return;
+    }
+
+    const uint8_t profile = ptr[2] >> 1;
+    const uint8_t level = ((ptr[2] & 0x1) << 5) | ((ptr[3] >> 3) & 0x1f);
+    const uint8_t rpu_present_flag = (ptr[3] >> 2) & 0x01;
+    const uint8_t el_present_flag = (ptr[3] >> 1) & 0x01;
+    const uint8_t bl_present_flag = (ptr[3] & 0x01);
+    const int32_t bl_compatibility_id = (int32_t)(ptr[4] >> 4);
+
+    ALOGV("profile-level-compatibility value in dv(c|v)c box %d-%d-%d",
+          profile, level, bl_compatibility_id);
+
+    // All Dolby Profiles will have profile and level info in MediaFormat
+    // Profile 8 and 9 will have bl_compatibility_id too.
+    const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONPROFILETYPE> profiles{
+        {1, OMX_VIDEO_DolbyVisionProfileDvavPen},
+        {3, OMX_VIDEO_DolbyVisionProfileDvheDen},
+        {4, OMX_VIDEO_DolbyVisionProfileDvheDtr},
+        {5, OMX_VIDEO_DolbyVisionProfileDvheStn},
+        {6, OMX_VIDEO_DolbyVisionProfileDvheDth},
+        {7, OMX_VIDEO_DolbyVisionProfileDvheDtb},
+        {8, OMX_VIDEO_DolbyVisionProfileDvheSt},
+        {9, OMX_VIDEO_DolbyVisionProfileDvavSe},
+        {10, OMX_VIDEO_DolbyVisionProfileDvav110},
+    };
+
+    const static ALookup<uint8_t, OMX_VIDEO_DOLBYVISIONLEVELTYPE> levels{
+        {0, OMX_VIDEO_DolbyVisionLevelUnknown},
+        {1, OMX_VIDEO_DolbyVisionLevelHd24},
+        {2, OMX_VIDEO_DolbyVisionLevelHd30},
+        {3, OMX_VIDEO_DolbyVisionLevelFhd24},
+        {4, OMX_VIDEO_DolbyVisionLevelFhd30},
+        {5, OMX_VIDEO_DolbyVisionLevelFhd60},
+        {6, OMX_VIDEO_DolbyVisionLevelUhd24},
+        {7, OMX_VIDEO_DolbyVisionLevelUhd30},
+        {8, OMX_VIDEO_DolbyVisionLevelUhd48},
+        {9, OMX_VIDEO_DolbyVisionLevelUhd60},
+    };
+    // set rpuAssoc
+    if (rpu_present_flag && el_present_flag && !bl_present_flag) {
+        format->setInt32("rpuAssoc", 1);
+    }
+    // set profile & level if they are recognized
+    OMX_VIDEO_DOLBYVISIONPROFILETYPE codecProfile;
+    OMX_VIDEO_DOLBYVISIONLEVELTYPE codecLevel;
+    if (profiles.map(profile, &codecProfile)) {
+        format->setInt32("profile", codecProfile);
+        if (codecProfile == OMX_VIDEO_DolbyVisionProfileDvheSt ||
+            codecProfile == OMX_VIDEO_DolbyVisionProfileDvavSe) {
+            format->setInt32("bl_compatibility_id", bl_compatibility_id);
+        }
+        if (levels.map(level, &codecLevel)) {
+            format->setInt32("level", codecLevel);
+        }
+    }
+}
+
 static void parseH263ProfileLevelFromD263(const uint8_t *ptr, size_t size, sp<AMessage> &format) {
     if (size < 7) {
         return;
@@ -1406,6 +1468,12 @@
         msg->setBuffer("csd-0", buffer);
     }
 
+    if (meta->findData(kKeyDVCC, &type, &data, &size)) {
+        const uint8_t *ptr = (const uint8_t *)data;
+        ALOGV("DV: calling parseDolbyVisionProfileLevelFromDvcc with data size %zu", size);
+        parseDolbyVisionProfileLevelFromDvcc(ptr, size, msg);
+    }
+
     *format = msg;
 
     return OK;
@@ -1801,7 +1869,7 @@
     if (msg->findInt32("frame-rate", &fps) && fps > 0) {
         meta->setInt32(kKeyFrameRate, fps);
     } else if (msg->findFloat("frame-rate", &fpsFloat)
-            && fpsFloat >= 1 && static_cast<int32_t>(fpsFloat) <= INT32_MAX) {
+            && fpsFloat >= 1 && fpsFloat <= (float)INT32_MAX) {
         // truncate values to distinguish between e.g. 24 vs 23.976 fps
         meta->setInt32(kKeyFrameRate, (int32_t)fpsFloat);
     }
@@ -1834,6 +1902,31 @@
             meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
         } else if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
             meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+        } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
+            if (msg->findBuffer("csd-2", &csd2)) {
+                //dvcc should be 24
+                if (csd2->size() == 24) {
+                    meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
+                    uint8_t *dvcc = csd2->data();
+                    const uint8_t profile = dvcc[2] >> 1;
+                    if (profile > 1 && profile < 9) {
+                        std::vector<uint8_t> hvcc(csd0size + 1024);
+                        size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
+                        meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
+                    } else if (DolbyVisionProfileDvav110 == profile) {
+                        meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+                    } else {
+                        sp<ABuffer> csd1;
+                        if (msg->findBuffer("csd-1", &csd1)) {
+                            std::vector<char> avcc(csd0size + csd1->size() + 1024);
+                            size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+                            meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+                        }
+                    }
+                }
+            } else {
+                ALOGW("We need csd-2!!. %s", msg->debugString().c_str());
+            }
         } else if (mime == MEDIA_MIMETYPE_VIDEO_VP9) {
             meta->setData(kKeyVp9CodecPrivate, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_AUDIO_OPUS) {
@@ -1880,8 +1973,18 @@
         meta->setData(kKeyStreamHeader, 'mdat', csd0->data(), csd0->size());
     } else if (msg->findBuffer("d263", &csd0)) {
         meta->setData(kKeyD263, kTypeD263, csd0->data(), csd0->size());
-    }
+    } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION && msg->findBuffer("csd-2", &csd2)) {
+        meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
 
+        // Remove CSD-2 from the data here to avoid duplicate data in meta
+        meta->remove(kKeyOpaqueCSD2);
+
+        if (msg->findBuffer("csd-avc", &csd0)) {
+            meta->setData(kKeyAVCC, kTypeAVCC, csd0->data(), csd0->size());
+        } else if (msg->findBuffer("csd-hevc", &csd0)) {
+            meta->setData(kKeyHVCC, kTypeHVCC, csd0->data(), csd0->size());
+        }
+    }
     // XXX TODO add whatever other keys there are
 
 #if 0
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index 59317e7..de9d12c 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -29,6 +29,7 @@
 #include <media/stagefright/foundation/ColorUtils.h>
 #include <media/stagefright/foundation/FileDescriptor.h>
 
+#include <android-base/properties.h>
 #include <media/hardware/MetadataBufferType.h>
 #include <ui/GraphicBuffer.h>
 #include <gui/BufferItem.h>
@@ -800,6 +801,9 @@
     }
 }
 
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
 bool GraphicBufferSource::calculateCodecTimestamp_l(
         nsecs_t bufferTimeNs, int64_t *codecTimeUs) {
     int64_t timeUs = bufferTimeNs / 1000;
@@ -816,14 +820,15 @@
             mPrevFrameUs = mBaseFrameUs =
                     std::llround((timeUs * mCaptureFps) / mFps);
             mFrameCount = 0;
-        } else {
-            // snap to nearest capture point
+        } else if (mSnapTimestamps) {
             double nFrames = (timeUs - mPrevCaptureUs) * mCaptureFps / 1000000;
             if (nFrames < 0.5 - kTimestampFluctuation) {
                 // skip this frame as it's too close to previous capture
-                ALOGD("skipping frame, timeUs %lld", static_cast<long long>(timeUs));
+                ALOGD("skipping frame, timeUs %lld",
+                      static_cast<long long>(timeUs));
                 return false;
             }
+            // snap to nearest capture point
             if (nFrames <= 1.0) {
                 nFrames = 1.0;
             }
@@ -832,6 +837,22 @@
                     mFrameCount * 1000000 / mCaptureFps);
             mPrevFrameUs = mBaseFrameUs + std::llround(
                     mFrameCount * 1000000 / mFps);
+        } else {
+            if (timeUs <= mPrevCaptureUs) {
+                if (mFrameDropper != NULL && mFrameDropper->disabled()) {
+                    // Warn only, client has disabled frame drop logic possibly for image
+                    // encoding cases where camera's ZSL mode could send out of order frames.
+                    ALOGW("Received frame that's going backward in time");
+                } else {
+                    // Drop the frame if it's going backward in time. Bad timestamp
+                    // could disrupt encoder's rate control completely.
+                    ALOGW("Dropping frame that's going backward in time");
+                    return false;
+                }
+            }
+            mPrevCaptureUs = timeUs;
+            mPrevFrameUs = mBaseFrameUs + std::llround(
+                    (timeUs - mBaseCaptureUs) * (mCaptureFps / mFps));
         }
 
         ALOGV("timeUs %lld, captureUs %lld, frameUs %lld",
@@ -1359,6 +1380,12 @@
 
     mFps = fps;
     mCaptureFps = captureFps;
+    if (captureFps > fps) {
+        mSnapTimestamps = 1 == base::GetIntProperty(
+                "debug.stagefright.snap_timestamps", int64_t(0));
+    } else {
+        mSnapTimestamps = false;
+    }
 
     return OK;
 }
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
index b4c4d4a..ed5d7cb 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
@@ -461,12 +461,33 @@
     // Slow motion mode is enabled if both encoding and capture frame rates are
     // defined and the encoding frame rate is less than half the capture frame
     // rate. In this mode, the source is expected to produce frames with an even
-    // timestamp interval (after rounding) with the configured capture fps. The
-    // first source timestamp is used as the source base time. Afterwards, the
-    // timestamp of each source frame is snapped to the nearest expected capture
-    // timestamp and scaled to match the configured encoding frame rate.
+    // timestamp interval (after rounding) with the configured capture fps.
+    //
+    // These modes must be configured by calling setTimeLapseConfig() before
+    // using this source.
+    //
+    // Timestamp snapping for slow motion recording
+    // ============================================
+    //
+    // When the slow motion mode is configured with setTimeLapseConfig(), the
+    // property "debug.stagefright.snap_timestamps" will be checked. If the
+    // value of the property is set to any value other than 1, mSnapTimestamps
+    // will be set to false. Otherwise, mSnapTimestamps will be set to true.
+    // (mSnapTimestamps will be false for time lapse recording regardless of the
+    // value of the property.)
+    //
+    // If mSnapTimestamps is true, i.e., timestamp snapping is enabled, the
+    // first source timestamp will be used as the source base time; afterwards,
+    // the timestamp of each source frame will be snapped to the nearest
+    // expected capture timestamp and scaled to match the configured encoding
+    // frame rate.
+    //
+    // If timestamp snapping is disabled, the timestamp of source frames will
+    // be scaled to match the ratio between the configured encoding frame rate
+    // and the configured capture frame rate.
 
-    // These modes must be enabled before using this source.
+    // whether timestamps will be snapped
+    bool mSnapTimestamps{true};
 
     // adjusted capture timestamp of the base frame
     int64_t mBaseCaptureUs;
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index d7d871a..f35bce1 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -15,8 +15,10 @@
     },
 
     header_libs: ["libbase_headers"],
-    static_libs: [
+    shared_libs: [
         "libaudioutils",
+    ],
+    static_libs: [
         "libFLAC",
     ],
 }
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
index a4f798e..6c8102b 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
@@ -169,7 +169,7 @@
 
     int32 i, j;
 
-    *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)((float)0x7FFFFFFF / 18.0f - 1.0f)) >> 15;
+    *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)((float)0x7FFFFFFF / (float)18 - 1.0f)) >> 15;
 
 
     if (gr_info->window_switching_flag &&  gr_info->block_type == 2)
diff --git a/media/libstagefright/codecs/on2/enc/Android.bp b/media/libstagefright/codecs/on2/enc/Android.bp
index cd69e0d..705e554 100644
--- a/media/libstagefright/codecs/on2/enc/Android.bp
+++ b/media/libstagefright/codecs/on2/enc/Android.bp
@@ -21,4 +21,5 @@
     },
 
     shared_libs: ["libvpx"],
+    header_libs: ["libbase_headers"],
 }
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index da86758..87e8fd4 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -1426,75 +1426,90 @@
     RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
 
     UWORD32 ui_exec_done;
+    WORD32 i_num_preroll = 0;
     /* Checking for end of processing */
     err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DONE_QUERY,
                                 &ui_exec_done);
     RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DONE_QUERY");
 
-#ifdef ENABLE_MPEG_D_DRC
+    err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+                              IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES,
+                              &i_num_preroll);
+
+    RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES");
     {
-        if (ui_exec_done != 1) {
-            VOID* p_array;        // ITTIAM:buffer to handle gain payload
-            WORD32 buf_size = 0;  // ITTIAM:gain payload length
-            WORD32 bit_str_fmt = 1;
-            WORD32 gain_stream_flag = 1;
+        int32_t pi_preroll_frame_offset = 0;
+        do {
+#ifdef ENABLE_MPEG_D_DRC
+            if (ui_exec_done != 1) {
+                VOID* p_array;        // ITTIAM:buffer to handle gain payload
+                WORD32 buf_size = 0;  // ITTIAM:gain payload length
+                WORD32 bit_str_fmt = 1;
+                WORD32 gain_stream_flag = 1;
 
-            err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
-                                        IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
-            RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
+                err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+                                            IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN, &buf_size);
+                RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_LEN");
 
-            err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
-                                        IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
-            RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
+                err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CONFIG_PARAM,
+                                            IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF, &p_array);
+                RETURN_IF_FATAL(err_code, "IA_ENHAACPLUS_DEC_CONFIG_GAIN_PAYLOAD_BUF");
 
-            if (buf_size > 0) {
-                /*Set bitstream_split_format */
-                err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
-                                          IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
-                RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+                if (buf_size > 0) {
+                    /*Set bitstream_split_format */
+                    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+                                              IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT, &bit_str_fmt);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
 
-                memcpy(mDrcInBuf, p_array, buf_size);
-                /* Set number of bytes to be processed */
-                err_code =
-                    ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS, 0, &buf_size);
-                RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+                    memcpy(mDrcInBuf, p_array, buf_size);
+                    /* Set number of bytes to be processed */
+                    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES_BS,
+                                              0, &buf_size);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
 
-                err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
-                                          IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG, &gain_stream_flag);
-                RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+                    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_CONFIG_PARAM,
+                                              IA_DRC_DEC_CONFIG_GAIN_STREAM_FLAG,
+                                              &gain_stream_flag);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
 
-                /* Execute process */
-                err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
-                                          IA_CMD_TYPE_INIT_CPY_BSF_BUFF, NULL);
-                RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
+                    /* Execute process */
+                    err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_INIT,
+                                              IA_CMD_TYPE_INIT_CPY_BSF_BUFF, NULL);
+                    RETURN_IF_FATAL(err_code, "IA_DRC_DEC_CONFIG_PARAM_BITS_FORMAT");
 
-                mMpegDDRCPresent = 1;
+                    mMpegDDRCPresent = 1;
+                }
             }
-        }
-    }
 #endif
-    /* How much buffer is used in input buffers */
-    err_code =
-        ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF, 0, bytesConsumed);
-    RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF");
+            /* How much buffer is used in input buffers */
+            err_code =
+                ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_CURIDX_INPUT_BUF,
+                                 0, bytesConsumed);
+            RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_CURIDX_INPUT_BUF");
 
-    /* Get the output bytes */
-    err_code = ixheaacd_dec_api(mXheaacCodecHandle, IA_API_CMD_GET_OUTPUT_BYTES, 0, outBytes);
-    RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES");
+            /* Get the output bytes */
+            err_code = ixheaacd_dec_api(mXheaacCodecHandle,
+                                        IA_API_CMD_GET_OUTPUT_BYTES, 0, outBytes);
+            RETURN_IF_FATAL(err_code, "IA_API_CMD_GET_OUTPUT_BYTES");
 #ifdef ENABLE_MPEG_D_DRC
 
-    if (mMpegDDRCPresent == 1) {
-        memcpy(mDrcInBuf, mOutputBuffer, *outBytes);
-        err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES, 0, outBytes);
-        RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
+            if (mMpegDDRCPresent == 1) {
+                memcpy(mDrcInBuf, mOutputBuffer + pi_preroll_frame_offset, *outBytes);
+                pi_preroll_frame_offset += *outBytes;
+                err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_SET_INPUT_BYTES,
+                                          0, outBytes);
+                RETURN_IF_FATAL(err_code, "IA_API_CMD_SET_INPUT_BYTES");
 
-        err_code =
-            ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, NULL);
-        RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
+                err_code = ia_drc_dec_api(mMpegDDrcHandle, IA_API_CMD_EXECUTE,
+                                          IA_CMD_TYPE_DO_EXECUTE, NULL);
+                RETURN_IF_FATAL(err_code, "IA_CMD_TYPE_DO_EXECUTE");
 
-        memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
-    }
+                memcpy(mOutputBuffer, mDrcOutBuf, *outBytes);
+            }
 #endif
+            i_num_preroll--;
+        } while (i_num_preroll > 0);
+    }
     return IA_NO_ERROR;
 }
 
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index d685321..c7dc415 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -324,8 +324,8 @@
 }
 
 #define DECLARE_YUV2RGBFUNC(func, rgb) int (*func)(     \
-        const uint8*, int, const uint8*, int,           \
-        const uint8*, int, uint8*, int, int, int)       \
+        const uint8_t*, int, const uint8_t*, int,           \
+        const uint8_t*, int, uint8_t*, int, int, int)       \
         = mSrcColorSpace.isBt709() ? libyuv::H420To##rgb \
         : mSrcColorSpace.isJpeg() ? libyuv::J420To##rgb  \
         : libyuv::I420To##rgb
@@ -350,7 +350,7 @@
     {
         DECLARE_YUV2RGBFUNC(func, RGB565);
         (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
-                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
+                (uint8_t *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
         break;
     }
 
@@ -358,7 +358,7 @@
     {
         DECLARE_YUV2RGBFUNC(func, ABGR);
         (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
-                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
+                (uint8_t *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
         break;
     }
 
@@ -366,7 +366,7 @@
     {
         DECLARE_YUV2RGBFUNC(func, ARGB);
         (*func)(src_y, src.mStride, src_u, src.mStride / 2, src_v, src.mStride / 2,
-                (uint8 *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
+                (uint8_t *)dst_ptr, dst.mStride, src.cropWidth(), src.cropHeight());
         break;
     }
 
@@ -391,17 +391,17 @@
 
     switch (mDstFormat) {
     case OMX_COLOR_Format16bitRGB565:
-        libyuv::NV12ToRGB565(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+        libyuv::NV12ToRGB565(src_y, src.mStride, src_u, src.mStride, (uint8_t *)dst_ptr,
                 dst.mStride, src.cropWidth(), src.cropHeight());
         break;
 
     case OMX_COLOR_Format32bitBGRA8888:
-        libyuv::NV12ToARGB(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+        libyuv::NV12ToARGB(src_y, src.mStride, src_u, src.mStride, (uint8_t *)dst_ptr,
                 dst.mStride, src.cropWidth(), src.cropHeight());
         break;
 
     case OMX_COLOR_Format32BitRGBA8888:
-        libyuv::NV12ToABGR(src_y, src.mStride, src_u, src.mStride, (uint8 *)dst_ptr,
+        libyuv::NV12ToABGR(src_y, src.mStride, src_u, src.mStride, (uint8_t *)dst_ptr,
                 dst.mStride, src.cropWidth(), src.cropHeight());
         break;
 
diff --git a/media/libstagefright/exports.lds b/media/libstagefright/exports.lds
index aabc233..f5ddf1e 100644
--- a/media/libstagefright/exports.lds
+++ b/media/libstagefright/exports.lds
@@ -395,7 +395,6 @@
         ScaleFilterCols_NEON*;
         ScaleFilterReduce;
         ScaleFilterRows_NEON*;
-        ScaleOffset;
         ScalePlane;
         ScalePlane_16;
         ScalePlaneBilinearDown;
@@ -505,4 +504,8 @@
         YUY2ToYRow_Any_NEON*;
         YUY2ToYRow_C;
         YUY2ToYRow_NEON*;
+        ogg_packet_*;
+        ogg_page_*;
+        ogg_stream_*;
+        ogg_sync_*;
 };
diff --git a/media/libstagefright/flac/dec/Android.bp b/media/libstagefright/flac/dec/Android.bp
index b494e16..7ebe71f 100644
--- a/media/libstagefright/flac/dec/Android.bp
+++ b/media/libstagefright/flac/dec/Android.bp
@@ -1,4 +1,4 @@
-cc_library {
+cc_library_shared {
     name: "libstagefright_flacdec",
     vendor_available: true,
 
@@ -18,29 +18,20 @@
         cfi: true,
     },
 
-    static: {
-        whole_static_libs: [
-            "libFLAC",
-            "libaudioutils",
-        ],
-    },
-
-    shared: {
-        static_libs: [
-            "libFLAC",
-            "libaudioutils",
-        ],
-        export_static_lib_headers: [
-            "libFLAC",
-        ],
-    },
-
     shared_libs: [
+        "libaudioutils",
         "liblog",
     ],
 
+    static_libs: [
+        "libFLAC",
+    ],
+
+    export_static_lib_headers: [
+        "libFLAC",
+    ],
+
     header_libs: [
         "libmedia_headers",
-        "libFLAC-headers",
     ],
 }
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index df66ac6..7752bda 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -22,7 +22,6 @@
 
 #include "AMessage.h"
 
-#include <binder/Parcel.h>
 #include <log/log.h>
 
 #include "AAtomizer.h"
@@ -34,6 +33,10 @@
 
 #include <media/stagefright/foundation/hexdump.h>
 
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
 namespace android {
 
 extern ALooperRoster gLooperRoster;
@@ -643,6 +646,7 @@
     return s;
 }
 
+#ifndef __ANDROID_VNDK__
 // static
 sp<AMessage> AMessage::FromParcel(const Parcel &parcel, size_t maxNestingLevel) {
     int32_t what = parcel.readInt32();
@@ -809,6 +813,7 @@
         }
     }
 }
+#endif  // __ANDROID_VNDK__
 
 sp<AMessage> AMessage::changesFrom(const sp<const AMessage> &other, bool deep) const {
     if (other == NULL) {
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index a8adff5..4bd186c 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -23,11 +23,14 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <binder/Parcel.h>
 #include <utils/String8.h>
 #include "ADebug.h"
 #include "AString.h"
 
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
 namespace android {
 
 // static
@@ -362,6 +365,7 @@
     return !strcasecmp(mData + mSize - suffixLen, suffix);
 }
 
+#ifndef __ANDROID_VNDK__
 // static
 AString AString::FromParcel(const Parcel &parcel) {
     size_t size = static_cast<size_t>(parcel.readInt32());
@@ -376,6 +380,7 @@
     }
     return err;
 }
+#endif
 
 AString AStringPrintf(const char *format, ...) {
     va_list ap;
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index b95f054..5485f6d 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -79,6 +79,17 @@
         "hexdump.cpp",
     ],
 
+    target: {
+        vendor: {
+            exclude_shared_libs: [
+                "libbinder",
+            ],
+            cflags: [
+                "-DNO_IMEMORY",
+            ],
+        },
+    },
+
     clang: true,
 
     sanitize: {
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
index 9beac05..8e245dc 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -72,7 +72,7 @@
             }
         } else {
             getSharedControl()->clear();
-            mData = (uint8_t *)mMemory->pointer() + sizeof(SharedControl);
+            mData = (uint8_t *)mMemory->unsecurePointer() + sizeof(SharedControl);
             ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
         }
     }
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libstagefright/foundation/MediaBufferGroup.cpp
index 84ff9a6..3c25047 100644
--- a/media/libstagefright/foundation/MediaBufferGroup.cpp
+++ b/media/libstagefright/foundation/MediaBufferGroup.cpp
@@ -75,7 +75,7 @@
 
         for (size_t i = 0; i < buffers; ++i) {
             sp<IMemory> mem = memoryDealer->allocate(augmented_size);
-            if (mem.get() == nullptr || mem->pointer() == nullptr) {
+            if (mem.get() == nullptr || mem->unsecurePointer() == nullptr) {
                 ALOGW("Only allocated %zu shared buffers of size %zu", i, buffer_size);
                 break;
             }
diff --git a/media/libstagefright/foundation/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
index 1d0a607..8174597 100644
--- a/media/libstagefright/foundation/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -17,7 +17,6 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MetaData"
 #include <inttypes.h>
-#include <binder/Parcel.h>
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
 
@@ -29,6 +28,10 @@
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MetaData.h>
 
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
 namespace android {
 
 
@@ -45,6 +48,7 @@
 MetaData::~MetaData() {
 }
 
+#ifndef __ANDROID_VNDK__
 /* static */
 sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
 
@@ -52,6 +56,7 @@
     meta->updateFromParcel(parcel);
     return meta;
 }
+#endif
 
 }  // namespace android
 
diff --git a/media/libstagefright/foundation/MetaDataBase.cpp b/media/libstagefright/foundation/MetaDataBase.cpp
index bfea6f1..4b439c6 100644
--- a/media/libstagefright/foundation/MetaDataBase.cpp
+++ b/media/libstagefright/foundation/MetaDataBase.cpp
@@ -17,7 +17,6 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MetaDataBase"
 #include <inttypes.h>
-#include <binder/Parcel.h>
 #include <utils/KeyedVector.h>
 #include <utils/Log.h>
 
@@ -29,6 +28,10 @@
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MetaDataBase.h>
 
+#ifndef __ANDROID_VNDK__
+#include <binder/Parcel.h>
+#endif
+
 namespace android {
 
 struct MetaDataBase::typed_data {
@@ -449,6 +452,7 @@
     }
 }
 
+#ifndef __ANDROID_VNDK__
 status_t MetaDataBase::writeToParcel(Parcel &parcel) {
     status_t ret;
     size_t numItems = mInternalData->mItems.size();
@@ -528,6 +532,7 @@
     ALOGW("no metadata in parcel");
     return UNKNOWN_ERROR;
 }
+#endif
 
 }  // namespace android
 
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index 513e41f..f5687e0 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -292,6 +292,10 @@
         *opusHeadSize = data_size;
         return true;
     } else if (memcmp(AOPUS_CSD_MARKER_PREFIX, data, AOPUS_CSD_MARKER_PREFIX_SIZE) == 0) {
+        if (data_size < AOPUS_UNIFIED_CSD_MINSIZE || data_size > AOPUS_UNIFIED_CSD_MAXSIZE) {
+            ALOGD("Unexpected size for unified opus csd %zu", data_size);
+            return false;
+        }
         size_t i = 0;
         bool found = false;
         while (i <= data_size - AOPUS_MARKER_SIZE - AOPUS_LENGTH_SIZE) {
diff --git a/media/libstagefright/foundation/TEST_MAPPING b/media/libstagefright/foundation/TEST_MAPPING
new file mode 100644
index 0000000..3301c4b
--- /dev/null
+++ b/media/libstagefright/foundation/TEST_MAPPING
@@ -0,0 +1,5 @@
+{
+  "presubmit": [
+    { "name": "sf_foundation_test" }
+  ]
+}
diff --git a/media/libstagefright/foundation/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
index e8a6083..f53d2c9 100644
--- a/media/libstagefright/foundation/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -166,10 +166,21 @@
     unsigned pic_height_in_map_units_minus1 = parseUE(&br);
     unsigned frame_mbs_only_flag = br.getBits(1);
 
-    *width = pic_width_in_mbs_minus1 * 16 + 16;
+    //    *width = pic_width_in_mbs_minus1 * 16 + 16;
+    if (__builtin_mul_overflow(pic_width_in_mbs_minus1, 16, &pic_width_in_mbs_minus1) ||
+        __builtin_add_overflow(pic_width_in_mbs_minus1, 16, width)) {
+        *width = 0;
+    }
 
-    *height = (2 - frame_mbs_only_flag)
-        * (pic_height_in_map_units_minus1 * 16 + 16);
+    //    *height = (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 * 16 + 16);
+    if (__builtin_mul_overflow(
+                pic_height_in_map_units_minus1, 16, &pic_height_in_map_units_minus1) ||
+        __builtin_add_overflow(
+                pic_height_in_map_units_minus1, 16, &pic_height_in_map_units_minus1) ||
+        __builtin_mul_overflow(
+                pic_height_in_map_units_minus1, (2 - frame_mbs_only_flag), height)) {
+        *height = 0;
+    }
 
     if (!frame_mbs_only_flag) {
         br.getBits(1);  // mb_adaptive_frame_field_flag
@@ -202,17 +213,19 @@
 
 
         // *width -= (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX;
-        if(__builtin_add_overflow(frame_crop_left_offset, frame_crop_right_offset, &frame_crop_left_offset) ||
-            __builtin_mul_overflow(frame_crop_left_offset, cropUnitX, &frame_crop_left_offset) ||
-            __builtin_sub_overflow(*width, frame_crop_left_offset, width) ||
+        if(__builtin_add_overflow(
+                   frame_crop_left_offset, frame_crop_right_offset, &frame_crop_left_offset) ||
+           __builtin_mul_overflow(frame_crop_left_offset, cropUnitX, &frame_crop_left_offset) ||
+           __builtin_sub_overflow(*width, frame_crop_left_offset, width) ||
             *width < 0) {
             *width = 0;
         }
 
         //*height -= (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
-        if(__builtin_add_overflow(frame_crop_top_offset, frame_crop_bottom_offset, &frame_crop_top_offset) ||
-            __builtin_mul_overflow(frame_crop_top_offset, cropUnitY, &frame_crop_top_offset) ||
-            __builtin_sub_overflow(*height, frame_crop_top_offset, height) ||
+        if(__builtin_add_overflow(
+                   frame_crop_top_offset, frame_crop_bottom_offset, &frame_crop_top_offset) ||
+           __builtin_mul_overflow(frame_crop_top_offset, cropUnitY, &frame_crop_top_offset) ||
+           __builtin_sub_overflow(*height, frame_crop_top_offset, height) ||
             *height < 0) {
             *height = 0;
         }
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
index 742651e..b5d6666 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AMessage.h
@@ -63,6 +63,7 @@
     AMessage();
     AMessage(uint32_t what, const sp<const AHandler> &handler);
 
+#ifndef __ANDROID_VNDK__
     // Construct an AMessage from a parcel.
     // nestingAllowed determines how many levels AMessage can be nested inside
     // AMessage. The default value here is arbitrarily set to 255.
@@ -87,6 +88,7 @@
     // All items in the AMessage must have types that are recognized by
     // FromParcel(); otherwise, TRESPASS error will occur.
     void writeToParcel(Parcel *parcel) const;
+#endif
 
     void setWhat(uint32_t what);
     uint32_t what() const;
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
index 0f6299c..deef0d4 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AString.h
@@ -89,8 +89,10 @@
 
     void tolower();
 
+#ifndef __ANDROID_VNDK__
     static AString FromParcel(const Parcel &parcel);
     status_t writeToParcel(Parcel *parcel) const;
+#endif
 
 private:
     constexpr static const char *kEmptyString = "";
diff --git a/media/libstagefright/foundation/tests/Android.bp b/media/libstagefright/foundation/tests/Android.bp
new file mode 100644
index 0000000..f2157c9
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Android.bp
@@ -0,0 +1,27 @@
+cc_test {
+    name: "sf_foundation_test",
+    test_suites: ["device-tests"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    include_dirs: [
+        "frameworks/av/include",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+
+    srcs: [
+        "AData_test.cpp",
+        "Base64_test.cpp",
+        "Flagged_test.cpp",
+        "TypeTraits_test.cpp",
+        "Utils_test.cpp",
+    ],
+}
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
deleted file mode 100644
index a9e3c76..0000000
--- a/media/libstagefright/foundation/tests/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := sf_foundation_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-	AData_test.cpp \
-	Base64_test.cpp \
-	Flagged_test.cpp \
-	TypeTraits_test.cpp \
-	Utils_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libstagefright_foundation \
-	libutils \
-
-LOCAL_C_INCLUDES := \
-	frameworks/av/include \
-
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CLANG := true
-
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 4d0848a..fdcde29 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -2161,7 +2161,9 @@
             return ERROR_MALFORMED;
         }
 
-        CHECK_LE(offset + aac_frame_length, buffer->size());
+        if (aac_frame_length > buffer->size() - offset) {
+            return ERROR_MALFORMED;
+        }
 
         int64_t unitTimeUs = timeUs + numSamples * 1000000LL / sampleRate;
         offset += aac_frame_length;
diff --git a/media/libstagefright/include/FrameCaptureLayer.h b/media/libstagefright/include/FrameCaptureLayer.h
new file mode 100644
index 0000000..23fd5e5
--- /dev/null
+++ b/media/libstagefright/include/FrameCaptureLayer.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAME_CAPTURE_LAYER_H_
+#define FRAME_CAPTURE_LAYER_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <gui/IConsumerListener.h>
+#include <ui/GraphicTypes.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+
+namespace android {
+
+class GraphicBuffer;
+class IGraphicBufferConsumer;
+class Rect;
+class Surface;
+
+/*
+ * This class is a simple BufferQueue consumer implementation to
+ * obtain a decoded buffer output from MediaCodec. The output
+ * buffer is then sent to FrameCaptureProcessor to be converted
+ * to sRGB properly.
+ */
+struct FrameCaptureLayer : public ConsumerListener {
+    FrameCaptureLayer();
+    ~FrameCaptureLayer() = default;
+
+    // ConsumerListener
+    void onFrameAvailable(const BufferItem& /*item*/) override;
+    void onBuffersReleased() override;
+    void onSidebandStreamChanged() override;
+
+    status_t init();
+
+    sp<Surface> getSurface() { return mSurface; }
+
+    status_t capture(const ui::PixelFormat reqPixelFormat,
+            const Rect &sourceCrop, sp<GraphicBuffer> *outBuffer);
+
+private:
+    struct BufferLayer;
+    // Note: do not hold any sp ref to GraphicBufferSource
+    // GraphicBufferSource is holding an sp to us, holding any sp ref
+    // to GraphicBufferSource will cause circular dependency and both
+    // object will not be released.
+    sp<IGraphicBufferConsumer> mConsumer;
+    sp<Surface> mSurface;
+    std::map<int32_t, sp<GraphicBuffer> > mSlotToBufferMap;
+
+    Mutex mLock;
+    Condition mCondition;
+    bool mFrameAvailable GUARDED_BY(mLock);
+
+    status_t acquireBuffer(BufferItem *bi);
+    status_t releaseBuffer(const BufferItem &bi);
+
+    DISALLOW_EVIL_CONSTRUCTORS(FrameCaptureLayer);
+};
+
+}  // namespace android
+
+#endif  // FRAME_CAPTURE_LAYER_H_
diff --git a/media/libstagefright/include/FrameDecoder.h b/media/libstagefright/include/FrameDecoder.h
index dc58c15..353c957 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -24,15 +24,16 @@
 #include <media/stagefright/foundation/ABase.h>
 #include <media/MediaSource.h>
 #include <media/openmax/OMX_Video.h>
-#include <system/graphics-base.h>
+#include <ui/GraphicTypes.h>
 
 namespace android {
 
 struct AMessage;
-class MediaCodecBuffer;
-class IMediaSource;
-class VideoFrame;
 struct MediaCodec;
+class IMediaSource;
+class MediaCodecBuffer;
+class Surface;
+class VideoFrame;
 
 struct FrameRect {
     int32_t left, top, right, bottom;
@@ -44,13 +45,10 @@
             const sp<MetaData> &trackMeta,
             const sp<IMediaSource> &source);
 
-    status_t init(
-            int64_t frameTimeUs, size_t numFrames, int option, int colorFormat);
+    status_t init(int64_t frameTimeUs, int option, int colorFormat);
 
     sp<IMemory> extractFrame(FrameRect *rect = NULL);
 
-    status_t extractFrames(std::vector<sp<IMemory> >* frames);
-
     static sp<IMemory> getMetadataOnly(
             const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail = false);
 
@@ -59,9 +57,9 @@
 
     virtual sp<AMessage> onGetFormatAndSeekOptions(
             int64_t frameTimeUs,
-            size_t numFrames,
             int seekMode,
-            MediaSource::ReadOptions *options) = 0;
+            MediaSource::ReadOptions *options,
+            sp<Surface> *window) = 0;
 
     virtual status_t onExtractRect(FrameRect *rect) = 0;
 
@@ -79,29 +77,30 @@
 
     sp<MetaData> trackMeta()     const      { return mTrackMeta; }
     OMX_COLOR_FORMATTYPE dstFormat() const  { return mDstFormat; }
+    ui::PixelFormat captureFormat() const   { return mCaptureFormat; }
     int32_t dstBpp()             const      { return mDstBpp; }
-
-    void addFrame(const sp<IMemory> &frame) {
-        mFrames.push_back(frame);
-    }
+    void setFrame(const sp<IMemory> &frameMem) { mFrameMemory = frameMem; }
 
 private:
     AString mComponentName;
     sp<MetaData> mTrackMeta;
     sp<IMediaSource> mSource;
     OMX_COLOR_FORMATTYPE mDstFormat;
+    ui::PixelFormat mCaptureFormat;
     int32_t mDstBpp;
-    std::vector<sp<IMemory> > mFrames;
+    sp<IMemory> mFrameMemory;
     MediaSource::ReadOptions mReadOptions;
     sp<MediaCodec> mDecoder;
     sp<AMessage> mOutputFormat;
     bool mHaveMoreInputs;
     bool mFirstSample;
+    sp<Surface> mSurface;
 
     status_t extractInternal();
 
     DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
 };
+struct FrameCaptureLayer;
 
 struct VideoFrameDecoder : public FrameDecoder {
     VideoFrameDecoder(
@@ -112,9 +111,9 @@
 protected:
     virtual sp<AMessage> onGetFormatAndSeekOptions(
             int64_t frameTimeUs,
-            size_t numFrames,
             int seekMode,
-            MediaSource::ReadOptions *options) override;
+            MediaSource::ReadOptions *options,
+            sp<Surface> *window) override;
 
     virtual status_t onExtractRect(FrameRect *rect) override {
         // Rect extraction for sequences is not supported for now.
@@ -134,11 +133,16 @@
             bool *done) override;
 
 private:
+    sp<FrameCaptureLayer> mCaptureLayer;
+    VideoFrame *mFrame;
     bool mIsAvcOrHevc;
     MediaSource::ReadOptions::SeekMode mSeekMode;
     int64_t mTargetTimeUs;
-    size_t mNumFrames;
-    size_t mNumFramesDecoded;
+    List<int64_t> mSampleDurations;
+    int64_t mDefaultSampleDurationUs;
+
+    sp<Surface> initSurface();
+    status_t captureSurface();
 };
 
 struct ImageDecoder : public FrameDecoder {
@@ -150,9 +154,9 @@
 protected:
     virtual sp<AMessage> onGetFormatAndSeekOptions(
             int64_t frameTimeUs,
-            size_t numFrames,
             int seekMode,
-            MediaSource::ReadOptions *options) override;
+            MediaSource::ReadOptions *options,
+            sp<Surface> *window) override;
 
     virtual status_t onExtractRect(FrameRect *rect) override;
 
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 784fd36..7754de4 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -37,6 +37,15 @@
 #define TRACK_BUFFER_TIMING     0
 
 namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+struct IGraphicBufferSource;
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
 
 struct ABuffer;
 class ACodecBufferChannel;
@@ -279,7 +288,7 @@
     size_t mNumUndequeuedBuffers;
     sp<DataConverter> mConverter[2];
 
-    sp<IGraphicBufferSource> mGraphicBufferSource;
+    sp<hardware::media::omx::V1_0::IGraphicBufferSource> mGraphicBufferSource;
     int64_t mRepeatFrameDelayUs;
     int64_t mMaxPtsGapUs;
     float mMaxFps;
@@ -496,6 +505,7 @@
             AudioEncoding encoding = kAudioEncodingPcm16bit);
 
     status_t setPriority(int32_t priority);
+    status_t setLowLatency(int32_t lowLatency);
     status_t setLatency(uint32_t latency);
     status_t getLatency(uint32_t *latency);
     status_t setAudioPresentation(int32_t presentationId, int32_t programId);
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index ad60f46..e728c00 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -42,12 +42,20 @@
 struct RenderedFrameInfo;
 class Surface;
 struct ICrypto;
+class IMemory;
+
 namespace hardware {
 namespace cas {
 namespace native {
 namespace V1_0 {
 struct IDescrambler;
-}}}}
+}}}
+namespace drm {
+namespace V1_0 {
+struct SharedBuffer;
+}}
+}
+
 using hardware::cas::native::V1_0::IDescrambler;
 
 struct CodecBase : public AHandler, /* static */ ColorUtils {
@@ -314,6 +322,18 @@
      */
     virtual void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) = 0;
 
+    /**
+     * Convert binder IMemory to drm SharedBuffer
+     *
+     * \param   memory      IMemory object to store encrypted content.
+     * \param   heapSeqNum  Heap sequence number from ICrypto; -1 if N/A
+     * \param   buf         SharedBuffer structure to fill.
+     */
+    static void IMemoryToSharedBuffer(
+            const sp<IMemory> &memory,
+            int32_t heapSeqNum,
+            hardware::drm::V1_0::SharedBuffer *buf);
+
 protected:
     std::unique_ptr<CodecBase::BufferCallback> mCallback;
     sp<ICrypto> mCrypto;
diff --git a/media/libstagefright/include/media/stagefright/FrameCaptureProcessor.h b/media/libstagefright/include/media/stagefright/FrameCaptureProcessor.h
new file mode 100644
index 0000000..66e5daa
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/FrameCaptureProcessor.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAME_CAPTURE_PROCESSOR_H_
+#define FRAME_CAPTURE_PROCESSOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandler.h>
+
+namespace android {
+
+struct AMessage;
+class GraphicBuffer;
+class Rect;
+
+namespace renderengine {
+class RenderEngine;
+struct LayerSettings;
+}
+
+/*
+ * Process a decoded graphic buffer through RenderEngine to
+ * convert it to sRGB.
+ *
+ * This class is a singleton that holds one instance of RenderEngine
+ * and its event queue (on which the GL context runs). The RenderEngine
+ * is created upon the first getInstance().
+ */
+class FrameCaptureProcessor : public AHandler {
+
+public:
+
+    struct Layer : public RefBase {
+        virtual void getLayerSettings(
+                const Rect &sourceCrop, uint32_t textureName,
+                renderengine::LayerSettings *layerSettings) = 0;
+    };
+
+    static sp<FrameCaptureProcessor> getInstance();
+
+    status_t capture(
+            const sp<Layer> &layer,
+            const Rect &sourceCrop, const sp<GraphicBuffer> &outBuffer);
+
+protected:
+    virtual ~FrameCaptureProcessor();
+    void onMessageReceived(const sp<AMessage> &msg);
+
+private:
+    FrameCaptureProcessor();
+
+    enum {
+        kWhatCreate,
+        kWhatCapture,
+    };
+
+    static Mutex sLock;
+    static sp<FrameCaptureProcessor> sInstance GUARDED_BY(sLock);
+
+    constexpr static float sDefaultMaxLumiance = 500.0f;
+
+    status_t mInitStatus;
+    sp<ALooper> mLooper;
+    std::unique_ptr<renderengine::RenderEngine> mRE;
+    uint32_t mTextureName;
+
+    static status_t PostAndAwaitResponse(
+            const sp<AMessage> &msg, sp<AMessage> *response);
+    static void PostReplyWithError(
+            const sp<AReplyToken> &replyID, status_t err);
+
+    status_t initCheck() { return mInitStatus; }
+    void createRenderEngine();
+
+    // message handlers
+    status_t onCreate();
+    status_t onCapture(const sp<Layer> &layer,
+            const Rect &sourceCrop, const sp<GraphicBuffer> &outBuffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(FrameCaptureProcessor);
+};
+
+}  // namespace android
+
+#endif  // FRAME_CAPTURE_PROCESSOR_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
index ace63ae..9145b63 100644
--- a/media/libstagefright/include/media/stagefright/MediaBuffer.h
+++ b/media/libstagefright/include/media/stagefright/MediaBuffer.h
@@ -48,7 +48,11 @@
     explicit MediaBuffer(const sp<ABuffer> &buffer);
 #ifndef NO_IMEMORY
     MediaBuffer(const sp<IMemory> &mem) :
-        MediaBuffer((uint8_t *)mem->pointer() + sizeof(SharedControl), mem->size()) {
+         // TODO: Using unsecurePointer() has some associated security pitfalls
+         //       (see declaration for details).
+         //       Either document why it is safe in this case or address the
+         //       issue (e.g. by copying).
+        MediaBuffer((uint8_t *)mem->unsecurePointer() + sizeof(SharedControl), mem->size()) {
         // delegate and override mMemory
         mMemory = mem;
     }
@@ -94,9 +98,13 @@
 
     virtual int remoteRefcount() const {
 #ifndef NO_IMEMORY
-        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
+         // TODO: Using unsecurePointer() has some associated security pitfalls
+         //       (see declaration for details).
+         //       Either document why it is safe in this case or address the
+         //       issue (e.g. by copying).
+        if (mMemory.get() == nullptr || mMemory->unsecurePointer() == nullptr) return 0;
         int32_t remoteRefcount =
-                reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
+                reinterpret_cast<SharedControl *>(mMemory->unsecurePointer())->getRemoteRefcount();
         // Sanity check so that remoteRefCount() is non-negative.
         return remoteRefcount >= 0 ? remoteRefcount : 0; // do not allow corrupted data.
 #else
@@ -107,8 +115,12 @@
     // returns old value
     int addRemoteRefcount(int32_t value) {
 #ifndef NO_IMEMORY
-        if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
-        return reinterpret_cast<SharedControl *>(mMemory->pointer())->addRemoteRefcount(value);
+          // TODO: Using unsecurePointer() has some associated security pitfalls
+         //       (see declaration for details).
+         //       Either document why it is safe in this case or address the
+         //       issue (e.g. by copying).
+       if (mMemory.get() == nullptr || mMemory->unsecurePointer() == nullptr) return 0;
+        return reinterpret_cast<SharedControl *>(mMemory->unsecurePointer())->addRemoteRefcount(value);
 #else
         (void) value;
         return 0;
@@ -121,8 +133,12 @@
 
     static bool isDeadObject(const sp<IMemory> &memory) {
 #ifndef NO_IMEMORY
-        if (memory.get() == nullptr || memory->pointer() == nullptr) return false;
-        return reinterpret_cast<SharedControl *>(memory->pointer())->isDeadObject();
+         // TODO: Using unsecurePointer() has some associated security pitfalls
+         //       (see declaration for details).
+         //       Either document why it is safe in this case or address the
+         //       issue (e.g. by copying).
+        if (memory.get() == nullptr || memory->unsecurePointer() == nullptr) return false;
+        return reinterpret_cast<SharedControl *>(memory->unsecurePointer())->isDeadObject();
 #else
         (void) memory;
         return false;
@@ -220,7 +236,11 @@
 
     inline SharedControl *getSharedControl() const {
 #ifndef NO_IMEMORY
-         return reinterpret_cast<SharedControl *>(mMemory->pointer());
+         // TODO: Using unsecurePointer() has some associated security pitfalls
+         //       (see declaration for details).
+         //       Either document why it is safe in this case or address the
+         //       issue (e.g. by copying).
+         return reinterpret_cast<SharedControl *>(mMemory->unsecurePointer());
 #else
          return nullptr;
 #endif
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index cd30347..78d00b1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -24,8 +24,7 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/MediaCodecInfo.h>
-#include <media/MediaResource.h>
-#include <media/MediaAnalyticsItem.h>
+#include <media/MediaMetrics.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/FrameRenderTracker.h>
 #include <utils/Vector.h>
@@ -43,8 +42,6 @@
 struct ICrypto;
 class MediaCodecBuffer;
 class IMemory;
-class IResourceManagerClient;
-class IResourceManagerService;
 struct PersistentSurface;
 class SoftwareRenderer;
 class Surface;
@@ -54,7 +51,13 @@
 namespace V1_0 {
 struct IDescrambler;
 }}}}
+namespace media {
+class IResourceManagerClient;
+class MediaResourceParcel;
+}
 using hardware::cas::native::V1_0::IDescrambler;
+using media::IResourceManagerClient;
+using media::MediaResourceParcel;
 
 struct MediaCodec : public AHandler {
     enum ConfigureFlags {
@@ -189,7 +192,7 @@
 
     status_t getCodecInfo(sp<MediaCodecInfo> *codecInfo) const;
 
-    status_t getMetrics(MediaAnalyticsItem * &reply);
+    status_t getMetrics(mediametrics_handle_t &reply);
 
     status_t setParameters(const sp<AMessage> &params);
 
@@ -284,34 +287,7 @@
         bool mOwnedByClient;
     };
 
-    struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {
-        ResourceManagerServiceProxy(pid_t pid, uid_t uid);
-        ~ResourceManagerServiceProxy();
-
-        void init();
-
-        // implements DeathRecipient
-        virtual void binderDied(const wp<IBinder>& /*who*/);
-
-        void addResource(
-                int64_t clientId,
-                const sp<IResourceManagerClient> &client,
-                const Vector<MediaResource> &resources);
-
-        void removeResource(
-                int64_t clientId,
-                const Vector<MediaResource> &resources);
-
-        void removeClient(int64_t clientId);
-
-        bool reclaimResource(const Vector<MediaResource> &resources);
-
-    private:
-        Mutex mLock;
-        sp<IResourceManagerService> mService;
-        pid_t mPid;
-        uid_t mUid;
-    };
+    struct ResourceManagerServiceProxy;
 
     State mState;
     uid_t mUid;
@@ -328,11 +304,11 @@
     sp<Surface> mSurface;
     SoftwareRenderer *mSoftRenderer;
 
-    MediaAnalyticsItem *mAnalyticsItem;
-    void initAnalyticsItem();
-    void updateAnalyticsItem();
-    void flushAnalyticsItem();
-    void updateEphemeralAnalytics(MediaAnalyticsItem *item);
+    mediametrics_handle_t mMetricsHandle;
+    void initMediametrics();
+    void updateMediametrics();
+    void flushMediametrics();
+    void updateEphemeralMediametrics(mediametrics_handle_t item);
 
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
@@ -434,8 +410,8 @@
     bool isExecuting() const;
 
     uint64_t getGraphicBufferSize();
-    void addResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
-    void removeResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
+    void addResource(const MediaResourceParcel &resource);
+    void removeResource(const MediaResourceParcel &resource);
     void requestCpuBoostIfNeeded();
 
     bool hasPendingBuffer(int portIndex);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 50d7724..16e207d 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -510,22 +510,24 @@
 constexpr int32_t DolbyVisionProfileDvheStn = 0x20;
 constexpr int32_t DolbyVisionProfileDvheDth = 0x40;
 constexpr int32_t DolbyVisionProfileDvheDtb = 0x80;
-constexpr int32_t DolbyVisionProfileDvheSt = 0x100;
-constexpr int32_t DolbyVisionProfileDvavSe = 0x200;
+constexpr int32_t DolbyVisionProfileDvheSt  = 0x100;
+constexpr int32_t DolbyVisionProfileDvavSe  = 0x200;
+constexpr int32_t DolbyVisionProfileDvav110 = 0x400;
 
 inline static const char *asString_DolbyVisionProfile(int32_t i, const char *def = "??") {
     switch (i) {
-        case DolbyVisionProfileDvavPer: return "DvavPer";
-        case DolbyVisionProfileDvavPen: return "DvavPen";
-        case DolbyVisionProfileDvheDer: return "DvheDer";
-        case DolbyVisionProfileDvheDen: return "DvheDen";
-        case DolbyVisionProfileDvheDtr: return "DvheDtr";
-        case DolbyVisionProfileDvheStn: return "DvheStn";
-        case DolbyVisionProfileDvheDth: return "DvheDth";
-        case DolbyVisionProfileDvheDtb: return "DvheDtb";
-        case DolbyVisionProfileDvheSt:  return "DvheSt";
-        case DolbyVisionProfileDvavSe:  return "DvavSe";
-        default:                        return def;
+        case DolbyVisionProfileDvavPer:  return "DvavPer";
+        case DolbyVisionProfileDvavPen:  return "DvavPen";
+        case DolbyVisionProfileDvheDer:  return "DvheDer";
+        case DolbyVisionProfileDvheDen:  return "DvheDen";
+        case DolbyVisionProfileDvheDtr:  return "DvheDtr";
+        case DolbyVisionProfileDvheStn:  return "DvheStn";
+        case DolbyVisionProfileDvheDth:  return "DvheDth";
+        case DolbyVisionProfileDvheDtb:  return "DvheDtb";
+        case DolbyVisionProfileDvheSt:   return "DvheSt";
+        case DolbyVisionProfileDvavSe:   return "DvavSe";
+        case DolbyVisionProfileDvav110:  return "Dav110";
+        default:                         return def;
     }
 }
 
@@ -774,6 +776,7 @@
 constexpr char KEY_LANGUAGE[] = "language";
 constexpr char KEY_LATENCY[] = "latency";
 constexpr char KEY_LEVEL[] = "level";
+constexpr char KEY_LOW_LATENCY[] = "low-latency";
 constexpr char KEY_MAX_B_FRAMES[] = "max-bframes";
 constexpr char KEY_MAX_BIT_RATE[] = "max-bitrate";
 constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
diff --git a/media/libstagefright/include/media/stagefright/MetaData.h b/media/libstagefright/include/media/stagefright/MetaData.h
index f625358..68adf346 100644
--- a/media/libstagefright/include/media/stagefright/MetaData.h
+++ b/media/libstagefright/include/media/stagefright/MetaData.h
@@ -41,7 +41,9 @@
     friend class BnMediaSource;
     friend class BpMediaSource;
     friend class BpMediaExtractor;
+#ifndef __ANDROID_VNDK__
     static sp<MetaData> createFromParcel(const Parcel &parcel);
+#endif
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 8dc2dd5..e17093a 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -59,6 +59,7 @@
     kKeyAACProfile        = 'aacp',  // int32_t
     kKeyAVCC              = 'avcc',  // raw data
     kKeyHVCC              = 'hvcc',  // raw data
+    kKeyDVCC              = 'dvcc',  // raw data
     kKeyAV1C              = 'av1c',  // raw data
     kKeyThumbnailHVCC     = 'thvc',  // raw data
     kKeyD263              = 'd263',  // raw data
@@ -245,6 +246,7 @@
     kTypeAVCC        = 'avcc',
     kTypeHVCC        = 'hvcc',
     kTypeAV1C        = 'av1c',
+    kTypeDVCC        = 'dvcc',
     kTypeD263        = 'd263',
 };
 
@@ -319,8 +321,10 @@
     struct Rect;
     struct MetaDataInternal;
     MetaDataInternal *mInternalData;
+#ifndef __ANDROID_VNDK__
     status_t writeToParcel(Parcel &parcel);
     status_t updateFromParcel(const Parcel &parcel);
+#endif
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/media/stagefright/PersistentSurface.h b/media/libstagefright/include/media/stagefright/PersistentSurface.h
index 49b36c9..f4943c3 100644
--- a/media/libstagefright/include/media/stagefright/PersistentSurface.h
+++ b/media/libstagefright/include/media/stagefright/PersistentSurface.h
@@ -18,31 +18,21 @@
 
 #define PERSISTENT_SURFACE_H_
 
-#include <android/IGraphicBufferSource.h>
 #include <binder/Parcel.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HybridInterface.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <media/stagefright/foundation/ABase.h>
 
-using android::hidl::base::V1_0::IBase;
-
 namespace android {
 
 struct PersistentSurface : public RefBase {
     PersistentSurface() {}
 
-    // create an OMX persistent surface
+    // create a persistent surface
     PersistentSurface(
             const sp<IGraphicBufferProducer>& bufferProducer,
-            const sp<IGraphicBufferSource>& bufferSource) :
-        mBufferProducer(bufferProducer),
-        mBufferSource(bufferSource) { }
-
-    // create a HIDL persistent surface
-    PersistentSurface(
-            const sp<IGraphicBufferProducer>& bufferProducer,
-            const sp<IBase>& hidlTarget) :
+            const sp<hidl::base::V1_0::IBase>& hidlTarget) :
         mBufferProducer(bufferProducer),
         mHidlTarget(hidlTarget) { }
 
@@ -50,18 +40,12 @@
         return mBufferProducer;
     }
 
-    sp<IGraphicBufferSource> getBufferSource() const {
-        return mBufferSource;
-    }
-
-    sp<IBase> getHidlTarget() const {
+    sp<hidl::base::V1_0::IBase> getHidlTarget() const {
         return mHidlTarget;
     }
 
     status_t writeToParcel(Parcel *parcel) const {
         parcel->writeStrongBinder(IInterface::asBinder(mBufferProducer));
-        // this can handle null
-        parcel->writeStrongBinder(IInterface::asBinder(mBufferSource));
         // write hidl target
         if (mHidlTarget != nullptr) {
             HalToken token;
@@ -79,8 +63,6 @@
     status_t readFromParcel(const Parcel *parcel) {
         mBufferProducer = interface_cast<IGraphicBufferProducer>(
                 parcel->readStrongBinder());
-        mBufferSource = interface_cast<IGraphicBufferSource>(
-                parcel->readStrongBinder());
         // read hidl target
         bool haveHidlTarget = parcel->readBool();
         if (haveHidlTarget) {
@@ -97,8 +79,7 @@
 
 private:
     sp<IGraphicBufferProducer> mBufferProducer;
-    sp<IGraphicBufferSource> mBufferSource;
-    sp<IBase> mHidlTarget;
+    sp<hidl::base::V1_0::IBase> mHidlTarget;
 
     DISALLOW_EVIL_CONSTRUCTORS(PersistentSurface);
 };
diff --git a/media/libstagefright/include/media/stagefright/RemoteDataSource.h b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
index 5a69bd7..83273cb 100644
--- a/media/libstagefright/include/media/stagefright/RemoteDataSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteDataSource.h
@@ -48,7 +48,7 @@
         if (size > kBufferSize) {
             size = kBufferSize;
         }
-        return mSource->readAt(offset, mMemory->pointer(), size);
+        return mSource->readAt(offset, mMemory->unsecurePointer(), size);
     }
     virtual status_t getSize(off64_t *size) {
         return mSource->getSize(size);
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 5af7b23..657144c 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -36,6 +36,10 @@
 #include <inttypes.h>
 #include <netinet/in.h>
 
+#ifndef __ANDROID_APEX__
+#include "HlsSampleDecryptor.h"
+#endif
+
 namespace android {
 
 ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
@@ -50,7 +54,13 @@
 
     // Create the decryptor anyway since we don't know the use-case unless key is provided
     // Won't decrypt if key info not available (e.g., scanner/extractor just parsing ts files)
-    mSampleDecryptor = isSampleEncrypted() ? new HlsSampleDecryptor : NULL;
+    mSampleDecryptor = isSampleEncrypted() ?
+#ifdef __ANDROID_APEX__
+        new SampleDecryptor
+#else
+        new HlsSampleDecryptor
+#endif
+        : NULL;
 }
 
 sp<MetaData> ElementaryStreamQueue::getFormat() {
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 3227f47..a06bd6a 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -25,7 +25,7 @@
 #include <utils/RefBase.h>
 #include <vector>
 
-#include "HlsSampleDecryptor.h"
+#include "SampleDecryptor.h"
 
 namespace android {
 
@@ -109,7 +109,7 @@
 
     sp<MetaData> mFormat;
 
-    sp<HlsSampleDecryptor> mSampleDecryptor;
+    sp<SampleDecryptor> mSampleDecryptor;
     int mAUIndex;
 
     bool isSampleEncrypted() const {
diff --git a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h b/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
index 2c76620..63b4d7b 100644
--- a/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
+++ b/media/libstagefright/mpeg2ts/HlsSampleDecryptor.h
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef SAMPLE_AES_PROCESSOR_H_
+#ifndef HLS_SAMPLE_AES_PROCESSOR_H_
 
-#define SAMPLE_AES_PROCESSOR_H_
+#define HLS_SAMPLE_AES_PROCESSOR_H_
 
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
@@ -28,18 +28,20 @@
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
+#include "SampleDecryptor.h"
+
 namespace android {
 
-struct HlsSampleDecryptor : RefBase {
+struct HlsSampleDecryptor : SampleDecryptor {
 
     HlsSampleDecryptor();
     explicit HlsSampleDecryptor(const sp<AMessage> &sampleAesKeyItem);
 
-    void signalNewSampleAesKey(const sp<AMessage> &sampleAesKeyItem);
+    virtual void signalNewSampleAesKey(const sp<AMessage> &sampleAesKeyItem);
 
-    size_t processNal(uint8_t *nalData, size_t nalSize);
-    void processAAC(size_t adtsHdrSize, uint8_t *data, size_t size);
-    void processAC3(uint8_t *data, size_t size);
+    virtual size_t processNal(uint8_t *nalData, size_t nalSize);
+    virtual void processAAC(size_t adtsHdrSize, uint8_t *data, size_t size);
+    virtual void processAC3(uint8_t *data, size_t size);
 
     static AString aesBlockToStr(uint8_t block[AES_BLOCK_SIZE]);
 
@@ -60,4 +62,4 @@
 
 }  // namespace android
 
-#endif // SAMPLE_AES_PROCESSOR_H_
+#endif // HLS_SAMPLE_AES_PROCESSOR_H_
diff --git a/media/libstagefright/mpeg2ts/SampleDecryptor.h b/media/libstagefright/mpeg2ts/SampleDecryptor.h
new file mode 100644
index 0000000..6bc4ac8
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/SampleDecryptor.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SAMPLE_AES_PROCESSOR_H_
+
+#define SAMPLE_AES_PROCESSOR_H_
+
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+// Base class of HlsSampleDecryptor which has dummy default implementation.
+struct SampleDecryptor : RefBase {
+
+    SampleDecryptor() { };
+
+    virtual void signalNewSampleAesKey(const sp<AMessage> &) { };
+
+    virtual size_t processNal(uint8_t *, size_t) { return -1; };
+    virtual void processAAC(size_t, uint8_t *, size_t) { };
+    virtual void processAC3(uint8_t *, size_t) { };
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(SampleDecryptor);
+};
+
+}  // namespace android
+
+#endif // SAMPLE_AES_PROCESSOR_H_
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
index ed272bb..7d217eb 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferSource.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "TWGraphicBufferSource"
 
@@ -21,6 +25,7 @@
 #include <media/stagefright/omx/1.0/WOmxNode.h>
 #include <media/stagefright/omx/1.0/Conversion.h>
 #include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/omx/OmxGraphicBufferSource.h>
 #include <android/hardware/media/omx/1.0/IOmxBufferSource.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <media/openmax/OMX_Component.h>
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index ddb4ba0..e1c3916 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -128,7 +128,7 @@
     }
 
     OMX_U8 *getPointer() {
-        return mMem.get() ? static_cast<OMX_U8*>(mMem->pointer()) :
+        return mMem.get() ? static_cast<OMX_U8*>(mMem->unsecurePointer()) :
                 mHidlMemory.get() ? static_cast<OMX_U8*>(
                 static_cast<void*>(mHidlMemory->getPointer())) : nullptr;
     }
@@ -1173,7 +1173,11 @@
         return BAD_VALUE;
     }
     if (params != NULL) {
-        paramsPointer = params->pointer();
+        // TODO: Using unsecurePointer() has some associated security pitfalls
+        //       (see declaration for details).
+        //       Either document why it is safe in this case or address the
+        //       issue (e.g. by copying).
+        paramsPointer = params->unsecurePointer();
         paramsSize = params->size();
     } else if (hParams != NULL) {
         paramsPointer = hParams->getPointer();
diff --git a/media/libstagefright/omx/OmxGraphicBufferSource.cpp b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
index 8de1f4f..7b187f9 100644
--- a/media/libstagefright/omx/OmxGraphicBufferSource.cpp
+++ b/media/libstagefright/omx/OmxGraphicBufferSource.cpp
@@ -14,12 +14,18 @@
  * limitations under the License.
  */
 
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
 #include <inttypes.h>
 
 #define LOG_TAG "OmxGraphicBufferSource"
 //#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
+#include <media/openmax/OMX_Core.h>
+
 #include <media/stagefright/bqhelper/ComponentWrapper.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
 #include <media/stagefright/omx/OmxGraphicBufferSource.h>
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
index 9669677..264c01d 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
@@ -48,7 +48,6 @@
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
 
-#include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
 
 namespace android {
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
index 4e56c98..02d4b7b 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/WGraphicBufferSource.h
@@ -26,18 +26,16 @@
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 
-#include <android/BnGraphicBufferSource.h>
-
-#include <media/stagefright/omx/OmxGraphicBufferSource.h>
-
 namespace android {
+
+class OmxGraphicBufferSource;
+
 namespace hardware {
 namespace media {
 namespace omx {
 namespace V1_0 {
 namespace implementation {
 
-using ::android::OmxGraphicBufferSource;
 using ::android::hardware::graphics::common::V1_0::Dataspace;
 using ::android::hardware::media::omx::V1_0::ColorAspects;
 using ::android::hardware::media::omx::V1_0::IGraphicBufferSource;
@@ -52,8 +50,6 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-using ::android::IOMXNode;
-
 /**
  * Wrapper classes for conversion
  * ==============================
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
index 518e0cb..e576d75 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/OmxGraphicBufferSource.h
@@ -21,7 +21,6 @@
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
 #include <media/stagefright/foundation/ABase.h>
 
-#include <android/BnGraphicBufferSource.h>
 #include <android/BnOMXBufferSource.h>
 
 #include "IOmxNodeWrapper.h"
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 8df2676..56b604d 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -46,6 +46,8 @@
             const char *url, AString *host, unsigned *port, AString *path,
             AString *user, AString *pass);
 
+    int getSocket() { return mSocket; }
+
 protected:
     virtual ~ARTSPConnection();
     virtual void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 9263565..2b42040 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -141,6 +141,12 @@
                 AString key, value;
 
                 ssize_t equalPos = line.find("=");
+                /* The condition 'if (line.size() < 2 || line.c_str()[1] != '=')' a few lines above
+                 * ensures '=' is at position 1.  However for robustness we do the following check.
+                 */
+                if (equalPos < 0) {
+                    return false;
+                }
 
                 key = AString(line, 0, equalPos + 1);
                 value = AString(line, equalPos + 1, line.size() - equalPos - 1);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 9c30623..7f025a5 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -258,6 +258,10 @@
         msg->post();
     }
 
+    sp<ARTSPConnection> getARTSPConnection() {
+      return mConn;
+    }
+
     static void addRR(const sp<ABuffer> &buf) {
         uint8_t *ptr = buf->data() + buf->size();
         ptr[0] = 0x80 | 0;
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 7b22b05..1f65372 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -40,7 +40,7 @@
     ALOGI("ServiceManager: %p", sm.get());
     AIcu_initializeIcuOrDie();
     MediaPlayerService::instantiate();
-    ResourceManagerService::instantiate();
+    media::ResourceManagerService::instantiate();
     registerExtensions();
     ProcessState::self()->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
diff --git a/media/mediaserver/manifest_media_c2_software.xml b/media/mediaserver/manifest_media_c2_software.xml
index 5196336..f23ed44 100644
--- a/media/mediaserver/manifest_media_c2_software.xml
+++ b/media/mediaserver/manifest_media_c2_software.xml
@@ -2,7 +2,7 @@
     <hal>
         <name>android.hardware.media.c2</name>
         <transport>hwbinder</transport>
-        <version>1.0</version>
+        <version>1.1</version>
         <interface>
             <name>IComponentStore</name>
             <instance>software</instance>
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
index f6c325c..ecb75a9 100644
--- a/media/mediaserver/mediaserver.rc
+++ b/media/mediaserver/mediaserver.rc
@@ -1,3 +1,6 @@
+on property:init.svc.media=*
+    setprop init.svc.mediadrm ${init.svc.media}
+
 service media /system/bin/mediaserver
     class main
     user media
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index a291939..af69a10 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -45,6 +45,7 @@
 #include "android-base/strings.h"
 
 namespace android {
+static const int SN_EVENT_LOG_ID = 0x534e4554;
 
 static const MtpOperationCode kSupportedOperationCodes[] = {
     MTP_OPERATION_GET_DEVICE_INFO,
@@ -967,9 +968,20 @@
     if (!parseDateTime(modified, modifiedTime))
         modifiedTime = 0;
 
+    if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0) ||
+        (strcmp(name, "/") == 0) || (strcmp(basename(name), name) != 0)) {
+        char errMsg[80];
+
+        snprintf(errMsg, sizeof(errMsg), "Invalid name: %s", (const char *) name);
+        ALOGE("%s (b/130656917)", errMsg);
+        android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "130656917", -1, errMsg,
+                                      strlen(errMsg));
+
+        return MTP_RESPONSE_INVALID_PARAMETER;
+    }
     if (path[path.size() - 1] != '/')
         path.append("/");
-    path.append(name);
+    path.append(basename(name));
 
     // check space first
     if (mSendObjectFileSize > storage->getFreeSpace())
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 1f8799f..8cc9a9a 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -34,8 +34,11 @@
 
 class IMtpDatabase;
 class MtpStorage;
+class MtpMockServer;
 
 class MtpServer {
+    // libFuzzer testing
+    friend class MtpMockServer;
 
 private:
     IMtpDatabase*       mDatabase;
diff --git a/media/mtp/MtpStringBuffer.cpp b/media/mtp/MtpStringBuffer.cpp
index cd379bf..d8d425b 100644
--- a/media/mtp/MtpStringBuffer.cpp
+++ b/media/mtp/MtpStringBuffer.cpp
@@ -26,14 +26,31 @@
 
 namespace {
 
-std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> gConvert;
+const char * utf16_cerror = "__CONVERSION_ERROR__";
+const char16_t * utf8_cerror = u"__CONVERSION_ERROR__";
+
+std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> gConvert(utf16_cerror, utf8_cerror);
 
 static std::string utf16ToUtf8(std::u16string input_str) {
-    return gConvert.to_bytes(input_str);
+    std::string conversion = gConvert.to_bytes(input_str);
+
+    if (conversion == utf16_cerror) {
+        ALOGE("Unable to convert UTF-16 string to UTF-8");
+        return "";
+    } else {
+        return conversion;
+    }
 }
 
 static std::u16string utf8ToUtf16(std::string input_str) {
-    return gConvert.from_bytes(input_str);
+    std::u16string conversion = gConvert.from_bytes(input_str);
+
+    if (conversion == utf8_cerror) {
+        ALOGE("Unable to convert UTF-8 string to UTF-16");
+        return u"";
+    } else {
+        return conversion;
+    }
 }
 
 } // namespace
diff --git a/media/mtp/MtpUtils.cpp b/media/mtp/MtpUtils.cpp
index 8564576..84a20d3 100644
--- a/media/mtp/MtpUtils.cpp
+++ b/media/mtp/MtpUtils.cpp
@@ -150,6 +150,7 @@
             ret += copyFile(oldFile.c_str(), newFile.c_str());
         }
     }
+    closedir(dir);
     return ret;
 }
 
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index aac6d71..0eb46f4 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -42,6 +42,7 @@
     name: "libmediandk",
 
     srcs: [
+        "NdkJavaVMHelper.cpp",
         "NdkMediaCodec.cpp",
         "NdkMediaCrypto.cpp",
         "NdkMediaDataSource.cpp",
@@ -90,11 +91,11 @@
         "libutils",
         "libcutils",
         "libnativewindow",
-        "libbinder",
         "libhidlbase",
         "libgui",
         "libui",
         "libmediandk_utils",
+        "libnativehelper",
     ],
 
     export_include_dirs: ["include"],
diff --git a/media/ndk/NdkJavaVMHelper.cpp b/media/ndk/NdkJavaVMHelper.cpp
new file mode 100644
index 0000000..baf2744
--- /dev/null
+++ b/media/ndk/NdkJavaVMHelper.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NdkJavaVMHelper"
+
+#include <media/NdkJavaVMHelper.h>
+#include <utils/Log.h>
+
+namespace android {
+
+// static
+JNIEnv *NdkJavaVMHelper::getJNIEnv() {
+    JNIEnv *env;
+    jsize nVMs;
+    JavaVM *vm;
+
+    int status = JNI_GetCreatedJavaVMs(&vm, 1, &nVMs);
+    if (status != JNI_OK || nVMs == 0 || vm == NULL) {
+        ALOGE("Failed to get JVM instance");
+        return NULL;
+    } else if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("Failed to get JNIEnv for JavaVM: %p", vm);
+        return NULL;
+    }
+
+    return env;
+}
+
+}  // namespace android
\ No newline at end of file
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index 792fc00..741e58b 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -26,9 +26,8 @@
 #include <cutils/properties.h>
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
-#include <binder/IServiceManager.h>
+#include <mediadrm/DrmUtils.h>
 #include <mediadrm/ICrypto.h>
-#include <mediadrm/IMediaDrmService.h>
 #include <android_util_Binder.h>
 
 #include <jni.h>
@@ -36,19 +35,7 @@
 using namespace android;
 
 static sp<ICrypto> makeCrypto() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.drm"));
-
-    sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
-    if (service == NULL) {
-        return NULL;
-    }
-
-    sp<ICrypto> crypto = service->makeCrypto();
-    if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
-        return NULL;
-    }
-    return crypto;
+    return DrmUtils::MakeCrypto();
 }
 
 struct AMediaCrypto {
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index c1d4686..98ccd6c 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -30,6 +30,7 @@
 #include <datasource/HTTPBase.h>
 #include <datasource/NuCachedSource2.h>
 #include <media/IMediaHTTPService.h>
+#include <media/NdkJavaVMHelper.h>
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaDataSource.h>
 #include <media/stagefright/InterfaceUtils.h>
@@ -167,7 +168,8 @@
     JNIEnv *env;
     const char *clazz, *method, *signature;
 
-    env = AndroidRuntime::getJNIEnv();
+    env = NdkJavaVMHelper::getJNIEnv();
+
     clazz = "android/media/MediaHTTPService";
     method = "createHttpServiceBinderIfNecessary";
     signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 842216c..8a95982 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -29,19 +29,19 @@
 
 #include <android-base/properties.h>
 #include <binder/PermissionController.h>
+#include <mediadrm/DrmUtils.h>
 #include <mediadrm/IDrm.h>
 #include <mediadrm/IDrmClient.h>
 #include <media/stagefright/MediaErrors.h>
 #include <binder/IServiceManager.h>
 #include <media/NdkMediaCrypto.h>
-#include <mediadrm/IMediaDrmService.h>
 
 
 using namespace android;
 
 typedef Vector<uint8_t> idvec_t;
 
-struct DrmListener: virtual public BnDrmClient
+struct DrmListener: virtual public IDrmClient
 {
 private:
     AMediaDrm *mObj;
@@ -71,12 +71,27 @@
         mKeysChangeListener = listener;
     }
 
-    void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
+    void sendEvent(
+            DrmPlugin::EventType eventType,
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const hardware::hidl_vec<uint8_t> &data) override;
+
+    void sendExpirationUpdate(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            int64_t expiryTimeInMS) override;
+
+    void sendKeysChange(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const std::vector<DrmKeyStatus> &keyStatusList,
+            bool hasNewUsableKey) override;
+
+    void sendSessionLostState(
+            const hardware::hidl_vec<uint8_t> &) override {}
+
 };
 
 struct AMediaDrm {
     sp<IDrm> mDrm;
-    sp<IDrmClient> mDrmClient;
     List<idvec_t> mIds;
     KeyedVector<String8, String8> mQueryResults;
     Vector<uint8_t> mKeyRequest;
@@ -88,71 +103,52 @@
     sp<DrmListener> mListener;
 };
 
-void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
-    if (!mEventListener || !mExpirationUpdateListener || !mKeysChangeListener) {
-        ALOGE("No listeners are specified");
+void DrmListener::sendExpirationUpdate(
+        const hardware::hidl_vec<uint8_t> &sessionId,
+        int64_t expiryTimeInMS) {
+    if (!mExpirationUpdateListener) {
+        ALOGE("No ExpirationUpdateListener specified");
         return;
     }
 
-    obj->setDataPosition(0);
+    if (expiryTimeInMS >= 0) {
+        AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+        (*mExpirationUpdateListener)(mObj, &asid, expiryTimeInMS);
+    } else {
+        ALOGE("expiry time negative, status=%" PRId64 "", expiryTimeInMS);
+    }
+}
 
-    AMediaDrmSessionId sessionId = {NULL, 0};
-    int32_t sessionIdSize = obj->readInt32();
-    if (sessionIdSize <= 0) {
-        ALOGE("Invalid session id size");
+void DrmListener::sendKeysChange(
+        const hardware::hidl_vec<uint8_t> &sessionId,
+        const std::vector<DrmKeyStatus> &keyStatusList,
+        bool hasNewUsableKey) {
+    if (!mKeysChangeListener) {
+        ALOGE("No KeysChangeListener specified");
         return;
     }
 
-    std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]);
-    sessionId.ptr = sessionIdData.get();
-    sessionId.length = sessionIdSize;
-    status_t err = obj->read(sessionIdData.get(), sessionId.length);
-    if (err != OK) {
-        ALOGE("Failed to read session id, error=%d", err);
-        return;
-    }
-
-    if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) {
-        int64_t expiryTimeInMS = obj->readInt64();
-        if (expiryTimeInMS >= 0) {
-            (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS);
-        } else {
-            ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS);
-        }
-        return;
-    } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) {
-        int32_t numKeys = 0;
-        err = obj->readInt32(&numKeys);
-        if (err != OK) {
-            ALOGE("Failed to read number of keys status, error=%d", err);
-            return;
-        }
-
-        Vector<AMediaDrmKeyStatus> keysStatus;
-        std::vector<std::unique_ptr<uint8_t[]> > dataPointers;
+    Vector<AMediaDrmKeyStatus> keysStatus;
+    for (const auto &drmKeyStatus : keyStatusList) {
         AMediaDrmKeyStatus keyStatus;
+        keyStatus.keyId.ptr = drmKeyStatus.keyId.data();
+        keyStatus.keyId.length = drmKeyStatus.keyId.size();
+        keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(drmKeyStatus.type);
+        keysStatus.push(keyStatus);
+    }
 
-        for (size_t i = 0; i < numKeys; ++i) {
-            keyStatus.keyId.ptr = nullptr;
-            keyStatus.keyId.length = 0;
-            int32_t idSize = obj->readInt32();
-            if (idSize > 0) {
-                std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]);
-                err = obj->read(data.get(), idSize);
-                if (err != OK) {
-                    ALOGE("Failed to read key data, error=%d", err);
-                    return;
-                }
-                keyStatus.keyId.ptr = data.get();
-                keyStatus.keyId.length = idSize;
-                dataPointers.push_back(std::move(data));
-            }
-            keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32());
-            keysStatus.push(keyStatus);
-        }
+    AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+    int32_t numKeys = keyStatusList.size();
+    (*mKeysChangeListener)(mObj, &asid, keysStatus.array(), numKeys, hasNewUsableKey);
+    return;
+}
 
-        bool hasNewUsableKey = obj->readInt32();
-        (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey);
+void DrmListener::sendEvent(
+        DrmPlugin::EventType eventType,
+        const hardware::hidl_vec<uint8_t> &sessionId,
+        const hardware::hidl_vec<uint8_t> &data) {
+    if (!mEventListener) {
+        ALOGE("No EventListener specified");
         return;
     }
 
@@ -176,23 +172,17 @@
             ndkEventType = EVENT_SESSION_RECLAIMED;
             break;
         default:
-            ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
+            ALOGE("Invalid event DrmPlugin::EventType %d, ignored", eventType);
             return;
     }
 
-    int32_t dataSize = obj->readInt32();
-    uint8_t *data = NULL;
+    AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+    int32_t dataSize = data.size();
+    const uint8_t *dataPtr = data.data();
     if (dataSize > 0) {
-        data = new uint8_t[dataSize];
-        err = obj->read(data, dataSize);
-        if (err == OK) {
-            (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
-        } else {
-            ALOGE("Failed to read event data, error=%d", err);
-        }
-        delete [] data;
+        (*mEventListener)(mObj, &asid, ndkEventType, 0, dataPtr, dataSize);
     } else {
-        ALOGE("Error reading parcel: invalid event data size=%d", dataSize);
+        ALOGE("invalid event data size=%d", dataSize);
     }
 }
 
@@ -268,19 +258,7 @@
 }
 
 static sp<IDrm> CreateDrm() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder = sm->getService(String16("media.drm"));
-
-    sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
-    if (service == NULL) {
-        return NULL;
-    }
-
-    sp<IDrm> drm = service->makeDrm();
-    if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
-        return NULL;
-    }
-    return drm;
+    return DrmUtils::MakeDrm();
 }
 
 
diff --git a/media/ndk/include/media/NdkJavaVMHelper.h b/media/ndk/include/media/NdkJavaVMHelper.h
new file mode 100644
index 0000000..1c20275
--- /dev/null
+++ b/media/ndk/include/media/NdkJavaVMHelper.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NDK_JAVA_VM_HELPER_H_
+
+#define NDK_JAVA_VM_HELPER_H_
+
+#include "jni.h"
+
+namespace android {
+
+struct NdkJavaVMHelper {
+    static JNIEnv *getJNIEnv();
+};
+
+}  // namespace android
+
+#endif  // NDK_JAVA_VM_HELPER_H_
\ No newline at end of file
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.cpp b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
index e88d011..20a1468 100644
--- a/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
@@ -16,8 +16,10 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "C2Decoder"
+#include <log/log.h>
 
 #include "C2Decoder.h"
+#include <iostream>
 
 int32_t C2Decoder::createCodec2Component(string compName, AMediaFormat *format) {
     ALOGV("In %s", __func__);
@@ -87,7 +89,7 @@
                 work.swap(mWorkQueue.front());
                 mWorkQueue.pop_front();
             } else {
-                cout << "Wait for generating C2Work exceeded timeout" << endl;
+                std::cout << "Wait for generating C2Work exceeded timeout" << std::endl;
                 return -1;
             }
         }
@@ -110,13 +112,13 @@
             status = mLinearPool->fetchLinearBlock(
                     alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
             if (status != C2_OK || block == nullptr) {
-                cout << "C2LinearBlock::map() failed : " << status << endl;
+                std::cout << "C2LinearBlock::map() failed : " << status << std::endl;
                 return status;
             }
 
             C2WriteView view = block->map().get();
             if (view.error() != C2_OK) {
-                cout << "C2LinearBlock::map() failed : " << view.error() << endl;
+                std::cout << "C2LinearBlock::map() failed : " << view.error() << std::endl;
                 return view.error();
             }
             memcpy(view.base(), inputBuffer + mOffset, size);
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.h b/media/tests/benchmark/src/native/decoder/C2Decoder.h
index 0e79d51..4a3eb96 100644
--- a/media/tests/benchmark/src/native/decoder/C2Decoder.h
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.h
@@ -17,10 +17,6 @@
 #ifndef __C2_DECODER_H__
 #define __C2_DECODER_H__
 
-#include <stdio.h>
-#include <algorithm>
-#include <fstream>
-
 #include "BenchmarkC2Common.h"
 
 #define ALIGN(_sz, _align) (((_sz) + ((_align) - 1)) & ~((_align) - 1))
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 8a9039c..5047b19 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -51,6 +51,10 @@
         "libmedia_headers",
     ],
 
+    include_dirs: [
+        // For DEBUGGER_SIGNAL
+        "system/core/debuggerd/include",
+    ],
     local_include_dirs: ["include"],
     export_include_dirs: ["include"],
 }
diff --git a/media/utils/ProcessInfo.cpp b/media/utils/ProcessInfo.cpp
index 27f1a79..113e4a7 100644
--- a/media/utils/ProcessInfo.cpp
+++ b/media/utils/ProcessInfo.cpp
@@ -23,6 +23,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IProcessInfoService.h>
 #include <binder/IServiceManager.h>
+#include <private/android_filesystem_config.h>
 
 namespace android {
 
@@ -55,8 +56,9 @@
 
 bool ProcessInfo::isValidPid(int pid) {
     int callingPid = IPCThreadState::self()->getCallingPid();
+    int callingUid = IPCThreadState::self()->getCallingUid();
     // Trust it if this is called from the same process otherwise pid has to match the calling pid.
-    return (callingPid == getpid()) || (callingPid == pid);
+    return (callingPid == getpid()) || (callingPid == pid) || (callingUid == AID_MEDIA);
 }
 
 ProcessInfo::~ProcessInfo() {}
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 02141a8..b132782 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -61,12 +61,12 @@
 
 static bool checkRecordingInternal(const String16& opPackageName, pid_t pid,
         uid_t uid, bool start) {
-    // Okay to not track in app ops as audio server is us and if
+    // Okay to not track in app ops as audio server or media server is us and if
     // device is rooted security model is considered compromised.
     // system_server loses its RECORD_AUDIO permission when a secondary
     // user is active, but it is a core system service so let it through.
     // TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0
-    if (isAudioServerOrSystemServerOrRootUid(uid)) return true;
+    if (isAudioServerOrMediaServerOrSystemServerOrRootUid(uid)) return true;
 
     // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
     // may open a record track on behalf of a client.  Note that pid may be a tid.
@@ -167,9 +167,16 @@
 }
 
 bool modifyAudioRoutingAllowed() {
+    return modifyAudioRoutingAllowed(
+        IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid());
+}
+
+bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid) {
+    if (isAudioServerUid(IPCThreadState::self()->getCallingUid())) return true;
     // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
-    bool ok = PermissionCache::checkCallingPermission(sModifyAudioRouting);
-    if (!ok) ALOGE("android.permission.MODIFY_AUDIO_ROUTING");
+    bool ok = PermissionCache::checkPermission(sModifyAudioRouting, pid, uid);
+    if (!ok) ALOGE("%s(): android.permission.MODIFY_AUDIO_ROUTING denied for uid %d",
+        __func__, uid);
     return ok;
 }
 
@@ -225,9 +232,9 @@
     off_t size = lseek(heap->getHeapID(), 0, SEEK_END);
     lseek(heap->getHeapID(), 0, SEEK_SET);
 
-    if (iMemory->pointer() == NULL || size < (off_t)iMemory->size()) {
+    if (iMemory->unsecurePointer() == NULL || size < (off_t)iMemory->size()) {
         ALOGE("%s check failed: pointer %p size %zu fd size %u",
-              __FUNCTION__, iMemory->pointer(), iMemory->size(), (uint32_t)size);
+              __FUNCTION__, iMemory->unsecurePointer(), iMemory->size(), (uint32_t)size);
         return BAD_VALUE;
     }
 
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 265a232..4a3e470 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -14,13 +14,50 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "TimeCheck"
 
 #include <utils/Log.h>
 #include <mediautils/TimeCheck.h>
 #include <mediautils/EventLog.h>
+#include "debuggerd/handler.h"
 
 namespace android {
 
+// Audio HAL server pids vector used to generate audio HAL processes tombstone
+// when audioserver watchdog triggers.
+// We use a lockless storage to avoid potential deadlocks in the context of watchdog
+// trigger.
+// Protection again simultaneous writes is not needed given one update takes place
+// during AudioFlinger construction and other comes necessarily later once the IAudioFlinger
+// interface is available.
+// The use of an atomic index just guaranties that current vector is fully initialized
+// when read.
+/* static */
+void TimeCheck::accessAudioHalPids(std::vector<pid_t>* pids, bool update) {
+    static constexpr int kNumAudioHalPidsVectors = 3;
+    static std::vector<pid_t> audioHalPids[kNumAudioHalPidsVectors];
+    static std::atomic<int> curAudioHalPids = 0;
+
+    if (update) {
+        audioHalPids[(curAudioHalPids + 1) % kNumAudioHalPidsVectors] = *pids;
+        curAudioHalPids++;
+    } else {
+        *pids = audioHalPids[curAudioHalPids];
+    }
+}
+
+/* static */
+void TimeCheck::setAudioHalPids(const std::vector<pid_t>& pids) {
+    accessAudioHalPids(&(const_cast<std::vector<pid_t>&>(pids)), true);
+}
+
+/* static */
+std::vector<pid_t> TimeCheck::getAudioHalPids() {
+    std::vector<pid_t> pids;
+    accessAudioHalPids(&pids, false);
+    return pids;
+}
+
 /* static */
 sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
 {
@@ -82,10 +119,22 @@
         if (waitTimeNs > 0) {
             status = mCond.waitRelative(mMutex, waitTimeNs);
         }
-    }
-    if (status != NO_ERROR) {
-        LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
-        LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
+        if (status != NO_ERROR) {
+            // Generate audio HAL processes tombstones and allow time to complete
+            // before forcing restart
+            std::vector<pid_t> pids = getAudioHalPids();
+            if (pids.size() != 0) {
+                for (const auto& pid : pids) {
+                    ALOGI("requesting tombstone for pid: %d", pid);
+                    sigqueue(pid, DEBUGGER_SIGNAL, {.sival_int = 0});
+                }
+                sleep(1);
+            } else {
+                ALOGI("No HAL process pid available, skipping tombstones");
+            }
+            LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag);
+            LOG_ALWAYS_FATAL("TimeCheck timeout for %s", tag);
+        }
     }
     return true;
 }
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index e1089d5..9e852fd 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -58,10 +58,11 @@
     return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
 }
 
-// used for calls that should come from system_server or audio_server and
+// used for calls that should come from system_server or audio_server or media server and
 // include AID_ROOT for command-line tests.
-static inline bool isAudioServerOrSystemServerOrRootUid(uid_t uid) {
-    return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER || uid == AID_ROOT;
+static inline bool isAudioServerOrMediaServerOrSystemServerOrRootUid(uid_t uid) {
+    return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER
+              || uid == AID_MEDIA || uid == AID_ROOT;
 }
 
 // Mediaserver may forward the client PID and UID as part of a binder interface call;
@@ -84,6 +85,7 @@
 bool captureHotwordAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
 bool settingsAllowed();
 bool modifyAudioRoutingAllowed();
+bool modifyAudioRoutingAllowed(pid_t pid, uid_t uid);
 bool modifyDefaultAudioEffectsAllowed();
 bool dumpAllowed();
 bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
diff --git a/media/utils/include/mediautils/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
index 6c5f656..5ba6d7c 100644
--- a/media/utils/include/mediautils/TimeCheck.h
+++ b/media/utils/include/mediautils/TimeCheck.h
@@ -20,7 +20,7 @@
 
 #include <utils/KeyedVector.h>
 #include <utils/Thread.h>
-
+#include <vector>
 
 namespace android {
 
@@ -35,6 +35,8 @@
 
             TimeCheck(const char *tag, uint32_t timeoutMs = kDefaultTimeOutMs);
             ~TimeCheck();
+    static  void setAudioHalPids(const std::vector<pid_t>& pids);
+    static  std::vector<pid_t> getAudioHalPids();
 
 private:
 
@@ -63,6 +65,7 @@
     };
 
     static sp<TimeCheckThread> getTimeCheckThread();
+    static void accessAudioHalPids(std::vector<pid_t>* pids, bool update);
 
     const           nsecs_t mEndTimeNs;
 };
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 96ad54b..de8c7e7 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -34,6 +34,7 @@
     ],
 
     shared_libs: [
+        "libaudiofoundation",
         "libaudiohal",
         "libaudioprocessing",
         "libaudiospdif",
@@ -60,6 +61,10 @@
         "libsndfile",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     cflags: [
         "-DSTATE_QUEUE_INSTANTIATIONS=\"StateQueueInstantiations.cpp\"",
         "-fvisibility=hidden",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8591efd..9756abb 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -19,6 +19,9 @@
 #define LOG_TAG "AudioFlinger"
 //#define LOG_NDEBUG 0
 
+// Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
+#define AUDIO_ARRAYS_STATIC_CHECK 1
+
 #include "Configuration.h"
 #include <dirent.h>
 #include <math.h>
@@ -67,6 +70,7 @@
 #include <media/nbaio/PipeReader.h>
 #include <mediautils/BatteryNotifier.h>
 #include <mediautils/ServiceUtilities.h>
+#include <mediautils/TimeCheck.h>
 #include <private/android_filesystem_config.h>
 
 //#define BUFLOG_NDEBUG 0
@@ -190,6 +194,9 @@
     mEffectsFactoryHal = EffectsFactoryHalInterface::create();
 
     mMediaLogNotifier->run("MediaLogNotifier");
+    std::vector<pid_t> halPids;
+    mDevicesFactoryHal->getHalPids(&halPids);
+    TimeCheck::setAudioHalPids(halPids);
 }
 
 void AudioFlinger::onFirstRef()
@@ -215,6 +222,11 @@
     gAudioFlinger = this;
 }
 
+status_t AudioFlinger::setAudioHalPids(const std::vector<pid_t>& pids) {
+  TimeCheck::setAudioHalPids(pids);
+  return NO_ERROR;
+}
+
 AudioFlinger::~AudioFlinger()
 {
     while (!mRecordThreads.isEmpty()) {
@@ -378,7 +390,7 @@
 
 AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
         audio_module_handle_t module,
-        audio_devices_t devices)
+        audio_devices_t deviceType)
 {
     // if module is 0, the request comes from an old policy manager and we should load
     // well known modules
@@ -393,7 +405,7 @@
             sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
             uint32_t supportedDevices;
             if (dev->getSupportedDevices(&supportedDevices) == OK &&
-                    (supportedDevices & devices) == devices) {
+                    (supportedDevices & deviceType) == deviceType) {
                 return audioHwDevice;
             }
         }
@@ -652,7 +664,7 @@
         return new NBLog::Writer();
     }
 success:
-    NBLog::Shared *sharedRawPtr = (NBLog::Shared *) shared->pointer();
+    NBLog::Shared *sharedRawPtr = (NBLog::Shared *) shared->unsecurePointer();
     new((void *) sharedRawPtr) NBLog::Shared(); // placement new here, but the corresponding
                                                 // explicit destructor not needed since it is POD
     sMediaLogService->registerWriter(shared, size, name);
@@ -1159,16 +1171,16 @@
     return mute;
 }
 
-void AudioFlinger::setRecordSilenced(uid_t uid, bool silenced)
+void AudioFlinger::setRecordSilenced(audio_port_handle_t portId, bool silenced)
 {
-    ALOGV("AudioFlinger::setRecordSilenced(uid:%d, silenced:%d)", uid, silenced);
+    ALOGV("AudioFlinger::setRecordSilenced(portId:%d, silenced:%d)", portId, silenced);
 
     AutoMutex lock(mLock);
     for (size_t i = 0; i < mRecordThreads.size(); i++) {
-        mRecordThreads[i]->setRecordSilenced(uid, silenced);
+        mRecordThreads[i]->setRecordSilenced(portId, silenced);
     }
     for (size_t i = 0; i < mMmapThreads.size(); i++) {
-        mMmapThreads[i]->setRecordSilenced(uid, silenced);
+        mMmapThreads[i]->setRecordSilenced(portId, silenced);
     }
 }
 
@@ -1354,6 +1366,13 @@
     }
 }
 
+void AudioFlinger::updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices)
+{
+    for (size_t i = 0; i < mRecordThreads.size(); i++) {
+        mRecordThreads.valueAt(i)->updateOutDevices(devices);
+    }
+}
+
 // forwardAudioHwSyncToDownstreamPatches_l() must be called with AudioFlinger::mLock held
 void AudioFlinger::forwardParametersToDownstreamPatches_l(
         audio_io_handle_t upStream, const String8& keyValuePairs,
@@ -2301,13 +2320,13 @@
 
 
 sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
-                                                            audio_io_handle_t *output,
-                                                            audio_config_t *config,
-                                                            audio_devices_t devices,
-                                                            const String8& address,
-                                                            audio_output_flags_t flags)
+                                                        audio_io_handle_t *output,
+                                                        audio_config_t *config,
+                                                        audio_devices_t deviceType,
+                                                        const String8& address,
+                                                        audio_output_flags_t flags)
 {
-    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
+    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
     if (outHwDev == NULL) {
         return 0;
     }
@@ -2348,7 +2367,7 @@
     status_t status = outHwDev->openOutputStream(
             &outputStream,
             *output,
-            devices,
+            deviceType,
             flags,
             config,
             address.string());
@@ -2358,8 +2377,7 @@
     if (status == NO_ERROR) {
         if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
             sp<MmapPlaybackThread> thread =
-                    new MmapPlaybackThread(this, *output, outHwDev, outputStream,
-                                          devices, AUDIO_DEVICE_NONE, mSystemReady);
+                    new MmapPlaybackThread(this, *output, outHwDev, outputStream, mSystemReady);
             mMmapThreads.add(*output, thread);
             ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
                   *output, thread.get());
@@ -2367,17 +2385,17 @@
         } else {
             sp<PlaybackThread> thread;
             if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
-                thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
+                thread = new OffloadThread(this, outputStream, *output, mSystemReady);
                 ALOGV("openOutput_l() created offload output: ID %d thread %p",
                       *output, thread.get());
             } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                     || !isValidPcmSinkFormat(config->format)
                     || !isValidPcmSinkChannelMask(config->channel_mask)) {
-                thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
+                thread = new DirectOutputThread(this, outputStream, *output, mSystemReady);
                 ALOGV("openOutput_l() created direct output: ID %d thread %p",
                       *output, thread.get());
             } else {
-                thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
+                thread = new MixerThread(this, outputStream, *output, mSystemReady);
                 ALOGV("openOutput_l() created mixer output: ID %d thread %p",
                       *output, thread.get());
             }
@@ -2393,27 +2411,29 @@
 status_t AudioFlinger::openOutput(audio_module_handle_t module,
                                   audio_io_handle_t *output,
                                   audio_config_t *config,
-                                  audio_devices_t *devices,
-                                  const String8& address,
+                                  const sp<DeviceDescriptorBase>& device,
                                   uint32_t *latencyMs,
                                   audio_output_flags_t flags)
 {
-    ALOGI("openOutput() this %p, module %d Device %#x, SamplingRate %d, Format %#08x, "
+    ALOGI("openOutput() this %p, module %d Device %s, SamplingRate %d, Format %#08x, "
               "Channels %#x, flags %#x",
               this, module,
-              (devices != NULL) ? *devices : 0,
+              device->toString().c_str(),
               config->sample_rate,
               config->format,
               config->channel_mask,
               flags);
 
-    if (devices == NULL || *devices == AUDIO_DEVICE_NONE) {
+    audio_devices_t deviceType = device->type();
+    const String8 address = String8(device->address().c_str());
+
+    if (deviceType == AUDIO_DEVICE_NONE) {
         return BAD_VALUE;
     }
 
     Mutex::Autolock _l(mLock);
 
-    sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags);
+    sp<ThreadBase> thread = openOutput_l(module, output, config, deviceType, address, flags);
     if (thread != 0) {
         if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
             PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
@@ -2683,9 +2703,7 @@
         AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream, flags);
         if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
             sp<MmapCaptureThread> thread =
-                    new MmapCaptureThread(this, *input,
-                                          inHwDev, inputStream,
-                                          primaryOutputDevice_l(), devices, mSystemReady);
+                    new MmapCaptureThread(this, *input, inHwDev, inputStream, mSystemReady);
             mMmapThreads.add(*input, thread);
             ALOGV("openInput_l() created mmap capture thread: ID %d thread %p", *input,
                     thread.get());
@@ -2694,13 +2712,7 @@
             // Start record thread
             // RecordThread requires both input and output device indication to forward to audio
             // pre processing modules
-            sp<RecordThread> thread = new RecordThread(this,
-                                      inputStream,
-                                      *input,
-                                      primaryOutputDevice_l(),
-                                      devices,
-                                      mSystemReady
-                                      );
+            sp<RecordThread> thread = new RecordThread(this, inputStream, *input, mSystemReady);
             mRecordThreads.add(*input, thread);
             ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
             return thread;
@@ -3116,15 +3128,15 @@
     return NULL;
 }
 
-audio_devices_t AudioFlinger::primaryOutputDevice_l() const
+DeviceTypeSet AudioFlinger::primaryOutputDevice_l() const
 {
     PlaybackThread *thread = primaryPlaybackThread_l();
 
     if (thread == NULL) {
-        return 0;
+        return DeviceTypeSet();
     }
 
-    return thread->outDevice();
+    return thread->outDeviceTypes();
 }
 
 AudioFlinger::PlaybackThread *AudioFlinger::fastPlaybackThread_l() const
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d639f26..3b6bbdb 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -65,13 +65,16 @@
 #include <media/audiohal/EffectBufferHalInterface.h>
 #include <media/audiohal/StreamHalInterface.h>
 #include <media/AudioBufferProvider.h>
+#include <media/AudioContainers.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioMixer.h>
+#include <media/DeviceDescriptorBase.h>
 #include <media/ExtendedAudioBufferProvider.h>
-#include <media/LinearMap.h>
 #include <media/VolumeShaper.h>
 
 #include <audio_utils/clock.h>
 #include <audio_utils/FdToString.h>
+#include <audio_utils/LinearMap.h>
 #include <audio_utils/SimpleLog.h>
 #include <audio_utils/TimestampVerifier.h>
 
@@ -162,7 +165,7 @@
     virtual     status_t    setMicMute(bool state);
     virtual     bool        getMicMute() const;
 
-    virtual     void        setRecordSilenced(uid_t uid, bool silenced);
+    virtual     void        setRecordSilenced(audio_port_handle_t portId, bool silenced);
 
     virtual     status_t    setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs);
     virtual     String8     getParameters(audio_io_handle_t ioHandle, const String8& keys) const;
@@ -175,8 +178,7 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags);
 
@@ -279,6 +281,8 @@
 
     virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
 
+    virtual status_t setAudioHalPids(const std::vector<pid_t>& pids);
+
     virtual     status_t    onTransact(
                                 uint32_t code,
                                 const Parcel& data,
@@ -372,7 +376,7 @@
     virtual     void        onFirstRef();
 
     AudioHwDevice*          findSuitableHwDev_l(audio_module_handle_t module,
-                                                audio_devices_t devices);
+                                                audio_devices_t deviceType);
 
     // Set kEnableExtendedChannels to true to enable greater than stereo output
     // for the MixerThread and device sink.  Number of channels allowed is
@@ -678,11 +682,11 @@
                                            audio_devices_t outputDevice,
                                            const String8& outputDeviceAddress);
               sp<ThreadBase> openOutput_l(audio_module_handle_t module,
-                                              audio_io_handle_t *output,
-                                              audio_config_t *config,
-                                              audio_devices_t devices,
-                                              const String8& address,
-                                              audio_output_flags_t flags);
+                                          audio_io_handle_t *output,
+                                          audio_config_t *config,
+                                          audio_devices_t deviceType,
+                                          const String8& address,
+                                          audio_output_flags_t flags);
 
               void closeOutputFinish(const sp<PlaybackThread>& thread);
               void closeInputFinish(const sp<RecordThread>& thread);
@@ -717,7 +721,7 @@
 
               // return thread associated with primary hardware device, or NULL
               PlaybackThread *primaryPlaybackThread_l() const;
-              audio_devices_t primaryOutputDevice_l() const;
+              DeviceTypeSet primaryOutputDevice_l() const;
 
               // return the playback thread with smallest HAL buffer size, and prefer fast
               PlaybackThread *fastPlaybackThread_l() const;
@@ -751,6 +755,7 @@
                 std::vector< sp<EffectModule> > purgeStaleEffects_l();
 
                 void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
+                void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices);
                 void forwardParametersToDownstreamPatches_l(
                         audio_io_handle_t upStream, const String8& keyValuePairs,
                         std::function<bool(const sp<PlaybackThread>&)> useThread = nullptr);
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index b109d06..dda164c 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -34,7 +34,7 @@
 status_t AudioHwDevice::openOutputStream(
         AudioStreamOut **ppStreamOut,
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address)
@@ -50,7 +50,7 @@
             config->sample_rate,
             config->format,
             config->channel_mask);
-    status_t status = outputStream->open(handle, devices, config, address);
+    status_t status = outputStream->open(handle, deviceType, config, address);
 
     if (status != NO_ERROR) {
         delete outputStream;
@@ -75,7 +75,7 @@
         if (wrapperNeeded) {
             if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
                 outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
-                status = outputStream->open(handle, devices, &originalConfig, address);
+                status = outputStream->open(handle, deviceType, &originalConfig, address);
                 if (status != NO_ERROR) {
                     ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
                         status);
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index d4299b0..6709d17 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -76,7 +76,7 @@
     status_t openOutputStream(
             AudioStreamOut **ppStreamOut,
             audio_io_handle_t handle,
-            audio_devices_t devices,
+            audio_devices_t deviceType,
             audio_output_flags_t flags,
             struct audio_config *config,
             const char *address);
diff --git a/services/audioflinger/AudioStreamOut.cpp b/services/audioflinger/AudioStreamOut.cpp
index a60a5f2..d13cb8f 100644
--- a/services/audioflinger/AudioStreamOut.cpp
+++ b/services/audioflinger/AudioStreamOut.cpp
@@ -118,7 +118,7 @@
 
 status_t AudioStreamOut::open(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         struct audio_config *config,
         const char *address)
 {
@@ -130,7 +130,7 @@
 
     int status = hwDev()->openOutputStream(
             handle,
-            devices,
+            deviceType,
             customFlags,
             config,
             address,
@@ -152,7 +152,7 @@
 
         status = hwDev()->openOutputStream(
                 handle,
-                devices,
+                deviceType,
                 customFlags,
                 &customConfig,
                 address,
diff --git a/services/audioflinger/AudioStreamOut.h b/services/audioflinger/AudioStreamOut.h
index b16b1af..16fbcf2 100644
--- a/services/audioflinger/AudioStreamOut.h
+++ b/services/audioflinger/AudioStreamOut.h
@@ -47,7 +47,7 @@
 
     virtual status_t open(
             audio_io_handle_t handle,
-            audio_devices_t devices,
+            audio_devices_t deviceType,
             struct audio_config *config,
             const char *address);
 
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 13152d0..1355b1b 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -29,7 +29,9 @@
 #include <system/audio_effects/effect_visualizer.h>
 #include <audio_utils/channels.h>
 #include <audio_utils/primitives.h>
+#include <media/AudioContainers.h>
 #include <media/AudioEffect.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/audiohal/EffectHalInterface.h>
 #include <media/audiohal/EffectsFactoryHalInterface.h>
 #include <mediautils/ServiceUtilities.h>
@@ -1229,9 +1231,11 @@
     }
 }
 
-status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
+status_t AudioFlinger::EffectModule::sendSetAudioDevicesCommand(
+        const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode)
 {
-    if (device == AUDIO_DEVICE_NONE) {
+    audio_devices_t deviceType = deviceTypesToBitMask(getAudioDeviceTypes(devices));
+    if (deviceType == AUDIO_DEVICE_NONE) {
         return NO_ERROR;
     }
 
@@ -1243,17 +1247,26 @@
     if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
         status_t cmdStatus;
         uint32_t size = sizeof(status_t);
-        uint32_t cmd = audio_is_output_devices(device) ? EFFECT_CMD_SET_DEVICE :
-                            EFFECT_CMD_SET_INPUT_DEVICE;
-        status = mEffectInterface->command(cmd,
+        // FIXME: use audio device types and addresses when the hal interface is ready.
+        status = mEffectInterface->command(cmdCode,
                                            sizeof(uint32_t),
-                                           &device,
+                                           &deviceType,
                                            &size,
                                            &cmdStatus);
     }
     return status;
 }
 
+status_t AudioFlinger::EffectModule::setDevices(const AudioDeviceTypeAddrVector &devices)
+{
+    return sendSetAudioDevicesCommand(devices, EFFECT_CMD_SET_DEVICE);
+}
+
+status_t AudioFlinger::EffectModule::setInputDevice(const AudioDeviceTypeAddr &device)
+{
+    return sendSetAudioDevicesCommand({device}, EFFECT_CMD_SET_INPUT_DEVICE);
+}
+
 status_t AudioFlinger::EffectModule::setMode(audio_mode_t mode)
 {
     Mutex::Autolock _l(mLock);
@@ -1588,7 +1601,7 @@
     int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
     mCblkMemory = client->heap()->allocate(EFFECT_PARAM_BUFFER_SIZE + bufOffset);
     if (mCblkMemory == 0 ||
-            (mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->pointer())) == NULL) {
+            (mCblk = static_cast<effect_param_cblk_t *>(mCblkMemory->unsecurePointer())) == NULL) {
         ALOGE("not enough memory for Effect size=%zu", EFFECT_PARAM_BUFFER_SIZE +
                 sizeof(effect_param_cblk_t));
         mCblkMemory.clear();
@@ -2288,12 +2301,21 @@
     return mEffects.size();
 }
 
-// setDevice_l() must be called with ThreadBase::mLock held
-void AudioFlinger::EffectChain::setDevice_l(audio_devices_t device)
+// setDevices_l() must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setDevices_l(const AudioDeviceTypeAddrVector &devices)
 {
     size_t size = mEffects.size();
     for (size_t i = 0; i < size; i++) {
-        mEffects[i]->setDevice(device);
+        mEffects[i]->setDevices(devices);
+    }
+}
+
+// setInputDevice_l() must be called with ThreadBase::mLock held
+void AudioFlinger::EffectChain::setInputDevice_l(const AudioDeviceTypeAddr &device)
+{
+    size_t size = mEffects.size();
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->setInputDevice(device);
     }
 }
 
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 220874d..dbf63c8 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -109,7 +109,8 @@
     const effect_descriptor_t& desc() const { return mDescriptor; }
     wp<EffectChain>&     chain() { return mChain; }
 
-    status_t         setDevice(audio_devices_t device);
+    status_t         setDevices(const AudioDeviceTypeAddrVector &devices);
+    status_t         setInputDevice(const AudioDeviceTypeAddr &device);
     status_t         setVolume(uint32_t *left, uint32_t *right, bool controller);
     status_t         setMode(audio_mode_t mode);
     status_t         setAudioSource(audio_source_t source);
@@ -158,6 +159,7 @@
     status_t start_l();
     status_t stop_l();
     status_t remove_effect_from_hal_l();
+    status_t sendSetAudioDevicesCommand(const AudioDeviceTypeAddrVector &devices, uint32_t cmdCode);
 
 mutable Mutex               mLock;      // mutex for process, commands and handles list protection
     wp<ThreadBase>      mThread;    // parent thread
@@ -350,7 +352,8 @@
     // FIXME use float to improve the dynamic range
     bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
     void resetVolume_l();
-    void setDevice_l(audio_devices_t device);
+    void setDevices_l(const AudioDeviceTypeAddrVector &devices);
+    void setInputDevice_l(const AudioDeviceTypeAddr &device);
     void setMode_l(audio_mode_t mode);
     void setAudioSource_l(audio_source_t source);
 
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 18cb53b..53e2dd5 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -25,6 +25,7 @@
 
 #include "AudioFlinger.h"
 #include <media/AudioParameter.h>
+#include <media/DeviceDescriptorBase.h>
 #include <media/PatchBuilder.h>
 #include <mediautils/ServiceUtilities.h>
 
@@ -167,6 +168,7 @@
                 if (hwDevice != 0) {
                     hwDevice->releaseAudioPatch(removedPatch.mHalHandle);
                 }
+                halHandle = removedPatch.mHalHandle;
             }
             mPatches.erase(iter);
             removeSoftwarePatchFromInsertedModules(*handle);
@@ -351,7 +353,7 @@
                 goto exit;
             }
             // limit to connections between devices and output streams
-            audio_devices_t type = AUDIO_DEVICE_NONE;
+            DeviceDescriptorBaseVector devices;
             for (unsigned int i = 0; i < patch->num_sinks; i++) {
                 if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
                     ALOGW("%s() invalid sink type %d for mix source",
@@ -364,7 +366,11 @@
                     status = BAD_VALUE;
                     goto exit;
                 }
-                type |= patch->sinks[i].ext.device.type;
+                sp<DeviceDescriptorBase> device = new DeviceDescriptorBase(
+                        patch->sinks[i].ext.device.type);
+                device->setAddress(patch->sinks[i].ext.device.address);
+                device->applyAudioPortConfig(&patch->sinks[i]);
+                devices.push_back(device);
             }
             sp<ThreadBase> thread =
                             mAudioFlinger.checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
@@ -378,10 +384,7 @@
                 }
             }
             if (thread == mAudioFlinger.primaryPlaybackThread_l()) {
-                AudioParameter param = AudioParameter();
-                param.addInt(String8(AudioParameter::keyRouting), (int)type);
-
-                mAudioFlinger.broacastParametersToRecordThreads_l(param.toString());
+                mAudioFlinger.updateOutDevicesForRecordThreads_l(devices);
             }
 
             status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index d5257bd..d87239d 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -25,7 +25,8 @@
     ~OpRecordAudioMonitor() override;
     bool hasOpRecordAudio() const;
 
-    static sp<OpRecordAudioMonitor> createIfNeeded(uid_t uid, const String16& opPackageName);
+    static sp<OpRecordAudioMonitor> createIfNeeded
+        (uid_t uid, const audio_attributes_t& attr, const String16& opPackageName);
 
 private:
     OpRecordAudioMonitor(uid_t uid, const String16& opPackageName);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ac892a5..4be21b1 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -29,6 +29,8 @@
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <cutils/properties.h>
+#include <media/AudioContainers.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioParameter.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/RecordBufferConverter.h>
@@ -460,7 +462,7 @@
 }
 
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        audio_devices_t outDevice, audio_devices_t inDevice, type_t type, bool systemReady)
+        type_t type, bool systemReady)
     :   Thread(false /*canCallJava*/),
         mType(type),
         mAudioFlinger(audioFlinger),
@@ -468,8 +470,7 @@
         // are set by PlaybackThread::readOutputParameters_l() or
         // RecordThread::readInputParameters_l()
         //FIXME: mStandby should be true here. Is this some kind of hack?
-        mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
-        mPrevOutDevice(AUDIO_DEVICE_NONE), mPrevInDevice(AUDIO_DEVICE_NONE),
+        mStandby(false),
         mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this)),
@@ -646,6 +647,18 @@
     return sendConfigEvent_l(configEvent);
 }
 
+status_t AudioFlinger::ThreadBase::sendUpdateOutDeviceConfigEvent(
+        const DeviceDescriptorBaseVector& outDevices)
+{
+    if (type() != RECORD) {
+        // The update out device operation is only for record thread.
+        return INVALID_OPERATION;
+    }
+    Mutex::Autolock _l(mLock);
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new UpdateOutDevicesConfigEvent(outDevices);
+    return sendConfigEvent_l(configEvent);
+}
+
 
 // post condition: mConfigEvents.isEmpty()
 void AudioFlinger::ThreadBase::processConfigEvents_l()
@@ -680,24 +693,29 @@
             }
         } break;
         case CFG_EVENT_CREATE_AUDIO_PATCH: {
-            const audio_devices_t oldDevice = getDevice();
+            const DeviceTypeSet oldDevices = getDeviceTypes();
             CreateAudioPatchConfigEventData *data =
                                             (CreateAudioPatchConfigEventData *)event->mData.get();
             event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
-            const audio_devices_t newDevice = getDevice();
-            mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
-                    (unsigned)oldDevice, toString(oldDevice).c_str(),
-                    (unsigned)newDevice, toString(newDevice).c_str());
+            const DeviceTypeSet newDevices = getDeviceTypes();
+            mLocalLog.log("CFG_EVENT_CREATE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
+                    dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
+                    dumpDeviceTypes(newDevices).c_str(), toString(newDevices).c_str());
         } break;
         case CFG_EVENT_RELEASE_AUDIO_PATCH: {
-            const audio_devices_t oldDevice = getDevice();
+            const DeviceTypeSet oldDevices = getDeviceTypes();
             ReleaseAudioPatchConfigEventData *data =
                                             (ReleaseAudioPatchConfigEventData *)event->mData.get();
             event->mStatus = releaseAudioPatch_l(data->mHandle);
-            const audio_devices_t newDevice = getDevice();
-            mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %#x (%s) new device %#x (%s)",
-                    (unsigned)oldDevice, toString(oldDevice).c_str(),
-                    (unsigned)newDevice, toString(newDevice).c_str());
+            const DeviceTypeSet newDevices = getDeviceTypes();
+            mLocalLog.log("CFG_EVENT_RELEASE_AUDIO_PATCH: old device %s (%s) new device %s (%s)",
+                    dumpDeviceTypes(oldDevices).c_str(), toString(oldDevices).c_str(),
+                    dumpDeviceTypes(newDevices).c_str(), toString(newDevices).c_str());
+        } break;
+        case CFG_EVENT_UPDATE_OUT_DEVICE: {
+            UpdateOutDevicesConfigEventData *data =
+                    (UpdateOutDevicesConfigEventData *)event->mData.get();
+            updateOutDevices(data->mOutDevices);
         } break;
         default:
             ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
@@ -840,8 +858,10 @@
         dprintf(fd, " none\n");
     }
     // Note: output device may be used by capture threads for effects such as AEC.
-    dprintf(fd, "  Output device: %#x (%s)\n", mOutDevice, toString(mOutDevice).c_str());
-    dprintf(fd, "  Input device: %#x (%s)\n", mInDevice, toString(mInDevice).c_str());
+    dprintf(fd, "  Output devices: %s (%s)\n",
+            dumpDeviceTypes(outDeviceTypes()).c_str(), toString(outDeviceTypes()).c_str());
+    dprintf(fd, "  Input device: %#x (%s)\n",
+            inDeviceType(), toString(inDeviceType()).c_str());
     dprintf(fd, "  Audio source: %d (%s)\n", mAudioSource, toString(mAudioSource).c_str());
 
     // Dump timestamp statistics for the Thread types that support it.
@@ -1011,6 +1031,12 @@
     mPowerManager.clear();
 }
 
+void AudioFlinger::ThreadBase::updateOutDevices(
+        const DeviceDescriptorBaseVector& outDevices __unused)
+{
+    ALOGE("%s should only be called in RecordThread", __func__);
+}
+
 void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who __unused)
 {
     sp<ThreadBase> thread = mThread.promote();
@@ -1351,8 +1377,9 @@
             }
             effectCreated = true;
 
-            effect->setDevice(mOutDevice);
-            effect->setDevice(mInDevice);
+            // FIXME: use vector of device and address when effect interface is ready.
+            effect->setDevices(outDeviceTypeAddrs());
+            effect->setInputDevice(inDeviceTypeAddr());
             effect->setMode(mAudioFlinger->getMode());
             effect->setAudioSource(mAudioSource);
         }
@@ -1468,8 +1495,8 @@
         return status;
     }
 
-    effect->setDevice(mOutDevice);
-    effect->setDevice(mInDevice);
+    effect->setDevices(outDeviceTypeAddrs());
+    effect->setInputDevice(inDeviceTypeAddr());
     effect->setMode(mAudioFlinger->getMode());
     effect->setAudioSource(mAudioSource);
 
@@ -1702,8 +1729,8 @@
     item->setInt64(MM_PREFIX "channelMask", (int64_t)mChannelMask);
     item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
     item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
-    item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
-    item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
+    item->setCString(MM_PREFIX "outDevice", toString(outDeviceTypes()).c_str());
+    item->setCString(MM_PREFIX "inDevice", toString(inDeviceType()).c_str());
 
     // thread statistics
     if (mIoJitterMs.getN() > 0) {
@@ -1734,10 +1761,9 @@
 AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
                                              AudioStreamOut* output,
                                              audio_io_handle_t id,
-                                             audio_devices_t device,
                                              type_t type,
                                              bool systemReady)
-    :   ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady),
+    :   ThreadBase(audioFlinger, id, type, systemReady),
         mNormalFrameCount(0), mSinkBuffer(NULL),
         mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
         mMixerBuffer(NULL),
@@ -1800,8 +1826,9 @@
     // TODO: We may also match on address as well as device type for
     // AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
     if (type == MIXER || type == DIRECT) {
-        mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
-                "audio.timestamp.corrected_output_devices",
+        // TODO: This property should be ensure that only contains one single device type.
+        mTimestampCorrectedDevice = (audio_devices_t)property_get_int64(
+                "audio.timestamp.corrected_output_device",
                 (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_OUT_BUS // turn on by default for MSD
                                        : AUDIO_DEVICE_NONE));
     }
@@ -2079,9 +2106,9 @@
             // More than 2 channels does not require stronger alignment than stereo
             alignment <<= 1;
         }
-        if (((uintptr_t)sharedBuffer->pointer() & (alignment - 1)) != 0) {
+        if (((uintptr_t)sharedBuffer->unsecurePointer() & (alignment - 1)) != 0) {
             ALOGE("Invalid buffer alignment: address %p, channel count %u",
-                  sharedBuffer->pointer(), channelCount);
+                  sharedBuffer->unsecurePointer(), channelCount);
             lStatus = BAD_VALUE;
             goto Exit;
         }
@@ -2609,7 +2636,7 @@
     LOG_ALWAYS_FATAL_IF(result != OK,
             "Error when retrieving output stream buffer size: %d", result);
     mFrameCount = mBufferSize / mFrameSize;
-    if (mFrameCount & 15) {
+    if ((mType == MIXER || mType == DUPLICATING) && (mFrameCount & 15)) {
         ALOGW("HAL output buffer size is %zu frames but AudioMixer requires multiples of 16 frames",
                 mFrameCount);
     }
@@ -2891,7 +2918,7 @@
 {
     if (!mMasterMute) {
         char value[PROPERTY_VALUE_MAX];
-        if (mOutDevice == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+        if (isSingleDeviceType(outDeviceTypes(), AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
             ALOGD("ro.audio.silent will be ignored for threads on AUDIO_DEVICE_OUT_REMOTE_SUBMIX");
             return;
         }
@@ -3035,7 +3062,7 @@
     // make sure standby delay is not too short when connected to an A2DP sink to avoid
     // truncating audio when going to standby.
     mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs;
-    if ((mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) {
+    if (!Intersection(outDeviceTypes(),  getAudioDeviceOutAllA2dpSet()).empty()) {
         if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) {
             mStandbyDelayNs = kDefaultStandbyTimeInNsecs;
         }
@@ -3283,8 +3310,8 @@
 
         // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
         //
-        // Note: we access outDevice() outside of mLock.
-        if (isMsdDevice() && (outDevice() & AUDIO_DEVICE_OUT_BUS) != 0) {
+        // Note: we access outDeviceTypes() outside of mLock.
+        if (isMsdDevice() && outDeviceTypes().count(AUDIO_DEVICE_OUT_BUS) != 0) {
             // Here, we try for the AF lock, but do not block on it as the latency
             // is more informational.
             if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
@@ -3820,8 +3847,10 @@
                             if (diff > 0) {
                                 // notify of throttle end on debug log
                                 // but prevent spamming for bluetooth
-                                ALOGD_IF(!audio_is_a2dp_out_device(outDevice()) &&
-                                         !audio_is_hearing_aid_out_device(outDevice()),
+                                ALOGD_IF(!isSingleDeviceType(
+                                                 outDeviceTypes(), audio_is_a2dp_out_device) &&
+                                         !isSingleDeviceType(
+                                                 outDeviceTypes(), audio_is_hearing_aid_out_device),
                                         "mixer(%p) throttle end: throttle time(%u)", this, diff);
                                 mThreadThrottleEndMs = mThreadThrottleTimeMs;
                             }
@@ -4006,25 +4035,31 @@
 
     // store new device and send to effects
     audio_devices_t type = AUDIO_DEVICE_NONE;
+    AudioDeviceTypeAddrVector deviceTypeAddrs;
     for (unsigned int i = 0; i < patch->num_sinks; i++) {
+        LOG_ALWAYS_FATAL_IF(popcount(patch->sinks[i].ext.device.type) > 1
+                            && !mOutput->audioHwDev->supportsAudioPatches(),
+                            "Enumerated device type(%#x) must not be used "
+                            "as it does not support audio patches",
+                            patch->sinks[i].ext.device.type);
         type |= patch->sinks[i].ext.device.type;
+        deviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
+                patch->sinks[i].ext.device.address));
     }
 
     audio_port_handle_t sinkPortId = patch->sinks[0].id;
 #ifdef ADD_BATTERY_DATA
     // when changing the audio output device, call addBatteryData to notify
     // the change
-    if (mOutDevice != type) {
+    if (outDeviceTypes() != deviceTypes) {
         uint32_t params = 0;
         // check whether speaker is on
-        if (type & AUDIO_DEVICE_OUT_SPEAKER) {
+        if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) > 0) {
             params |= IMediaPlayerService::kBatteryDataSpeakerOn;
         }
 
-        audio_devices_t deviceWithoutSpeaker
-            = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
         // check if any other device (except speaker) is on
-        if (type & deviceWithoutSpeaker) {
+        if (!isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_SPEAKER)) {
             params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
         }
 
@@ -4035,14 +4070,15 @@
 #endif
 
     for (size_t i = 0; i < mEffectChains.size(); i++) {
-        mEffectChains[i]->setDevice_l(type);
+        mEffectChains[i]->setDevices_l(deviceTypeAddrs);
     }
 
-    // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when
-    // the thread is created so that the first patch creation triggers an ioConfigChanged callback
-    bool configChanged = (mPrevOutDevice != type) || (mDeviceId != sinkPortId);
-    mOutDevice = type;
+    // mPatch.num_sinks is not set when the thread is created so that
+    // the first patch creation triggers an ioConfigChanged callback
+    bool configChanged = (mPatch.num_sinks == 0) ||
+                         (mPatch.sinks[0].id != sinkPortId);
     mPatch = *patch;
+    mOutDeviceTypeAddrs = deviceTypeAddrs;
 
     if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -4068,8 +4104,6 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
     if (configChanged) {
-        mPrevOutDevice = type;
-        mDeviceId = sinkPortId;
         sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
     }
     return status;
@@ -4093,7 +4127,8 @@
 {
     status_t status = NO_ERROR;
 
-    mOutDevice = AUDIO_DEVICE_NONE;
+    mPatch = audio_patch{};
+    mOutDeviceTypeAddrs.clear();
 
     if (mOutput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
@@ -4133,8 +4168,8 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-        audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
-    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady),
+        audio_io_handle_t id, bool systemReady, type_t type)
+    :   PlaybackThread(audioFlinger, output, id, type, systemReady),
         // mAudioMixer below
         // mFastMixer below
         mFastMixerFutex(0),
@@ -4144,7 +4179,7 @@
         // mNormalSink below
 {
     setMasterBalance(audioFlinger->getMasterBalance_l());
-    ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
+    ALOGV("MixerThread() id=%d type=%d", id, type);
     ALOGV("mSampleRate=%u, mChannelMask=%#x, mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
             "mFrameCount=%zu, mNormalFrameCount=%zu",
             mSampleRate, mChannelMask, mChannelCount, mFormat, mFrameSize, mFrameCount,
@@ -4186,7 +4221,7 @@
         // scheduled reliably with CFS. However, the BT A2DP HAL is
         // bursty (does not pull at a regular rate) and so cannot operate with FastMixer.
         initFastMixer = mFrameCount < mNormalFrameCount
-                && (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) == 0;
+                && Intersection(outDeviceTypes(), getAudioDeviceOutAllA2dpSet()).empty();
         break;
     }
     ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
@@ -5357,39 +5392,7 @@
         }
     }
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-#ifdef ADD_BATTERY_DATA
-        // when changing the audio output device, call addBatteryData to notify
-        // the change
-        if (mOutDevice != value) {
-            uint32_t params = 0;
-            // check whether speaker is on
-            if (value & AUDIO_DEVICE_OUT_SPEAKER) {
-                params |= IMediaPlayerService::kBatteryDataSpeakerOn;
-            }
-
-            audio_devices_t deviceWithoutSpeaker
-                = AUDIO_DEVICE_OUT_ALL & ~AUDIO_DEVICE_OUT_SPEAKER;
-            // check if any other device (except speaker) is on
-            if (value & deviceWithoutSpeaker) {
-                params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
-            }
-
-            if (params != 0) {
-                addBatteryData(params);
-            }
-        }
-#endif
-
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        if (value != AUDIO_DEVICE_NONE) {
-            a2dpDeviceChanged =
-                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
-            mOutDevice = value;
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(mOutDevice);
-            }
-        }
+        LOG_FATAL("Should not set routing device in MixerThread");
     }
 
     if (status == NO_ERROR) {
@@ -5490,9 +5493,8 @@
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device,
-        ThreadBase::type_t type, bool systemReady)
-    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
+        AudioStreamOut* output, audio_io_handle_t id, ThreadBase::type_t type, bool systemReady)
+    :   PlaybackThread(audioFlinger, output, id, type, systemReady)
 {
     setMasterBalance(audioFlinger->getMasterBalance_l());
 }
@@ -5894,16 +5896,7 @@
     AudioParameter param = AudioParameter(keyValuePair);
     int value;
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        if (value != AUDIO_DEVICE_NONE) {
-            a2dpDeviceChanged =
-                    (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
-            mOutDevice = value;
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(mOutDevice);
-            }
-        }
+        LOG_FATAL("Should not set routing device in DirectOutputThread");
     }
     if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
         // do not accept frame count changes if tracks are open as the track buffer
@@ -6115,8 +6108,8 @@
 
 // ----------------------------------------------------------------------------
 AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
-        AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
-    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
+        AudioStreamOut* output, audio_io_handle_t id, bool systemReady)
+    :   DirectOutputThread(audioFlinger, output, id, OFFLOAD, systemReady),
         mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true),
         mOffloadUnderrunPosition(~0LL)
 {
@@ -6441,7 +6434,7 @@
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
         AudioFlinger::MixerThread* mainThread, audio_io_handle_t id, bool systemReady)
-    :   MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->outDevice(),
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id,
                     systemReady, DUPLICATING),
         mWaitTimeMs(UINT_MAX)
 {
@@ -6673,11 +6666,9 @@
 AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
                                          AudioStreamIn *input,
                                          audio_io_handle_t id,
-                                         audio_devices_t outDevice,
-                                         audio_devices_t inDevice,
                                          bool systemReady
                                          ) :
-    ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
+    ThreadBase(audioFlinger, id, RECORD, systemReady),
     mInput(input),
     mSource(mInput),
     mActiveTracks(&this->mLocalLog),
@@ -6709,8 +6700,9 @@
 
     // TODO: We may also match on address as well as device type for
     // AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_DEVICE_IN_REMOTE_SUBMIX
-    mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
-            "audio.timestamp.corrected_input_devices",
+    // TODO: This property should be ensure that only contains one single device type.
+    mTimestampCorrectedDevice = (audio_devices_t)property_get_int64(
+            "audio.timestamp.corrected_input_device",
             (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_IN_BUS // turn on by default for MSD
                                    : AUDIO_DEVICE_NONE));
 
@@ -6757,7 +6749,7 @@
         sp<IMemory> pipeMemory;
         if ((roHeap == 0) ||
                 (pipeMemory = roHeap->allocate(pipeSize)) == 0 ||
-                (pipeBuffer = pipeMemory->pointer()) == nullptr) {
+                (pipeBuffer = pipeMemory->unsecurePointer()) == nullptr) {
             ALOGE("not enough memory for pipe buffer size=%zu; "
                     "roHeap=%p, pipeMemory=%p, pipeBuffer=%p; roHeapSize: %lld",
                     pipeSize, roHeap.get(), pipeMemory.get(), pipeBuffer,
@@ -7935,12 +7927,12 @@
     write(fd, result.string(), result.size());
 }
 
-void AudioFlinger::RecordThread::setRecordSilenced(uid_t uid, bool silenced)
+void AudioFlinger::RecordThread::setRecordSilenced(audio_port_handle_t portId, bool silenced)
 {
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mTracks.size() ; i++) {
         sp<RecordTrack> track = mTracks[i];
-        if (track != 0 && track->uid() == uid) {
+        if (track != 0 && track->portId() == portId) {
             track->setSilenced(silenced);
         }
     }
@@ -8054,7 +8046,7 @@
 {
     // disable AEC and NS if the device is a BT SCO headset supporting those
     // pre processings
-    bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
+    bool suspend = audio_is_bluetooth_sco_device(inDeviceType()) &&
                         mAudioFlinger->btNrecIsOff();
     if (mBtNrecSuspended.exchange(suspend) != suspend) {
         for (size_t i = 0; i < mEffectChains.size(); i++) {
@@ -8119,34 +8111,11 @@
         }
     }
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        for (size_t i = 0; i < mEffectChains.size(); i++) {
-            mEffectChains[i]->setDevice_l(value);
-        }
-
-        // store input device and output device but do not forward output device to audio HAL.
-        // Note that status is ignored by the caller for output device
-        // (see AudioFlinger::setParameters()
-        if (audio_is_output_devices(value)) {
-            mOutDevice = value;
-            status = BAD_VALUE;
-        } else {
-            mInDevice = value;
-            if (value != AUDIO_DEVICE_NONE) {
-                mPrevInDevice = value;
-            }
-            checkBtNrec_l();
-        }
+        LOG_FATAL("Should not set routing device in RecordThread");
     }
     if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
             mAudioSource != (audio_source_t)value) {
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        for (size_t i = 0; i < mEffectChains.size(); i++) {
-            mEffectChains[i]->setAudioSource_l((audio_source_t)value);
-        }
-        mAudioSource = (audio_source_t)value;
+        LOG_FATAL("Should not set audio source in RecordThread");
     }
 
     if (status == NO_ERROR) {
@@ -8348,11 +8317,11 @@
     status_t status = NO_ERROR;
 
     // store new device and send to effects
-    mInDevice = patch->sources[0].ext.device.type;
+    mInDeviceTypeAddr.mType = patch->sources[0].ext.device.type;
+    mInDeviceTypeAddr.mAddress = patch->sources[0].ext.device.address;
     audio_port_handle_t deviceId = patch->sources[0].id;
-    mPatch = *patch;
     for (size_t i = 0; i < mEffectChains.size(); i++) {
-        mEffectChains[i]->setDevice_l(mInDevice);
+        mEffectChains[i]->setInputDevice_l(inDeviceTypeAddr());
     }
 
     checkBtNrec_l();
@@ -8391,10 +8360,9 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    if ((mInDevice != mPrevInDevice) || (mDeviceId != deviceId)) {
+    if ((mPatch.num_sources == 0) || (mPatch.sources[0].id != deviceId)) {
         sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
-        mPrevInDevice = mInDevice;
-        mDeviceId = deviceId;
+        mPatch = *patch;
     }
 
     return status;
@@ -8404,7 +8372,8 @@
 {
     status_t status = NO_ERROR;
 
-    mInDevice = AUDIO_DEVICE_NONE;
+    mPatch = audio_patch{};
+    mInDeviceTypeAddr.reset();
 
     if (mInput->audioHwDev->supportsAudioPatches()) {
         sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
@@ -8417,6 +8386,15 @@
     return status;
 }
 
+void AudioFlinger::RecordThread::updateOutDevices(const DeviceDescriptorBaseVector& outDevices)
+{
+    mOutDevices = outDevices;
+    mOutDeviceTypeAddrs = deviceTypeAddrsFromDescriptors(mOutDevices);
+    for (size_t i = 0; i < mEffectChains.size(); i++) {
+        mEffectChains[i]->setDevices_l(outDeviceTypeAddrs());
+    }
+}
+
 void AudioFlinger::RecordThread::addPatchTrack(const sp<PatchRecord>& record)
 {
     Mutex::Autolock _l(mLock);
@@ -8493,9 +8471,8 @@
 
 AudioFlinger::MmapThread::MmapThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
-        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
-    : ThreadBase(audioFlinger, id, outDevice, inDevice, MMAP, systemReady),
+        AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady)
+    : ThreadBase(audioFlinger, id, MMAP, systemReady),
       mSessionId(AUDIO_SESSION_NONE),
       mPortId(AUDIO_PORT_HANDLE_NONE),
       mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
@@ -8861,26 +8838,7 @@
     int value;
     bool sendToHal = true;
     if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
-        audio_devices_t device = (audio_devices_t)value;
-        // forward device change to effects that have requested to be
-        // aware of attached audio device.
-        if (device != AUDIO_DEVICE_NONE) {
-            for (size_t i = 0; i < mEffectChains.size(); i++) {
-                mEffectChains[i]->setDevice_l(device);
-            }
-        }
-        if (audio_is_output_devices(device)) {
-            mOutDevice = device;
-            if (!isOutput()) {
-                sendToHal = false;
-            }
-        } else {
-            mInDevice = device;
-            if (device != AUDIO_DEVICE_NONE) {
-                mPrevInDevice = value;
-            }
-            // TODO: implement and call checkBtNrec_l();
-        }
+        LOG_FATAL("Should not happen set routing device in MmapThread");
     }
     if (sendToHal) {
         status = mHalStream->setParameters(keyValuePair);
@@ -8939,24 +8897,39 @@
     // store new device and send to effects
     audio_devices_t type = AUDIO_DEVICE_NONE;
     audio_port_handle_t deviceId;
+    AudioDeviceTypeAddrVector sinkDeviceTypeAddrs;
+    AudioDeviceTypeAddr sourceDeviceTypeAddr;
+    uint32_t numDevices = 0;
     if (isOutput()) {
         for (unsigned int i = 0; i < patch->num_sinks; i++) {
+            LOG_ALWAYS_FATAL_IF(popcount(patch->sinks[i].ext.device.type) > 1
+                                && !mAudioHwDev->supportsAudioPatches(),
+                                "Enumerated device type(%#x) must not be used "
+                                "as it does not support audio patches",
+                                patch->sinks[i].ext.device.type);
             type |= patch->sinks[i].ext.device.type;
+            sinkDeviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
+                    patch->sinks[i].ext.device.address));
         }
         deviceId = patch->sinks[0].id;
+        numDevices = mPatch.num_sinks;
     } else {
         type = patch->sources[0].ext.device.type;
         deviceId = patch->sources[0].id;
+        numDevices = mPatch.num_sources;
+        sourceDeviceTypeAddr.mType = patch->sources[0].ext.device.type;
+        sourceDeviceTypeAddr.mAddress = patch->sources[0].ext.device.address;
     }
 
     for (size_t i = 0; i < mEffectChains.size(); i++) {
-        mEffectChains[i]->setDevice_l(type);
+        if (isOutput()) {
+            mEffectChains[i]->setDevices_l(sinkDeviceTypeAddrs);
+        } else {
+            mEffectChains[i]->setInputDevice_l(sourceDeviceTypeAddr);
+        }
     }
 
-    if (isOutput()) {
-        mOutDevice = type;
-    } else {
-        mInDevice = type;
+    if (!isOutput()) {
         // store new source and send to effects
         if (mAudioSource != patch->sinks[0].ext.mix.usecase.source) {
             mAudioSource = patch->sinks[0].ext.mix.usecase.source;
@@ -8993,26 +8966,21 @@
         *handle = AUDIO_PATCH_HANDLE_NONE;
     }
 
-    if (isOutput() && (mPrevOutDevice != mOutDevice || mDeviceId != deviceId)) {
-        mPrevOutDevice = type;
-        sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+    if (numDevices == 0 || mDeviceId != deviceId) {
+        if (isOutput()) {
+            sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
+            mOutDeviceTypeAddrs = sinkDeviceTypeAddrs;
+        } else {
+            sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+            mInDeviceTypeAddr = sourceDeviceTypeAddr;
+        }
         sp<MmapStreamCallback> callback = mCallback.promote();
         if (mDeviceId != deviceId && callback != 0) {
             mLock.unlock();
             callback->onRoutingChanged(deviceId);
             mLock.lock();
         }
-        mDeviceId = deviceId;
-    }
-    if (!isOutput() && (mPrevInDevice != mInDevice || mDeviceId != deviceId)) {
-        mPrevInDevice = type;
-        sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
-        sp<MmapStreamCallback> callback = mCallback.promote();
-        if (mDeviceId != deviceId && callback != 0) {
-            mLock.unlock();
-            callback->onRoutingChanged(deviceId);
-            mLock.lock();
-        }
+        mPatch = *patch;
         mDeviceId = deviceId;
     }
     return status;
@@ -9022,7 +8990,9 @@
 {
     status_t status = NO_ERROR;
 
-    mInDevice = AUDIO_DEVICE_NONE;
+    mPatch = audio_patch{};
+    mOutDeviceTypeAddrs.clear();
+    mInDeviceTypeAddr.reset();
 
     bool supportsAudioPatches = mHalDevice->supportsAudioPatches(&supportsAudioPatches) == OK ?
                                         supportsAudioPatches : false;
@@ -9198,9 +9168,8 @@
 
 AudioFlinger::MmapPlaybackThread::MmapPlaybackThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        AudioHwDevice *hwDev,  AudioStreamOut *output,
-        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
-    : MmapThread(audioFlinger, id, hwDev, output->stream, outDevice, inDevice, systemReady),
+        AudioHwDevice *hwDev,  AudioStreamOut *output, bool systemReady)
+    : MmapThread(audioFlinger, id, hwDev, output->stream, systemReady),
       mStreamType(AUDIO_STREAM_MUSIC),
       mStreamVolume(1.0),
       mStreamMute(false),
@@ -9410,9 +9379,8 @@
 
 AudioFlinger::MmapCaptureThread::MmapCaptureThread(
         const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-        AudioHwDevice *hwDev,  AudioStreamIn *input,
-        audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady)
-    : MmapThread(audioFlinger, id, hwDev, input->stream, outDevice, inDevice, systemReady),
+        AudioHwDevice *hwDev,  AudioStreamIn *input, bool systemReady)
+    : MmapThread(audioFlinger, id, hwDev, input->stream, systemReady),
       mInput(input)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
@@ -9484,11 +9452,11 @@
     mInput->stream->updateSinkMetadata(metadata);
 }
 
-void AudioFlinger::MmapCaptureThread::setRecordSilenced(uid_t uid, bool silenced)
+void AudioFlinger::MmapCaptureThread::setRecordSilenced(audio_port_handle_t portId, bool silenced)
 {
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mActiveTracks.size() ; i++) {
-        if (mActiveTracks[i]->uid() == uid) {
+        if (mActiveTracks[i]->portId() == portId) {
             mActiveTracks[i]->setSilenced_l(silenced);
             broadcast_l();
         }
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 0a473d5..ef7eb6e 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -37,8 +37,7 @@
     static const char *threadTypeToString(type_t type);
 
     ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                audio_devices_t outDevice, audio_devices_t inDevice, type_t type,
-                bool systemReady);
+               type_t type, bool systemReady);
     virtual             ~ThreadBase();
 
     virtual status_t    readyToRun();
@@ -52,6 +51,7 @@
         CFG_EVENT_SET_PARAMETER,
         CFG_EVENT_CREATE_AUDIO_PATCH,
         CFG_EVENT_RELEASE_AUDIO_PATCH,
+        CFG_EVENT_UPDATE_OUT_DEVICE,
     };
 
     class ConfigEventData: public RefBase {
@@ -219,6 +219,28 @@
         virtual ~ReleaseAudioPatchConfigEvent() {}
     };
 
+    class UpdateOutDevicesConfigEventData : public ConfigEventData {
+    public:
+        explicit UpdateOutDevicesConfigEventData(const DeviceDescriptorBaseVector& outDevices) :
+            mOutDevices(outDevices) {}
+
+        virtual void dump(char *buffer, size_t size) {
+            snprintf(buffer, size, "Devices: %s", android::toString(mOutDevices).c_str());
+        }
+
+        DeviceDescriptorBaseVector mOutDevices;
+    };
+
+    class UpdateOutDevicesConfigEvent : public ConfigEvent {
+    public:
+        explicit UpdateOutDevicesConfigEvent(const DeviceDescriptorBaseVector& outDevices) :
+            ConfigEvent(CFG_EVENT_UPDATE_OUT_DEVICE) {
+            mData = new UpdateOutDevicesConfigEventData(outDevices);
+        }
+
+        virtual ~UpdateOutDevicesConfigEvent();
+    };
+
     class PMDeathRecipient : public IBinder::DeathRecipient {
     public:
         explicit    PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
@@ -278,19 +300,33 @@
                 status_t    sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
                                                             audio_patch_handle_t *handle);
                 status_t    sendReleaseAudioPatchConfigEvent(audio_patch_handle_t handle);
+                status_t    sendUpdateOutDeviceConfigEvent(
+                                    const DeviceDescriptorBaseVector& outDevices);
                 void        processConfigEvents_l();
     virtual     void        cacheParameters_l() = 0;
     virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
                                                audio_patch_handle_t *handle) = 0;
     virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
+    virtual     void        updateOutDevices(const DeviceDescriptorBaseVector& outDevices);
     virtual     void        toAudioPortConfig(struct audio_port_config *config) = 0;
 
 
                 // see note at declaration of mStandby, mOutDevice and mInDevice
                 bool        standby() const { return mStandby; }
-                audio_devices_t outDevice() const { return mOutDevice; }
-                audio_devices_t inDevice() const { return mInDevice; }
-                audio_devices_t getDevice() const { return isOutput() ? mOutDevice : mInDevice; }
+                const DeviceTypeSet outDeviceTypes() const {
+                    return getAudioDeviceTypes(mOutDeviceTypeAddrs);
+                }
+                audio_devices_t inDeviceType() const { return mInDeviceTypeAddr.mType; }
+                DeviceTypeSet getDeviceTypes() const {
+                    return isOutput() ? outDeviceTypes() : DeviceTypeSet({inDeviceType()});
+                }
+
+                const AudioDeviceTypeAddrVector& outDeviceTypeAddrs() const {
+                    return mOutDeviceTypeAddrs;
+                }
+                const AudioDeviceTypeAddr& inDeviceTypeAddr() const {
+                    return mInDeviceTypeAddr;
+                }
 
     virtual     bool        isOutput() const = 0;
 
@@ -502,26 +538,21 @@
                                                            // HAL format if Fastmixer is used.
                 audio_format_t          mHALFormat;
                 size_t                  mBufferSize;       // HAL buffer size for read() or write()
-
+                AudioDeviceTypeAddrVector mOutDeviceTypeAddrs; // output device types and addresses
+                AudioDeviceTypeAddr       mInDeviceTypeAddr;   // input device type and address
                 Vector< sp<ConfigEvent> >     mConfigEvents;
                 Vector< sp<ConfigEvent> >     mPendingConfigEvents; // events awaiting system ready
 
                 // These fields are written and read by thread itself without lock or barrier,
-                // and read by other threads without lock or barrier via standby(), outDevice()
-                // and inDevice().
+                // and read by other threads without lock or barrier via standby(), outDeviceTypes()
+                // and inDeviceType().
                 // Because of the absence of a lock or barrier, any other thread that reads
                 // these fields must use the information in isolation, or be prepared to deal
                 // with possibility that it might be inconsistent with other information.
                 bool                    mStandby;     // Whether thread is currently in standby.
-                audio_devices_t         mOutDevice;   // output device
-                audio_devices_t         mInDevice;    // input device
-                audio_devices_t         mPrevOutDevice;   // previous output device
-                audio_devices_t         mPrevInDevice;    // previous input device
+
                 struct audio_patch      mPatch;
-                /**
-                 * @brief mDeviceId  current device port unique identifier
-                 */
-                audio_port_handle_t     mDeviceId = AUDIO_PORT_HANDLE_NONE;
+
                 audio_source_t          mAudioSource;
 
                 const audio_io_handle_t mId;
@@ -544,7 +575,8 @@
                 ExtendedTimestamp       mTimestamp;
                 TimestampVerifier< // For timestamp statistics.
                         int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
-                audio_devices_t         mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+                // Timestamp corrected device should be a single device.
+                audio_devices_t         mTimestampCorrectedDevice = AUDIO_DEVICE_NONE;
 
                 // ThreadLoop statistics per iteration.
                 int64_t                 mLastIoBeginNs = -1;
@@ -719,7 +751,7 @@
     static const nsecs_t kMaxNextBufferDelayNs = 100000000;
 
     PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                   audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
+                   audio_io_handle_t id, type_t type, bool systemReady);
     virtual             ~PlaybackThread();
 
     // Thread virtuals
@@ -886,10 +918,10 @@
                             }
 
                 bool        isTimestampCorrectionEnabled() const override {
-                                const audio_devices_t device =
-                                        mOutDevice & mTimestampCorrectedDevices;
-                                return audio_is_output_devices(device) && popcount(device) > 0;
+                                return audio_is_output_devices(mTimestampCorrectedDevice)
+                                        && outDeviceTypes().count(mTimestampCorrectedDevice) != 0;
                             }
+
 protected:
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -1171,7 +1203,6 @@
     MixerThread(const sp<AudioFlinger>& audioFlinger,
                 AudioStreamOut* output,
                 audio_io_handle_t id,
-                audio_devices_t device,
                 bool systemReady,
                 type_t type = MIXER);
     virtual             ~MixerThread();
@@ -1269,8 +1300,8 @@
 public:
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                       audio_io_handle_t id, audio_devices_t device, bool systemReady)
-        : DirectOutputThread(audioFlinger, output, id, device, DIRECT, systemReady) { }
+                       audio_io_handle_t id, bool systemReady)
+        : DirectOutputThread(audioFlinger, output, id, DIRECT, systemReady) { }
 
     virtual                 ~DirectOutputThread();
 
@@ -1305,8 +1336,7 @@
     bool mVolumeShaperActive = false;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, audio_devices_t device, ThreadBase::type_t type,
-                        bool systemReady);
+                       audio_io_handle_t id, ThreadBase::type_t type, bool systemReady);
     void processVolume_l(Track *track, bool lastTrack);
 
     // prepareTracks_l() tells threadLoop_mix() the name of the single active track
@@ -1345,7 +1375,7 @@
 public:
 
     OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
-                        audio_io_handle_t id, uint32_t device, bool systemReady);
+                  audio_io_handle_t id, bool systemReady);
     virtual                 ~OffloadThread() {};
     virtual     void        flushHw_l();
 
@@ -1516,8 +1546,6 @@
             RecordThread(const sp<AudioFlinger>& audioFlinger,
                     AudioStreamIn *input,
                     audio_io_handle_t id,
-                    audio_devices_t outDevice,
-                    audio_devices_t inDevice,
                     bool systemReady
                     );
             virtual     ~RecordThread();
@@ -1577,6 +1605,7 @@
     virtual status_t    createAudioPatch_l(const struct audio_patch *patch,
                                            audio_patch_handle_t *handle);
     virtual status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
+            void        updateOutDevices(const DeviceDescriptorBaseVector& outDevices) override;
 
             void        addPatchTrack(const sp<PatchRecord>& record);
             void        deletePatchTrack(const sp<PatchRecord>& record);
@@ -1616,7 +1645,7 @@
             void        checkBtNrec();
 
             // Sets the UID records silence
-            void        setRecordSilenced(uid_t uid, bool silenced);
+            void        setRecordSilenced(audio_port_handle_t portId, bool silenced);
 
             status_t    getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
 
@@ -1629,8 +1658,8 @@
 
             bool        isTimestampCorrectionEnabled() const override {
                             // checks popcount for exactly one device.
-                            return audio_is_input_device(
-                                    mInDevice & mTimestampCorrectedDevices);
+                            return audio_is_input_device(mTimestampCorrectedDevice)
+                                    && inDeviceType() == mTimestampCorrectedDevice;
                         }
 
 protected:
@@ -1709,6 +1738,8 @@
             std::atomic_bool                    mBtNrecSuspended;
 
             int64_t                             mFramesRead = 0;    // continuous running counter.
+
+            DeviceDescriptorBaseVector          mOutDevices;
 };
 
 class MmapThread : public ThreadBase
@@ -1718,8 +1749,7 @@
 #include "MmapTracks.h"
 
     MmapThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                      AudioHwDevice *hwDev, sp<StreamHalInterface> stream,
-                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+               AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady);
     virtual     ~MmapThread();
 
     virtual     void        configure(const audio_attributes_t *attr,
@@ -1786,12 +1816,18 @@
     virtual     void        invalidateTracks(audio_stream_type_t streamType __unused) {}
 
                 // Sets the UID records silence
-    virtual     void        setRecordSilenced(uid_t uid __unused, bool silenced __unused) {}
+    virtual     void        setRecordSilenced(audio_port_handle_t portId __unused,
+                                              bool silenced __unused) {}
 
  protected:
                 void        dumpInternals_l(int fd, const Vector<String16>& args) override;
                 void        dumpTracks_l(int fd, const Vector<String16>& args) override;
 
+                /**
+                 * @brief mDeviceId  current device port unique identifier
+                 */
+                audio_port_handle_t     mDeviceId = AUDIO_PORT_HANDLE_NONE;
+
                 audio_attributes_t      mAttr;
                 audio_session_t         mSessionId;
                 audio_port_handle_t     mPortId;
@@ -1812,8 +1848,7 @@
 
 public:
     MmapPlaybackThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                      AudioHwDevice *hwDev, AudioStreamOut *output,
-                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+                       AudioHwDevice *hwDev, AudioStreamOut *output, bool systemReady);
     virtual     ~MmapPlaybackThread() {}
 
     virtual     void        configure(const audio_attributes_t *attr,
@@ -1862,8 +1897,7 @@
 
 public:
     MmapCaptureThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
-                      AudioHwDevice *hwDev, AudioStreamIn *input,
-                      audio_devices_t outDevice, audio_devices_t inDevice, bool systemReady);
+                      AudioHwDevice *hwDev, AudioStreamIn *input, bool systemReady);
     virtual     ~MmapCaptureThread() {}
 
                 AudioStreamIn* clearInput();
@@ -1873,7 +1907,8 @@
 
                 void           updateMetadata_l() override;
                 void           processVolume_l() override;
-                void           setRecordSilenced(uid_t uid, bool silenced) override;
+                void           setRecordSilenced(audio_port_handle_t portId,
+                                                 bool silenced) override;
 
     virtual     void           toAudioPortConfig(struct audio_port_config *config);
 
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 52e7d59..051f1e3 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -205,6 +205,16 @@
 protected:
     DISALLOW_COPY_AND_ASSIGN(TrackBase);
 
+    void releaseCblk() {
+        if (mCblk != nullptr) {
+            mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
+            if (mClient == 0) {
+                free(mCblk);
+            }
+            mCblk = nullptr;
+        }
+    }
+
     // AudioBufferProvider interface
     virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
     virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e4402bd..23c2209 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -150,7 +150,7 @@
     if (client != 0) {
         mCblkMemory = client->heap()->allocate(size);
         if (mCblkMemory == 0 ||
-                (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->pointer())) == NULL) {
+                (mCblk = static_cast<audio_track_cblk_t *>(mCblkMemory->unsecurePointer())) == NULL) {
             ALOGE("%s(%d): not enough memory for AudioTrack size=%zu", __func__, mId, size);
             client->heap()->dump("AudioTrack");
             mCblkMemory.clear();
@@ -172,7 +172,7 @@
             const sp<MemoryDealer> roHeap(thread->readOnlyHeap());
             if (roHeap == 0 ||
                     (mBufferMemory = roHeap->allocate(bufferSize)) == 0 ||
-                    (mBuffer = mBufferMemory->pointer()) == NULL) {
+                    (mBuffer = mBufferMemory->unsecurePointer()) == NULL) {
                 ALOGE("%s(%d): not enough memory for read-only buffer size=%zu",
                         __func__, mId, bufferSize);
                 if (roHeap != 0) {
@@ -187,7 +187,7 @@
         case ALLOC_PIPE:
             mBufferMemory = thread->pipeMemory();
             // mBuffer is the virtual address as seen from current process (mediaserver),
-            // and should normally be coming from mBufferMemory->pointer().
+            // and should normally be coming from mBufferMemory->unsecurePointer().
             // However in this case the TrackBase does not reference the buffer directly.
             // It should references the buffer via the pipe.
             // Therefore, to detect incorrect usage of the buffer, we set mBuffer to NULL.
@@ -239,12 +239,7 @@
 {
     // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference
     mServerProxy.clear();
-    if (mCblk != NULL) {
-        mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
-        if (mClient == 0) {
-            free(mCblk);
-        }
-    }
+    releaseCblk();
     mCblkMemory.clear();    // free the shared memory before releasing the heap it belongs to
     if (mClient != 0) {
         // Client destructor must run with AudioFlinger client mutex locked
@@ -516,7 +511,11 @@
             audio_port_handle_t portId,
             size_t frameCountToBeReady)
     :   TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
-                  (sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
+                  // TODO: Using unsecurePointer() has some associated security pitfalls
+                  //       (see declaration for details).
+                  //       Either document why it is safe in this case or address the
+                  //       issue (e.g. by copying).
+                  (sharedBuffer != 0) ? sharedBuffer->unsecurePointer() : buffer,
                   (sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
                   sessionId, creatorPid, uid, true /*isOut*/,
                   (type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
@@ -547,25 +546,27 @@
     ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
 
     ALOGV_IF(sharedBuffer != 0, "%s(%d): sharedBuffer: %p, size: %zu",
-            __func__, mId, sharedBuffer->pointer(), sharedBuffer->size());
+            __func__, mId, sharedBuffer->unsecurePointer(), sharedBuffer->size());
 
     if (mCblk == NULL) {
         return;
     }
 
+    if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
+        ALOGE("%s(%d): no more tracks available", __func__, mId);
+        releaseCblk(); // this makes the track invalid.
+        return;
+    }
+
     if (sharedBuffer == 0) {
         mAudioTrackServerProxy = new AudioTrackServerProxy(mCblk, mBuffer, frameCount,
                 mFrameSize, !isExternalTrack(), sampleRate);
     } else {
         mAudioTrackServerProxy = new StaticAudioTrackServerProxy(mCblk, mBuffer, frameCount,
-                mFrameSize);
+                mFrameSize, sampleRate);
     }
     mServerProxy = mAudioTrackServerProxy;
 
-    if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
-        ALOGE("%s(%d): no more tracks available", __func__, mId);
-        return;
-    }
     // only allocate a fast track index if we were able to allocate a normal track name
     if (flags & AUDIO_OUTPUT_FLAG_FAST) {
         // FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential
@@ -1897,7 +1898,7 @@
 // static
 sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
 AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded(
-            uid_t uid, const String16& opPackageName)
+            uid_t uid, const audio_attributes_t& attr, const String16& opPackageName)
 {
     if (isServiceUid(uid)) {
         ALOGV("not silencing record for service uid:%d pack:%s",
@@ -1905,6 +1906,13 @@
         return nullptr;
     }
 
+    // Capturing from FM TUNER output is not controlled by OP_RECORD_AUDIO
+    // because it does not affect users privacy as does capturing from an actual microphone.
+    if (attr.source == AUDIO_SOURCE_FM_TUNER) {
+        ALOGV("not muting FM TUNER capture for uid %d", uid);
+        return nullptr;
+    }
+
     if (opPackageName.size() == 0) {
         Vector<String16> packages;
         // no package name, happens with SL ES clients
@@ -2070,7 +2078,7 @@
         mRecordBufferConverter(NULL),
         mFlags(flags),
         mSilenced(false),
-        mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, opPackageName))
+        mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, attr, opPackageName))
 {
     if (mCblk == NULL) {
         return;
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 30f29d6..92d8c83 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -17,8 +17,10 @@
 #ifndef ANDROID_AUDIOPOLICY_INTERFACE_H
 #define ANDROID_AUDIOPOLICY_INTERFACE_H
 
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioSystem.h>
 #include <media/AudioPolicy.h>
+#include <media/DeviceDescriptorBase.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -67,6 +69,14 @@
         API_INPUT_TELEPHONY_RX, // used for capture from telephony RX path
     } input_type_t;
 
+    typedef enum {
+        API_OUTPUT_INVALID = -1,
+        API_OUTPUT_LEGACY  = 0,// e.g. audio playing to speaker
+        API_OUT_MIX_PLAYBACK,  // used for "remote submix" playback of audio from remote source
+                               // to local capture
+        API_OUTPUT_TELEPHONY_TX, // used for playback to telephony TX path
+    } output_type_t;
+
 public:
     virtual ~AudioPolicyInterface() {}
     //
@@ -113,7 +123,8 @@
                                         audio_output_flags_t *flags,
                                         audio_port_handle_t *selectedDeviceId,
                                         audio_port_handle_t *portId,
-                                        std::vector<audio_io_handle_t> *secondaryOutputs) = 0;
+                                        std::vector<audio_io_handle_t> *secondaryOutputs,
+                                        output_type_t *outputType) = 0;
     // indicates to the audio policy manager that the output starts being used by corresponding stream.
     virtual status_t startOutput(audio_port_handle_t portId) = 0;
     // indicates to the audio policy manager that the output stops being used by corresponding stream.
@@ -258,7 +269,7 @@
     virtual status_t getHwOffloadEncodingFormatsSupportedForA2DP(
                 std::vector<audio_format_t> *formats) = 0;
 
-    virtual void     setAppState(uid_t uid, app_state_t state) = 0;
+    virtual void     setAppState(audio_port_handle_t portId, app_state_t state) = 0;
 
     virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies) = 0;
 
@@ -269,6 +280,8 @@
 
     virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
                                                        volume_group_t &volumeGroup) = 0;
+
+    virtual bool     isCallScreenModeSupported() = 0;
 };
 
 
@@ -296,8 +309,7 @@
     virtual status_t openOutput(audio_module_handle_t module,
                                 audio_io_handle_t *output,
                                 audio_config_t *config,
-                                audio_devices_t *devices,
-                                const String8& address,
+                                const sp<DeviceDescriptorBase>& device,
                                 uint32_t *latencyMs,
                                 audio_output_flags_t flags) = 0;
     // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
index a94fd87..eb6c19e 100644
--- a/services/audiopolicy/TEST_MAPPING
+++ b/services/audiopolicy/TEST_MAPPING
@@ -2,9 +2,6 @@
   "presubmit": [
     {
        "name": "audiopolicy_tests"
-    },
-    {
-       "name": "systemaudio_tests"
     }
   ]
 }
diff --git a/services/audiopolicy/common/Android.bp b/services/audiopolicy/common/Android.bp
index a925b9a..6e0d2f6 100644
--- a/services/audiopolicy/common/Android.bp
+++ b/services/audiopolicy/common/Android.bp
@@ -1,4 +1,7 @@
 cc_library_headers {
     name: "libaudiopolicycommon",
+    header_libs: [
+        "libaudiofoundation_headers",
+    ],
     export_include_dirs: ["include"],
 }
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 1dbd1eb..7c8ce83 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -17,10 +17,13 @@
 #pragma once
 
 #include <media/AudioCommonTypes.h>
+#include <media/AudioContainers.h>
 #include <system/audio.h>
 #include <utils/Log.h>
 #include <math.h>
 
+#include "policy.h"
+
 namespace android {
 
 /**
@@ -82,43 +85,26 @@
      *
      * @return subset of device required to limit the number of volume category per device
      */
-    static audio_devices_t getDeviceForVolume(audio_devices_t device)
+    static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
     {
-        if (device == AUDIO_DEVICE_NONE) {
+        if (deviceTypes.empty()) {
             // this happens when forcing a route update and no track is active on an output.
             // In this case the returned category is not important.
-            device =  AUDIO_DEVICE_OUT_SPEAKER;
-        } else if (popcount(device) > 1) {
-            // Multiple device selection is either:
-            //  - speaker + one other device: give priority to speaker in this case.
-            //  - one A2DP device + another device: happens with duplicated output. In this case
-            // retain the device on the A2DP output as the other must not correspond to an active
-            // selection if not the speaker.
-            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
-            if (device & AUDIO_DEVICE_OUT_SPEAKER) {
-                device = AUDIO_DEVICE_OUT_SPEAKER;
-            } else if (device & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
-                device = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-            } else if (device & AUDIO_DEVICE_OUT_HDMI_ARC) {
-                device = AUDIO_DEVICE_OUT_HDMI_ARC;
-            } else if (device & AUDIO_DEVICE_OUT_AUX_LINE) {
-                device = AUDIO_DEVICE_OUT_AUX_LINE;
-            } else if (device & AUDIO_DEVICE_OUT_SPDIF) {
-                device = AUDIO_DEVICE_OUT_SPDIF;
-            } else {
-                device = (audio_devices_t)(device & AUDIO_DEVICE_OUT_ALL_A2DP);
-            }
+            return AUDIO_DEVICE_OUT_SPEAKER;
         }
 
+        audio_devices_t deviceType = apm_extract_one_audio_device(deviceTypes);
+
         /*SPEAKER_SAFE is an alias of SPEAKER for purposes of volume control*/
-        if (device == AUDIO_DEVICE_OUT_SPEAKER_SAFE)
-            device = AUDIO_DEVICE_OUT_SPEAKER;
+        if (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+            deviceType = AUDIO_DEVICE_OUT_SPEAKER;
+        }
 
-        ALOGW_IF(popcount(device) != 1,
-                 "getDeviceForVolume() invalid device combination: %08x",
-                 device);
+        ALOGW_IF(deviceType == AUDIO_DEVICE_NONE,
+                 "getDeviceForVolume() invalid device combination: %s, returning AUDIO_DEVICE_NONE",
+                 android::dumpDeviceTypes(deviceTypes).c_str());
 
-        return device;
+        return deviceType;
     }
 
     /**
@@ -128,9 +114,9 @@
      *
      * @return device category.
      */
-    static device_category getDeviceCategory(audio_devices_t device)
+    static device_category getDeviceCategory(const android::DeviceTypeSet& deviceTypes)
     {
-        switch(getDeviceForVolume(device)) {
+        switch(getDeviceForVolume(deviceTypes)) {
         case AUDIO_DEVICE_OUT_EARPIECE:
             return DEVICE_CATEGORY_EARPIECE;
         case AUDIO_DEVICE_OUT_WIRED_HEADSET:
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 605fc1c..0537365 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -19,6 +19,8 @@
 #include <system/audio.h>
 #include <vector>
 
+#include <media/AudioContainers.h>
+
 namespace android {
 
 using StreamTypeVector = std::vector<audio_stream_type_t>;
@@ -43,14 +45,6 @@
 #define MAX_MIXER_CHANNEL_COUNT FCC_8
 
 /**
- * A device mask for all audio input and output devices where matching inputs/outputs on device
- * type alone is not enough: the address must match too
- */
-#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX|AUDIO_DEVICE_OUT_BUS)
-
-#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_BUS)
-
-/**
  * Alias to AUDIO_DEVICE_OUT_DEFAULT defined for clarification when this value is used by volume
  * control APIs (e.g setStreamVolumeIndex().
  */
@@ -71,6 +65,34 @@
 }
 
 /**
+ * Check whether the output device type is one
+ * where addresses are used to distinguish between one connected device and another
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device needs distinguish on address, false otherwise..
+ */
+static inline bool apm_audio_out_device_distinguishes_on_address(audio_devices_t device)
+{
+    return device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ||
+           device == AUDIO_DEVICE_OUT_BUS;
+}
+
+/**
+ * Check whether the input device type is one
+ * where addresses are used to distinguish between one connected device and another
+ *
+ * @param[in] device to consider
+ *
+ * @return true if the device needs distinguish on address, false otherwise..
+ */
+static inline bool apm_audio_in_device_distinguishes_on_address(audio_devices_t device)
+{
+    return device == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
+           device == AUDIO_DEVICE_IN_BUS;
+}
+
+/**
  * Check whether the device type is one
  * where addresses are used to distinguish between one connected device and another
  *
@@ -80,10 +102,8 @@
  */
 static inline bool device_distinguishes_on_address(audio_devices_t device)
 {
-    return (((device & AUDIO_DEVICE_BIT_IN) != 0) &&
-            ((~AUDIO_DEVICE_BIT_IN & device & APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL) != 0)) ||
-           (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
-            ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
+    return apm_audio_in_device_distinguishes_on_address(device) ||
+           apm_audio_out_device_distinguishes_on_address(device);
 }
 
 /**
@@ -95,10 +115,7 @@
  */
 static inline bool device_has_encoding_capability(audio_devices_t device)
 {
-    if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        return true;
-    }
-    return false;
+    return audio_is_a2dp_out_device(device);
 }
 
 /**
@@ -184,3 +201,43 @@
 {
     return hasStream(streams, AUDIO_STREAM_VOICE_CALL);
 }
+
+/**
+ * @brief extract one device relevant from multiple device selection
+ * @param deviceTypes collection of audio device type
+ * @return the device type that is selected
+ */
+static inline audio_devices_t apm_extract_one_audio_device(
+        const android::DeviceTypeSet& deviceTypes) {
+    if (deviceTypes.empty()) {
+        return AUDIO_DEVICE_NONE;
+    } else if (deviceTypes.size() == 1) {
+        return *(deviceTypes.begin());
+    } else {
+        // Multiple device selection is either:
+        //  - speaker + one other device: give priority to speaker in this case.
+        //  - one A2DP device + another device: happens with duplicated output. In this case
+        // retain the device on the A2DP output as the other must not correspond to an active
+        // selection if not the speaker.
+        //  - HDMI-CEC system audio mode only output: give priority to available item in order.
+        if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
+            return AUDIO_DEVICE_OUT_SPEAKER;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
+            return AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
+            return AUDIO_DEVICE_OUT_HDMI_ARC;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
+            return AUDIO_DEVICE_OUT_AUX_LINE;
+        } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
+            return AUDIO_DEVICE_OUT_SPDIF;
+        } else {
+            std::vector<audio_devices_t> a2dpDevices = android::Intersection(
+                    deviceTypes, android::getAudioDeviceOutAllA2dpSet());
+            if (a2dpDevices.empty() || a2dpDevices.size() > 1) {
+                ALOGW("%s invalid device combination: %s",
+                      __func__, android::dumpDeviceTypes(deviceTypes).c_str());
+            }
+            return a2dpDevices.empty() ? AUDIO_DEVICE_NONE : a2dpDevices[0];
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index f02f3cf..fad3c5b 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -3,24 +3,24 @@
 
     srcs: [
         "src/AudioCollections.cpp",
-        "src/AudioGain.cpp",
         "src/AudioInputDescriptor.cpp",
         "src/AudioOutputDescriptor.cpp",
         "src/AudioPatch.cpp",
         "src/AudioPolicyMix.cpp",
-        "src/AudioPort.cpp",
-        "src/AudioProfile.cpp",
+        "src/AudioProfileVectorHelper.cpp",
         "src/AudioRoute.cpp",
         "src/ClientDescriptor.cpp",
         "src/DeviceDescriptor.cpp",
         "src/EffectDescriptor.cpp",
         "src/HwModule.cpp",
         "src/IOProfile.cpp",
+        "src/PolicyAudioPort.cpp",
         "src/Serializer.cpp",
         "src/SoundTriggerSession.cpp",
         "src/TypeConverter.cpp",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "libcutils",
         "libhidlbase",
         "liblog",
@@ -28,7 +28,10 @@
         "libutils",
         "libxml2",
     ],
-    export_shared_lib_headers: ["libmedia"],
+    export_shared_lib_headers: [
+        "libaudiofoundation",
+        "libmedia",
+    ],
     static_libs: [
         "libaudioutils",
     ],
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
index a948ea9..b692592 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -25,20 +25,15 @@
 
 namespace android {
 
-class AudioPort;
+class PolicyAudioPort;
 class AudioRoute;
 
-class AudioPortVector : public Vector<sp<AudioPort> >
-{
-public:
-    sp<AudioPort> findByTagName(const String8 &tagName) const;
-};
+using PolicyAudioPortVector = Vector<sp<PolicyAudioPort>>;
+using AudioRouteVector = Vector<sp<AudioRoute>>;
 
+sp<PolicyAudioPort> findByTagName(const PolicyAudioPortVector& policyAudioPortVector,
+                                  const std::string &tagName);
 
-class AudioRouteVector : public Vector<sp<AudioRoute> >
-{
-public:
-    void dump(String8 *dst, int spaces) const;
-};
+void dumpAudioRouteVector(const AudioRouteVector& audioRouteVector, String8 *dst, int spaces);
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 37f9d14..c67a006 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -21,11 +21,11 @@
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
 #include "AudioIODescriptorInterface.h"
-#include "AudioPort.h"
 #include "ClientDescriptor.h"
 #include "DeviceDescriptor.h"
 #include "EffectDescriptor.h"
 #include "IOProfile.h"
+#include "PolicyAudioPort.h"
 
 namespace android {
 
@@ -34,13 +34,17 @@
 
 // descriptor for audio inputs. Used to maintain current configuration of each opened audio input
 // and keep track of the usage of this input.
-class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
-    , public ClientMapHandler<RecordClientDescriptor>
+class AudioInputDescriptor: public AudioPortConfig,
+        public PolicyAudioPortConfig,
+        public AudioIODescriptorInterface,
+        public ClientMapHandler<RecordClientDescriptor>
 {
 public:
-    explicit AudioInputDescriptor(const sp<IOProfile>& profile,
-                                  AudioPolicyClientInterface *clientInterface);
-    audio_port_handle_t getId() const;
+    AudioInputDescriptor(const sp<IOProfile>& profile,
+                         AudioPolicyClientInterface *clientInterface);
+
+    virtual ~AudioInputDescriptor() = default;
+
     audio_module_handle_t getModuleHandle() const;
 
     audio_devices_t getDeviceType() const { return (mDevice != nullptr) ?
@@ -56,9 +60,18 @@
     wp<AudioPolicyMix>  mPolicyMix;                   // non NULL when used by a dynamic policy
     const sp<IOProfile> mProfile;                     // I/O profile this output derives from
 
+    // PolicyAudioPortConfig
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const {
+        return mProfile;
+    }
+
+    // AudioPortConfig
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
             const struct audio_port_config *srcConfig = NULL) const;
     virtual sp<AudioPort> getAudioPort() const { return mProfile; }
+
     void toAudioPort(struct audio_port *port) const;
     void setPreemptedSessions(const SortedVector<audio_session_t>& sessions);
     SortedVector<audio_session_t> getPreemptedSessions() const;
@@ -97,7 +110,7 @@
     RecordClientVector clientsList(bool activeOnly = false,
         audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
 
-    void setAppState(uid_t uid, app_state_t state);
+    void setAppState(audio_port_handle_t portId, app_state_t state);
 
     // implementation of ClientMapHandler<RecordClientDescriptor>
     void addClient(const sp<RecordClientDescriptor> &client) override;
@@ -111,7 +124,6 @@
     void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
 
     audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    audio_port_handle_t  mId = AUDIO_PORT_HANDLE_NONE;
     sp<DeviceDescriptor> mDevice = nullptr; /**< current device this input is routed to */
 
     // Because a preemptible capture session can preempt another one, we end up in an endless loop
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index cd54085..41f7dfc 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -21,14 +21,15 @@
 
 #include <sys/types.h>
 
+#include <media/AudioContainers.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/KeyedVector.h>
 #include <system/audio.h>
 #include "AudioIODescriptorInterface.h"
-#include "AudioPort.h"
 #include "ClientDescriptor.h"
 #include "DeviceDescriptor.h"
+#include "PolicyAudioPort.h"
 #include <vector>
 
 namespace android {
@@ -138,27 +139,28 @@
 
 // descriptor for audio outputs. Used to maintain current configuration of each opened audio output
 // and keep track of the usage of this output by each audio stream type.
-class AudioOutputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
-    , public ClientMapHandler<TrackClientDescriptor>
+class AudioOutputDescriptor: public AudioPortConfig,
+        public PolicyAudioPortConfig,
+        public AudioIODescriptorInterface,
+        public ClientMapHandler<TrackClientDescriptor>
 {
 public:
-    AudioOutputDescriptor(const sp<AudioPort>& port,
+    AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
                           AudioPolicyClientInterface *clientInterface);
     virtual ~AudioOutputDescriptor() {}
 
     void dump(String8 *dst) const override;
     void        log(const char* indent);
 
-    audio_port_handle_t getId() const;
     virtual DeviceVector devices() const { return mDevices; }
     bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
     virtual DeviceVector supportedDevices() const  { return mDevices; }
     virtual bool isDuplicated() const { return false; }
     virtual uint32_t latency() { return 0; }
-    virtual bool isFixedVolume(audio_devices_t device);
+    virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
     virtual bool setVolume(float volumeDb,
                            VolumeSource volumeSource, const StreamTypeVector &streams,
-                           audio_devices_t device,
+                           const DeviceTypeSet& deviceTypes,
                            uint32_t delayMs,
                            bool force);
 
@@ -245,9 +247,19 @@
         mRoutingActivities[ps].setMutedByDevice(isMuted);
     }
 
+    // PolicyAudioPortConfig
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const
+    {
+        return mPolicyAudioPort;
+    }
+
+    // AudioPortConfig
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
                            const struct audio_port_config *srcConfig = NULL) const;
-    virtual sp<AudioPort> getAudioPort() const { return mPort; }
+    virtual sp<AudioPort> getAudioPort() const { return mPolicyAudioPort->asAudioPort(); }
+
     virtual void toAudioPort(struct audio_port *port) const;
 
     audio_module_handle_t getModuleHandle() const;
@@ -289,11 +301,10 @@
     wp<AudioPolicyMix> mPolicyMix;  // non NULL when used by a dynamic policy
 
 protected:
-    const sp<AudioPort> mPort;
+    const sp<PolicyAudioPort> mPolicyAudioPort;
     AudioPolicyClientInterface * const mClientInterface;
     uint32_t mGlobalActiveCount = 0;  // non-client-specific active count
     audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
-    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
 
     // The ActiveClients shows the clients that contribute to the @VolumeSource counts
     // and may include upstream clients from a duplicating thread.
@@ -319,10 +330,10 @@
     void setDevices(const DeviceVector &devices) { mDevices = devices; }
     bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc);
     virtual DeviceVector supportedDevices() const;
-    virtual bool deviceSupportsEncodedFormats(audio_devices_t device);
+    virtual bool devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes);
     virtual uint32_t latency();
     virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
-    virtual bool isFixedVolume(audio_devices_t device);
+    virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes);
     sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; }
     sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; }
     void setClientActive(const sp<TrackClientDescriptor>& client, bool active) override;
@@ -334,7 +345,7 @@
     }
     virtual bool setVolume(float volumeDb,
                            VolumeSource volumeSource, const StreamTypeVector &streams,
-                           audio_devices_t device,
+                           const DeviceTypeSet& device,
                            uint32_t delayMs,
                            bool force);
 
@@ -408,7 +419,7 @@
 
     virtual bool setVolume(float volumeDb,
                            VolumeSource volumeSource, const StreamTypeVector &streams,
-                           audio_devices_t device,
+                           const DeviceTypeSet& deviceTypes,
                            uint32_t delayMs,
                            bool force);
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 0776a8d..e59386f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -19,17 +19,17 @@
 #include <unordered_map>
 #include <unordered_set>
 
-#include <AudioGain.h>
-#include <AudioPort.h>
 #include <AudioPatch.h>
 #include <DeviceDescriptor.h>
 #include <IOProfile.h>
 #include <HwModule.h>
+#include <PolicyAudioPort.h>
 #include <AudioInputDescriptor.h>
 #include <AudioOutputDescriptor.h>
 #include <AudioPolicyMix.h>
 #include <EffectDescriptor.h>
 #include <SoundTriggerSession.h>
+#include <media/AudioProfile.h>
 
 namespace android {
 
@@ -45,7 +45,8 @@
           mAvailableOutputDevices(availableOutputDevices),
           mAvailableInputDevices(availableInputDevices),
           mDefaultOutputDevice(defaultOutputDevice),
-          mIsSpeakerDrcEnabled(false)
+          mIsSpeakerDrcEnabled(false),
+          mIsCallScreenModeSupported(false)
     {}
 
     const std::string& getSource() const {
@@ -95,6 +96,14 @@
         mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
     }
 
+    bool isCallScreenModeSupported() const { return mIsCallScreenModeSupported; }
+
+    void setCallScreenModeSupported(bool isCallScreenModeSupported)
+    {
+        mIsCallScreenModeSupported = isCallScreenModeSupported;
+    }
+
+
     const HwModuleCollection getHwModules() const { return mHwModules; }
 
     const DeviceVector &getAvailableInputDevices() const
@@ -119,9 +128,9 @@
         mSource = "AudioPolicyConfig::setDefault";
         mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
         mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
-        mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic());
+        mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
         sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
-        defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic());
+        defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
         sp<AudioProfile> micProfile = new AudioProfile(
                 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
         defaultInputDevice->addAudioProfile(micProfile);
@@ -133,14 +142,14 @@
         mDefaultOutputDevice->attach(module);
         defaultInputDevice->attach(module);
 
-        sp<OutputProfile> outProfile = new OutputProfile(String8("primary"));
+        sp<OutputProfile> outProfile = new OutputProfile("primary");
         outProfile->addAudioProfile(
                 new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
         outProfile->addSupportedDevice(mDefaultOutputDevice);
         outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
         module->addOutputProfile(outProfile);
 
-        sp<InputProfile> inProfile = new InputProfile(String8("primary"));
+        sp<InputProfile> inProfile = new InputProfile("primary");
         inProfile->addAudioProfile(micProfile);
         inProfile->addSupportedDevice(defaultInputDevice);
         module->addInputProfile(inProfile);
@@ -189,6 +198,7 @@
     // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
     // Note: remove also speaker_drc_enabled from global configuration of XML config file.
     bool mIsSpeakerDrcEnabled;
+    bool mIsCallScreenModeSupported;
     SurroundFormats mSurroundFormats;
 };
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 094f506..fc79ab1 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -18,6 +18,7 @@
 
 #include "DeviceDescriptor.h"
 #include <utils/RefBase.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <media/AudioPolicy.h>
 #include <utils/Vector.h>
 #include <system/audio.h>
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
deleted file mode 100644
index d906f11..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "AudioCollections.h"
-#include "AudioProfile.h"
-#include "AudioGain.h"
-#include "HandleGenerator.h"
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
-#include <system/audio.h>
-#include <cutils/config_utils.h>
-
-namespace android {
-
-class HwModule;
-class AudioRoute;
-
-class AudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
-{
-public:
-    AudioPort(const String8& name, audio_port_type_t type,  audio_port_role_t role) :
-        mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
-
-    virtual ~AudioPort() {}
-
-    void setName(const String8 &name) { mName = name; }
-    const String8 &getName() const { return mName; }
-
-    audio_port_type_t getType() const { return mType; }
-    audio_port_role_t getRole() const { return mRole; }
-
-    virtual const String8 getTagName() const = 0;
-
-    void setGains(const AudioGains &gains) { mGains = gains; }
-    const AudioGains &getGains() const { return mGains; }
-
-    virtual void setFlags(uint32_t flags)
-    {
-        //force direct flag if offload flag is set: offloading implies a direct output stream
-        // and all common behaviors are driven by checking only the direct flag
-        // this should normally be set appropriately in the policy configuration file
-        if (mRole == AUDIO_PORT_ROLE_SOURCE && (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
-            flags |= AUDIO_OUTPUT_FLAG_DIRECT;
-        }
-        mFlags = flags;
-    }
-    uint32_t getFlags() const { return mFlags; }
-
-    virtual void attach(const sp<HwModule>& module);
-    virtual void detach();
-    bool isAttached() { return mModule != 0; }
-
-    // Audio port IDs are in a different namespace than AudioFlinger unique IDs
-    static audio_port_handle_t getNextUniqueId();
-
-    virtual void toAudioPort(struct audio_port *port) const;
-
-    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
-
-    void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
-
-    void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
-    AudioProfileVector &getAudioProfiles() { return mProfiles; }
-
-    bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
-
-    bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
-
-    // searches for an exact match
-    virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
-
-    // searches for a compatible match, currently implemented for input
-    // parameters are input|output, returned value is the best match.
-    status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
-                                         audio_channel_mask_t &channelMask,
-                                         audio_format_t &format) const
-    {
-        return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
-    }
-
-    void clearAudioProfiles() { return mProfiles.clearProfiles(); }
-
-    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
-
-    void pickAudioProfile(uint32_t &samplingRate,
-                          audio_channel_mask_t &channelMask,
-                          audio_format_t &format) const;
-
-    static const audio_format_t sPcmFormatCompareTable[];
-
-    static int compareFormats(audio_format_t format1, audio_format_t format2);
-
-    // Used to select an audio HAL output stream with a sample format providing the
-    // less degradation for a given AudioTrack sample format.
-    static bool isBetterFormatMatch(audio_format_t newFormat,
-                                        audio_format_t currentFormat,
-                                        audio_format_t targetFormat);
-    static uint32_t formatDistance(audio_format_t format1,
-                                   audio_format_t format2);
-    static const uint32_t kFormatDistanceMax = 4;
-
-    audio_module_handle_t getModuleHandle() const;
-    uint32_t getModuleVersionMajor() const;
-    const char *getModuleName() const;
-    sp<HwModule> getModule() const { return mModule; }
-
-    bool useInputChannelMask() const
-    {
-        return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
-                ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
-    }
-
-    inline bool isDirectOutput() const
-    {
-        return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
-                (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
-    }
-
-    void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
-    const AudioRouteVector &getRoutes() const { return mRoutes; }
-
-    void dump(String8 *dst, int spaces, bool verbose = true) const;
-
-    void log(const char* indent) const;
-
-    AudioGains mGains; // gain controllers
-
-private:
-    void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
-    void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
-
-    sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
-    String8  mName;
-    audio_port_type_t mType;
-    audio_port_role_t mRole;
-    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
-    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
-    AudioRouteVector mRoutes; // Routes involving this port
-};
-
-class AudioPortConfig : public virtual RefBase
-{
-public:
-    status_t applyAudioPortConfig(const struct audio_port_config *config,
-                                  struct audio_port_config *backupConfig = NULL);
-    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
-                                   const struct audio_port_config *srcConfig = NULL) const = 0;
-    virtual sp<AudioPort> getAudioPort() const = 0;
-    virtual bool hasSameHwModuleAs(const sp<AudioPortConfig>& other) const {
-        return (other != 0) && (other->getAudioPort() != 0) && (getAudioPort() != 0) &&
-                (other->getAudioPort()->getModuleHandle() == getAudioPort()->getModuleHandle());
-    }
-    bool hasGainController(bool canUseForVolume = false) const;
-
-    unsigned int mSamplingRate = 0u;
-    audio_format_t mFormat = AUDIO_FORMAT_INVALID;
-    audio_channel_mask_t mChannelMask = AUDIO_CHANNEL_NONE;
-    struct audio_gain_config mGain = { .index = -1 };
-    union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
deleted file mode 100644
index b588d57..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <vector>
-
-#include <system/audio.h>
-#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <utils/String8.h>
-
-#include "policy.h"
-
-namespace android {
-
-typedef SortedVector<uint32_t> SampleRateVector;
-typedef Vector<audio_format_t> FormatVector;
-
-template <typename T>
-bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
-{
-    if (left.size() != right.size()) {
-        return false;
-    }
-    for (size_t index = 0; index < right.size(); index++) {
-        if (left[index] != right[index]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-template <typename T>
-bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
-{
-    return !(left == right);
-}
-
-class ChannelsVector : public SortedVector<audio_channel_mask_t>
-{
-public:
-    ChannelsVector() = default;
-    ChannelsVector(const ChannelsVector&) = default;
-    ChannelsVector(const SortedVector<audio_channel_mask_t>& sv) :
-            SortedVector<audio_channel_mask_t>(sv) {}
-    ChannelsVector& operator=(const ChannelsVector&) = default;
-
-    // Applies audio_channel_mask_out_to_in to all elements and returns the result.
-    ChannelsVector asInMask() const;
-    // Applies audio_channel_mask_in_to_out to all elements and returns the result.
-    ChannelsVector asOutMask() const;
-};
-
-class AudioProfile : public virtual RefBase
-{
-public:
-    static sp<AudioProfile> createFullDynamic();
-
-    AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
-    AudioProfile(audio_format_t format,
-                 const ChannelsVector &channelMasks,
-                 const SampleRateVector &samplingRateCollection);
-
-    audio_format_t getFormat() const { return mFormat; }
-    const ChannelsVector &getChannels() const { return mChannelMasks; }
-    const SampleRateVector &getSampleRates() const { return mSamplingRates; }
-    void setChannels(const ChannelsVector &channelMasks);
-    void setSampleRates(const SampleRateVector &sampleRates);
-
-    void clear();
-    bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
-    bool supportsChannels(audio_channel_mask_t channels) const
-    {
-        return mChannelMasks.indexOf(channels) >= 0;
-    }
-    bool supportsRate(uint32_t rate) const { return mSamplingRates.indexOf(rate) >= 0; }
-
-    status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
-    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-                                        audio_channel_mask_t &updatedChannelMask,
-                                        audio_port_type_t portType,
-                                        audio_port_role_t portRole) const;
-    status_t checkCompatibleSamplingRate(uint32_t samplingRate,
-                                         uint32_t &updatedSamplingRate) const;
-
-    bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
-    bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
-    bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }
-
-    void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
-    bool isDynamicChannels() const { return mIsDynamicChannels; }
-
-    void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
-    bool isDynamicRate() const { return mIsDynamicRate; }
-
-    void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
-    bool isDynamicFormat() const { return mIsDynamicFormat; }
-
-    bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
-
-    void dump(String8 *dst, int spaces) const;
-
-private:
-    String8  mName;
-    audio_format_t mFormat;
-    ChannelsVector mChannelMasks;
-    SampleRateVector mSamplingRates;
-
-    bool mIsDynamicFormat = false;
-    bool mIsDynamicChannels = false;
-    bool mIsDynamicRate = false;
-};
-
-
-class AudioProfileVector : public Vector<sp<AudioProfile> >
-{
-public:
-    ssize_t add(const sp<AudioProfile> &profile);
-    // This API is intended to be used by the policy manager once retrieving capabilities
-    // for a profile with dynamic format, rate and channels attributes
-    ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd);
-
-    status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
-                               audio_format_t format) const;
-    status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
-                                    audio_format_t &format,
-                                    audio_port_type_t portType,
-                                    audio_port_role_t portRole) const;
-    void clearProfiles();
-    // Assuming that this profile vector contains input profiles,
-    // find the best matching config from 'outputProfiles', according to
-    // the given preferences for audio formats and channel masks.
-    // Note: std::vectors are used because specialized containers for formats
-    //       and channels can be sorted and use their own ordering.
-    status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
-            const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
-            const std::vector<audio_channel_mask_t>& preferredOutputChannels,
-            bool preferHigherSamplingRates,
-            audio_config_base *bestOutputConfig) const;
-
-    sp<AudioProfile> getFirstValidProfile() const;
-    sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
-    bool hasValidProfile() const { return getFirstValidProfile() != 0; }
-
-    FormatVector getSupportedFormats() const;
-    bool hasDynamicChannelsFor(audio_format_t format) const;
-    bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
-    bool hasDynamicProfile() const;
-    bool hasDynamicRateFor(audio_format_t format) const;
-
-    // One audio profile will be added for each format supported by Audio HAL
-    void setFormats(const FormatVector &formats);
-
-    void dump(String8 *dst, int spaces) const;
-
-private:
-    sp<AudioProfile> getProfileFor(audio_format_t format) const;
-    void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format);
-    void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format);
-
-    static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
-};
-
-bool operator == (const AudioProfile &left, const AudioProfile &right);
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
new file mode 100644
index 0000000..f84bda7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfileVectorHelper.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <media/AudioProfile.h>
+#include <system/audio.h>
+
+namespace android {
+
+void sortAudioProfiles(AudioProfileVector &audioProfileVector);
+
+ssize_t addAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                               const sp<AudioProfile> &profile);
+
+// One audio profile will be added for each format supported by Audio HAL
+void addProfilesForFormats(AudioProfileVector &audioProfileVector,
+                           const FormatVector &formatVector);
+
+// This API is intended to be used by the policy manager once retrieving capabilities
+// for a profile with dynamic format, rate and channels attributes
+void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                                   const sp<AudioProfile> &profileToAdd);
+
+void appendAudioProfiles(AudioProfileVector &audioProfileVector,
+                         const AudioProfileVector &audioProfileVectorToAppend);
+
+status_t checkExactProfile(const AudioProfileVector &audioProfileVector,
+                           const uint32_t samplingRate,
+                           audio_channel_mask_t channelMask,
+                           audio_format_t format);
+
+status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
+                                uint32_t &samplingRate,
+                                audio_channel_mask_t &channelMask,
+                                audio_format_t &format,
+                                audio_port_type_t portType,
+                                audio_port_role_t portRole);
+
+// Assuming that this profile vector contains input profiles,
+// find the best matching config from 'outputProfiles', according to
+// the given preferences for audio formats and channel masks.
+// Note: std::vectors are used because specialized containers for formats
+//       and channels can be sorted and use their own ordering.
+status_t findBestMatchingOutputConfig(
+        const AudioProfileVector &audioProfileVector,
+        const AudioProfileVector &outputProfileVector,
+        const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
+        const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
+        bool preferHigherSamplingRates,
+        audio_config_base &bestOutputConfig);
+
+
+} // namespace android
\ No newline at end of file
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
index 0357ff4..a7def3e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -25,7 +25,7 @@
 namespace android
 {
 
-class AudioPort;
+class PolicyAudioPort;
 class DeviceDescriptor;
 
 typedef enum {
@@ -38,11 +38,11 @@
 public:
     explicit AudioRoute(audio_route_type_t type) : mType(type) {}
 
-    void setSources(const AudioPortVector &sources) { mSources = sources; }
-    const AudioPortVector &getSources() const { return mSources; }
+    void setSources(const PolicyAudioPortVector &sources) { mSources = sources; }
+    const PolicyAudioPortVector &getSources() const { return mSources; }
 
-    void setSink(const sp<AudioPort> &sink) { mSink = sink; }
-    const sp<AudioPort> &getSink() const { return mSink; }
+    void setSink(const sp<PolicyAudioPort> &sink) { mSink = sink; }
+    const sp<PolicyAudioPort> &getSink() const { return mSink; }
 
     audio_route_type_t getType() const { return mType; }
 
@@ -57,13 +57,14 @@
      * @return true if the audio route supports the connection between the sink and the source,
      * false otherwise
      */
-    bool supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const;
+    bool supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                       const sp<PolicyAudioPort> &dstPort) const;
 
     void dump(String8 *dst, int spaces) const;
 
 private:
-    AudioPortVector mSources;
-    sp<AudioPort> mSink;
+    PolicyAudioPortVector mSources;
+    sp<PolicyAudioPort> mSink;
     audio_route_type_t mType;
 
 };
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 33e506f..a6562d7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -16,7 +16,9 @@
 
 #pragma once
 
-#include "AudioPort.h"
+#include "PolicyAudioPort.h"
+#include <media/AudioContainers.h>
+#include <media/DeviceDescriptorBase.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/SortedVector.h>
@@ -26,21 +28,26 @@
 
 namespace android {
 
-class DeviceDescriptor : public AudioPort, public AudioPortConfig
+class DeviceDescriptor : public DeviceDescriptorBase,
+                         public PolicyAudioPort, public PolicyAudioPortConfig
 {
 public:
      // Note that empty name refers by convention to a generic device.
-    explicit DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
-    DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
-            const String8 &tagName = String8(""));
+    explicit DeviceDescriptor(audio_devices_t type);
+    DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+            const FormatVector &encodedFormats = FormatVector{});
+    DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+            const std::string &address, const FormatVector &encodedFormats = FormatVector{});
+    DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr, const std::string &tagName = "",
+            const FormatVector &encodedFormats = FormatVector{});
 
     virtual ~DeviceDescriptor() {}
 
-    virtual const String8 getTagName() const { return mTagName; }
+    virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+        addAudioProfileAndSort(mProfiles, profile);
+    }
 
-    audio_devices_t type() const { return mDeviceType; }
-    String8 address() const { return mAddress; }
-    void setAddress(const String8 &address) { mAddress = address; }
+    virtual const std::string getTagName() const { return mTagName; }
 
     const FormatVector& encodedFormats() const { return mEncodedFormats; }
 
@@ -56,36 +63,42 @@
 
     bool supportsFormat(audio_format_t format);
 
+    // PolicyAudioPortConfig
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const {
+        return static_cast<PolicyAudioPort*>(const_cast<DeviceDescriptor*>(this));
+    }
+
     // AudioPortConfig
-    virtual sp<AudioPort> getAudioPort() const { return (AudioPort*) this; }
+    virtual status_t applyAudioPortConfig(const struct audio_port_config *config,
+                                          struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
             const struct audio_port_config *srcConfig = NULL) const;
 
-    // AudioPort
+    // PolicyAudioPort
+    virtual sp<AudioPort> asAudioPort() const {
+        return static_cast<AudioPort*>(const_cast<DeviceDescriptor*>(this));
+    }
     virtual void attach(const sp<HwModule>& module);
     virtual void detach();
 
+    // AudioPort
     virtual void toAudioPort(struct audio_port *port) const;
-    virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
 
-    audio_port_handle_t getId() const;
+    void importAudioPortAndPickAudioProfile(const sp<PolicyAudioPort>& policyPort,
+                                            bool force = false);
+
     void dump(String8 *dst, int spaces, int index, bool verbose = true) const;
-    void log() const;
-    std::string toString() const;
 
 private:
-    String8 mAddress{""};
-    String8 mTagName; // Unique human readable identifier for a device port found in conf file.
-    audio_devices_t     mDeviceType;
+    std::string mTagName; // Unique human readable identifier for a device port found in conf file.
     FormatVector        mEncodedFormats;
-    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
     audio_format_t      mCurrentEncodedFormat;
 };
 
 class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
 {
 public:
-    DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
+    DeviceVector() : SortedVector() {}
     explicit DeviceVector(const sp<DeviceDescriptor>& item) : DeviceVector()
     {
         add(item);
@@ -97,13 +110,16 @@
     void remove(const DeviceVector &devices);
     ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
 
-    audio_devices_t types() const { return mDeviceTypes; }
+    DeviceTypeSet types() const { return mDeviceTypes; }
 
     // If 'address' is empty and 'codec' is AUDIO_FORMAT_DEFAULT, a device with a non-empty
     // address may be returned if there is no device with the specified 'type' and empty address.
     sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8 &address,
                                    audio_format_t codec) const;
-    DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
+    DeviceVector getDevicesFromTypes(const DeviceTypeSet& types) const;
+    DeviceVector getDevicesFromType(audio_devices_t type) const {
+        return getDevicesFromTypes({type});
+    }
 
     /**
      * @brief getDeviceFromId
@@ -112,9 +128,35 @@
      * equal to AUDIO_PORT_HANDLE_NONE, it also returns a nullptr.
      */
     sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
-    sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
+    sp<DeviceDescriptor> getDeviceFromTagName(const std::string &tagName) const;
     DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
-    audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
+
+    DeviceVector getFirstDevicesFromTypes(std::vector<audio_devices_t> orderedTypes) const;
+    sp<DeviceDescriptor> getFirstExistingDevice(std::vector<audio_devices_t> orderedTypes) const;
+
+    // Return device descriptor that is used to open an input/output stream.
+    // Null pointer will be returned if
+    //     1) this collection is empty
+    //     2) the device descriptors are not the same category(input or output)
+    //     3) there are more than one device type for input case
+    //     4) the combination of all devices is invalid for selection
+    sp<DeviceDescriptor> getDeviceForOpening() const;
+
+    // If there are devices with the given type and the devices to add is not empty,
+    // remove all the devices with the given type and add all the devices to add.
+    void replaceDevicesByType(audio_devices_t typeToRemove, const DeviceVector &devicesToAdd);
+
+    bool containsDeviceAmongTypes(const DeviceTypeSet& deviceTypes) const {
+        return !Intersection(mDeviceTypes, deviceTypes).empty();
+    }
+
+    bool containsDeviceWithType(audio_devices_t deviceType) const {
+        return containsDeviceAmongTypes({deviceType});
+    }
+
+    bool onlyContainsDevicesWithType(audio_devices_t deviceType) const {
+        return isSingleDeviceType(mDeviceTypes, deviceType);
+    }
 
     bool contains(const sp<DeviceDescriptor>& item) const { return indexOf(item) >= 0; }
 
@@ -196,7 +238,7 @@
     {
         for (const auto &device : *this) {
             if (device->address() != "") {
-                return device->address();
+                return String8(device->address().c_str());
             }
         }
         return String8("");
@@ -208,7 +250,7 @@
 
 private:
     void refreshTypes();
-    audio_devices_t mDeviceTypes;
+    DeviceTypeSet mDeviceTypes;
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index eb34da4..23f0c9a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -82,19 +82,19 @@
     status_t addInputProfile(const sp<IOProfile> &profile);
     status_t addProfile(const sp<IOProfile> &profile);
 
-    status_t addOutputProfile(const String8& name, const audio_config_t *config,
+    status_t addOutputProfile(const std::string& name, const audio_config_t *config,
             audio_devices_t device, const String8& address);
-    status_t removeOutputProfile(const String8& name);
-    status_t addInputProfile(const String8& name, const audio_config_t *config,
+    status_t removeOutputProfile(const std::string& name);
+    status_t addInputProfile(const std::string& name, const audio_config_t *config,
             audio_devices_t device, const String8& address);
-    status_t removeInputProfile(const String8& name);
+    status_t removeInputProfile(const std::string& name);
 
     audio_module_handle_t getHandle() const { return mHandle; }
     void setHandle(audio_module_handle_t handle);
 
-    sp<AudioPort> findPortByTagName(const String8 &tagName) const
+    sp<PolicyAudioPort> findPortByTagName(const std::string &tagName) const
     {
-        return mPorts.findByTagName(tagName);
+        return findByTagName(mPorts, tagName);
     }
 
     /**
@@ -106,7 +106,8 @@
      * @return true if the HwModule supports the connection between the sink and the source,
      * false otherwise
      */
-    bool supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const;
+    bool supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                       const sp<PolicyAudioPort> &dstPort) const;
 
     // TODO remove from here (split serialization)
     void dump(String8 *dst) const;
@@ -122,7 +123,7 @@
     DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
     DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
     AudioRouteVector mRoutes;
-    AudioPortVector mPorts;
+    PolicyAudioPortVector mPorts;
 };
 
 class HwModuleCollection : public Vector<sp<HwModule> >
@@ -130,8 +131,8 @@
 public:
     sp<HwModule> getModuleFromName(const char *name) const;
 
-    sp<HwModule> getModuleForDeviceTypes(audio_devices_t device,
-                                         audio_format_t encodedFormat) const;
+    sp<HwModule> getModuleForDeviceType(audio_devices_t device,
+                                        audio_format_t encodedFormat) const;
 
     sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device,
                                     audio_format_t encodedFormat) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index e0b56d4..2044863 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -16,8 +16,10 @@
 
 #pragma once
 
-#include "AudioPort.h"
 #include "DeviceDescriptor.h"
+#include "PolicyAudioPort.h"
+#include "policy.h"
+#include <media/AudioContainers.h>
 #include <utils/String8.h>
 #include <system/audio.h>
 
@@ -30,18 +32,28 @@
 // It is used by the policy manager to determine if an output or input is suitable for
 // a given use case,  open/close it accordingly and connect/disconnect audio tracks
 // to/from it.
-class IOProfile : public AudioPort
+class IOProfile : public AudioPort, public PolicyAudioPort
 {
 public:
-    IOProfile(const String8 &name, audio_port_role_t role)
+    IOProfile(const std::string &name, audio_port_role_t role)
         : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
           maxOpenCount(1),
           curOpenCount(0),
           maxActiveCount(1),
           curActiveCount(0) {}
 
+    virtual ~IOProfile() = default;
+
     // For a Profile aka MixPort, tag name and name are equivalent.
-    virtual const String8 getTagName() const { return getName(); }
+    virtual const std::string getTagName() const { return getName(); }
+
+    virtual void addAudioProfile(const sp<AudioProfile> &profile) {
+        addAudioProfileAndSort(mProfiles, profile);
+    }
+
+    virtual sp<AudioPort> asAudioPort() const {
+        return static_cast<AudioPort*>(const_cast<IOProfile*>(this));
+    }
 
     // FIXME: this is needed because shared MMAP stream clients use the same audio session.
     // Once capture clients are tracked individually and not per session this can be removed
@@ -51,7 +63,7 @@
     // flags are parsed before maxActiveCount by the serializer.
     void setFlags(uint32_t flags) override
     {
-        AudioPort::setFlags(flags);
+        PolicyAudioPort::setFlags(flags);
         if (getRole() == AUDIO_PORT_ROLE_SINK && (flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
             maxActiveCount = 0;
         }
@@ -91,15 +103,12 @@
 
     bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
 
-    bool supportsDeviceTypes(audio_devices_t device) const
+    bool supportsDeviceTypes(const DeviceTypeSet& deviceTypes) const
     {
-        if (audio_is_output_devices(device)) {
-            if (deviceSupportsEncodedFormats(device)) {
-                return mSupportedDevices.types() & device;
-            }
-            return false;
-        }
-        return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
+        const bool areOutputDevices = Intersection(deviceTypes, getAudioDeviceInAllSet()).empty();
+        const bool devicesSupported = !mSupportedDevices.getDevicesFromTypes(deviceTypes).empty();
+        return devicesSupported &&
+               (!areOutputDevices || devicesSupportEncodedFormats(deviceTypes));
     }
 
     /**
@@ -114,18 +123,18 @@
     bool supportsDevice(const sp<DeviceDescriptor> &device, bool forceCheckOnAddress = false) const
     {
         if (!device_distinguishes_on_address(device->type()) && !forceCheckOnAddress) {
-            return supportsDeviceTypes(device->type());
+            return supportsDeviceTypes(DeviceTypeSet({device->type()}));
         }
         return mSupportedDevices.contains(device);
     }
 
-    bool deviceSupportsEncodedFormats(audio_devices_t device) const
+    bool devicesSupportEncodedFormats(DeviceTypeSet deviceTypes) const
     {
-        if (device == AUDIO_DEVICE_NONE) {
+        if (deviceTypes.empty()) {
             return true; // required for isOffloadSupported() check
         }
         DeviceVector deviceList =
-            mSupportedDevices.getDevicesFromTypeMask(device);
+            mSupportedDevices.getDevicesFromTypes(deviceTypes);
         if (!deviceList.empty()) {
             return deviceList.itemAt(0)->hasCurrentEncodedFormat();
         }
@@ -183,13 +192,13 @@
 class InputProfile : public IOProfile
 {
 public:
-    explicit InputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
+    explicit InputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
 };
 
 class OutputProfile : public IOProfile
 {
 public:
-    explicit OutputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
+    explicit OutputProfile(const std::string &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
 };
 
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
index d408446..fd8b81a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
@@ -16,8 +16,9 @@
 
 #pragma once
 
-#include <system/audio.h>
 #include <Volume.h>
+#include <media/AudioContainers.h>
+#include <system/audio.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <vector>
@@ -33,7 +34,7 @@
     virtual void addCurrentVolumeIndex(audio_devices_t device, int index) = 0;
     virtual bool canBeMuted() const = 0;
     virtual int getVolumeIndexMin() const = 0;
-    virtual int getVolumeIndex(audio_devices_t device) const = 0;
+    virtual int getVolumeIndex(const DeviceTypeSet& device) const = 0;
     virtual int getVolumeIndexMax() const = 0;
     virtual float volIndexToDb(device_category device, int indexInUi) const = 0;
     virtual bool hasVolumeIndexForDevice(audio_devices_t device) const = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
new file mode 100644
index 0000000..99df3c0
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "AudioCollections.h"
+#include "AudioProfileVectorHelper.h"
+#include "HandleGenerator.h"
+#include <media/AudioGain.h>
+#include <media/AudioPort.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class HwModule;
+class AudioRoute;
+
+class PolicyAudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
+{
+public:
+    PolicyAudioPort() : mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
+
+    virtual ~PolicyAudioPort() = default;
+
+    virtual const std::string getTagName() const = 0;
+
+    virtual sp<AudioPort> asAudioPort() const = 0;
+
+    virtual void setFlags(uint32_t flags)
+    {
+        //force direct flag if offload flag is set: offloading implies a direct output stream
+        // and all common behaviors are driven by checking only the direct flag
+        // this should normally be set appropriately in the policy configuration file
+        if (asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE &&
+                (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+            flags |= AUDIO_OUTPUT_FLAG_DIRECT;
+        }
+        mFlags = flags;
+    }
+    uint32_t getFlags() const { return mFlags; }
+
+    virtual void attach(const sp<HwModule>& module);
+    virtual void detach();
+    bool isAttached() { return mModule != 0; }
+
+    // Audio port IDs are in a different namespace than AudioFlinger unique IDs
+    static audio_port_handle_t getNextUniqueId();
+
+    // searches for an exact match
+    virtual status_t checkExactAudioProfile(const struct audio_port_config *config) const;
+
+    // searches for a compatible match, currently implemented for input
+    // parameters are input|output, returned value is the best match.
+    status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+                                         audio_channel_mask_t &channelMask,
+                                         audio_format_t &format) const
+    {
+        return checkCompatibleProfile(
+                asAudioPort()->getAudioProfiles(), samplingRate, channelMask, format,
+                asAudioPort()->getType(), asAudioPort()->getRole());
+    }
+
+    void pickAudioProfile(uint32_t &samplingRate,
+                          audio_channel_mask_t &channelMask,
+                          audio_format_t &format) const;
+
+    static const audio_format_t sPcmFormatCompareTable[];
+
+    static int compareFormats(audio_format_t format1, audio_format_t format2);
+
+    // Used to select an audio HAL output stream with a sample format providing the
+    // less degradation for a given AudioTrack sample format.
+    static bool isBetterFormatMatch(audio_format_t newFormat,
+                                    audio_format_t currentFormat,
+                                    audio_format_t targetFormat);
+    static uint32_t formatDistance(audio_format_t format1,
+                                   audio_format_t format2);
+    static const uint32_t kFormatDistanceMax = 4;
+
+    audio_module_handle_t getModuleHandle() const;
+    uint32_t getModuleVersionMajor() const;
+    const char *getModuleName() const;
+    sp<HwModule> getModule() const { return mModule; }
+
+    inline bool isDirectOutput() const
+    {
+        return (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) &&
+                (asAudioPort()->getRole() == AUDIO_PORT_ROLE_SOURCE) &&
+                (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+    }
+
+    void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+    const AudioRouteVector &getRoutes() const { return mRoutes; }
+
+private:
+    void pickChannelMask(audio_channel_mask_t &channelMask,
+                         const ChannelMaskSet &channelMasks) const;
+    void pickSamplingRate(uint32_t &rate, const SampleRateSet &samplingRates) const;
+
+    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
+    sp<HwModule> mModule;     // audio HW module exposing this I/O stream
+    AudioRouteVector mRoutes; // Routes involving this port
+};
+
+class PolicyAudioPortConfig : public virtual RefBase
+{
+public:
+    virtual ~PolicyAudioPortConfig() = default;
+
+    virtual sp<PolicyAudioPort> getPolicyAudioPort() const = 0;
+
+    status_t validationBeforeApplyConfig(const struct audio_port_config *config) const;
+
+    void applyPolicyAudioPortConfig(const struct audio_port_config *config) {
+        if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+            mFlags = config->flags;
+        }
+    }
+
+    void toPolicyAudioPortConfig(
+            struct audio_port_config *dstConfig,
+            const struct audio_port_config *srcConfig = NULL) const;
+
+
+    virtual bool hasSameHwModuleAs(const sp<PolicyAudioPortConfig>& other) const {
+        return (other.get() != nullptr) && (other->getPolicyAudioPort().get() != nullptr) &&
+                (getPolicyAudioPort().get() != nullptr) &&
+                (other->getPolicyAudioPort()->getModuleHandle() ==
+                        getPolicyAudioPort()->getModuleHandle());
+    }
+
+    union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
+};
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
index c90a582..cd10010 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -18,16 +18,16 @@
 //#define LOG_NDEBUG 0
 
 #include "AudioCollections.h"
-#include "AudioPort.h"
 #include "AudioRoute.h"
 #include "HwModule.h"
-#include "AudioGain.h"
+#include "PolicyAudioPort.h"
 
 namespace android {
 
-sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+sp<PolicyAudioPort> findByTagName(const PolicyAudioPortVector& policyAudioPortVector,
+                                  const std::string &tagName)
 {
-    for (const auto& port : *this) {
+    for (const auto& port : policyAudioPortVector) {
         if (port->getTagName() == tagName) {
             return port;
         }
@@ -35,15 +35,15 @@
     return nullptr;
 }
 
-void AudioRouteVector::dump(String8 *dst, int spaces) const
+void dumpAudioRouteVector(const AudioRouteVector& audioRouteVector, String8 *dst, int spaces)
 {
-    if (isEmpty()) {
+    if (audioRouteVector.isEmpty()) {
         return;
     }
-    dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", size());
-    for (size_t i = 0; i < size(); i++) {
+    dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", audioRouteVector.size());
+    for (size_t i = 0; i < audioRouteVector.size(); i++) {
         dst->appendFormat("%*s- Route %zu:\n", spaces, "", i + 1);
-        itemAt(i)->dump(dst, 4);
+        audioRouteVector.itemAt(i)->dump(dst, 4);
     }
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
deleted file mode 100644
index 2725870..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::AudioGain"
-//#define LOG_NDEBUG 0
-
-//#define VERY_VERBOSE_LOGGING
-#ifdef VERY_VERBOSE_LOGGING
-#define ALOGVV ALOGV
-#else
-#define ALOGVV(a...) do { } while(0)
-#endif
-
-#include "AudioGain.h"
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <math.h>
-
-namespace android {
-
-AudioGain::AudioGain(int index, bool useInChannelMask)
-{
-    mIndex = index;
-    mUseInChannelMask = useInChannelMask;
-    memset(&mGain, 0, sizeof(struct audio_gain));
-}
-
-void AudioGain::getDefaultConfig(struct audio_gain_config *config)
-{
-    config->index = mIndex;
-    config->mode = mGain.mode;
-    config->channel_mask = mGain.channel_mask;
-    if ((mGain.mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
-        config->values[0] = mGain.default_value;
-    } else {
-        uint32_t numValues;
-        if (mUseInChannelMask) {
-            numValues = audio_channel_count_from_in_mask(mGain.channel_mask);
-        } else {
-            numValues = audio_channel_count_from_out_mask(mGain.channel_mask);
-        }
-        for (size_t i = 0; i < numValues; i++) {
-            config->values[i] = mGain.default_value;
-        }
-    }
-    if ((mGain.mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
-        config->ramp_duration_ms = mGain.min_ramp_ms;
-    }
-}
-
-status_t AudioGain::checkConfig(const struct audio_gain_config *config)
-{
-    if ((config->mode & ~mGain.mode) != 0) {
-        return BAD_VALUE;
-    }
-    if ((config->mode & AUDIO_GAIN_MODE_JOINT) == AUDIO_GAIN_MODE_JOINT) {
-        if ((config->values[0] < mGain.min_value) ||
-                    (config->values[0] > mGain.max_value)) {
-            return BAD_VALUE;
-        }
-    } else {
-        if ((config->channel_mask & ~mGain.channel_mask) != 0) {
-            return BAD_VALUE;
-        }
-        uint32_t numValues;
-        if (mUseInChannelMask) {
-            numValues = audio_channel_count_from_in_mask(config->channel_mask);
-        } else {
-            numValues = audio_channel_count_from_out_mask(config->channel_mask);
-        }
-        for (size_t i = 0; i < numValues; i++) {
-            if ((config->values[i] < mGain.min_value) ||
-                    (config->values[i] > mGain.max_value)) {
-                return BAD_VALUE;
-            }
-        }
-    }
-    if ((config->mode & AUDIO_GAIN_MODE_RAMP) == AUDIO_GAIN_MODE_RAMP) {
-        if ((config->ramp_duration_ms < mGain.min_ramp_ms) ||
-                    (config->ramp_duration_ms > mGain.max_ramp_ms)) {
-            return BAD_VALUE;
-        }
-    }
-    return NO_ERROR;
-}
-
-void AudioGain::dump(String8 *dst, int spaces, int index) const
-{
-    dst->appendFormat("%*sGain %d:\n", spaces, "", index+1);
-    dst->appendFormat("%*s- mode: %08x\n", spaces, "", mGain.mode);
-    dst->appendFormat("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
-    dst->appendFormat("%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
-    dst->appendFormat("%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
-    dst->appendFormat("%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
-    dst->appendFormat("%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
-    dst->appendFormat("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
-    dst->appendFormat("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index a096e8f..b963121 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -22,7 +22,6 @@
 #include <policy.h>
 #include <AudioPolicyInterface.h>
 #include "AudioInputDescriptor.h"
-#include "AudioGain.h"
 #include "AudioPolicyMix.h"
 #include "HwModule.h"
 
@@ -35,8 +34,8 @@
 {
     if (profile != NULL) {
         profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-        if (profile->mGains.size() > 0) {
-            profile->mGains[0]->getDefaultConfig(&mGain);
+        if (profile->getGains().size() > 0) {
+            profile->getGains()[0]->getDefaultConfig(&mGain);
         }
     }
 }
@@ -49,16 +48,29 @@
     return mProfile->getModuleHandle();
 }
 
-audio_port_handle_t AudioInputDescriptor::getId() const
-{
-    return mId;
-}
-
 audio_source_t AudioInputDescriptor::source() const
 {
     return getHighestPriorityAttributes().source;
 }
 
+status_t AudioInputDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+                                                    audio_port_config *backupConfig)
+{
+    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+    status_t status = NO_ERROR;
+
+    toAudioPortConfig(&localBackupConfig);
+    if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+        AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+        applyPolicyAudioPortConfig(config);
+    }
+
+    if (backupConfig != NULL) {
+        *backupConfig = localBackupConfig;
+    }
+    return status;
+}
+
 void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
                                              const struct audio_port_config *srcConfig) const
 {
@@ -71,8 +83,8 @@
     }
 
     AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+    toPolicyAudioPortConfig(dstConfig, srcConfig);
 
-    dstConfig->id = mId;
     dstConfig->role = AUDIO_PORT_ROLE_SINK;
     dstConfig->type = AUDIO_PORT_TYPE_MIX;
     dstConfig->ext.mix.hw_module = getModuleHandle();
@@ -213,7 +225,7 @@
     mDevice = device;
 
     ALOGV("opening input for device %s profile %p name %s",
-          mDevice->toString().c_str(), mProfile.get(), mProfile->getName().string());
+          mDevice->toString().c_str(), mProfile.get(), mProfile->getName().c_str());
 
     audio_devices_t deviceType = mDevice->type();
 
@@ -221,7 +233,7 @@
                                                   input,
                                                   &lConfig,
                                                   &deviceType,
-                                                  mDevice->address(),
+                                                  String8(mDevice->address().c_str()),
                                                   source,
                                                   flags);
     LOG_ALWAYS_FATAL_IF(mDevice->type() != deviceType,
@@ -235,7 +247,7 @@
         mSamplingRate = lConfig.sample_rate;
         mChannelMask = lConfig.channel_mask;
         mFormat = lConfig.format;
-        mId = AudioPort::getNextUniqueId();
+        mId = PolicyAudioPort::getNextUniqueId();
         mIoHandle = *input;
         mProfile->curOpenCount++;
     }
@@ -451,13 +463,13 @@
     return enabledEffects;
 }
 
-void AudioInputDescriptor::setAppState(uid_t uid, app_state_t state)
+void AudioInputDescriptor::setAppState(audio_port_handle_t portId, app_state_t state)
 {
     RecordClientVector clients = clientsList(false /*activeOnly*/);
     RecordClientVector updatedClients;
 
     for (const auto& client : clients) {
-        if (uid == client->uid()) {
+        if (portId == client->portId()) {
             bool wasSilenced = client->isSilenced();
             client->setAppState(state);
             if (client->active() && wasSilenced != client->isSilenced()) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 8a60cf2..dd51658 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -21,27 +21,28 @@
 #include "AudioOutputDescriptor.h"
 #include "AudioPolicyMix.h"
 #include "IOProfile.h"
-#include "AudioGain.h"
 #include "Volume.h"
 #include "HwModule.h"
 #include "TypeConverter.h"
+#include <media/AudioGain.h>
 #include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
 
 // A device mask for all audio output devices that are considered "remote" when evaluating
 // active output devices in isStreamActiveRemotely()
-#define APM_AUDIO_OUT_DEVICE_REMOTE_ALL  AUDIO_DEVICE_OUT_REMOTE_SUBMIX
 
 namespace android {
 
-AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
+DeviceTypeSet APM_AUDIO_OUT_DEVICE_REMOTE_ALL = {AUDIO_DEVICE_OUT_REMOTE_SUBMIX};
+
+AudioOutputDescriptor::AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort,
                                              AudioPolicyClientInterface *clientInterface)
-    : mPort(port), mClientInterface(clientInterface)
+    : mPolicyAudioPort(policyAudioPort), mClientInterface(clientInterface)
 {
-    if (mPort.get() != nullptr) {
-        mPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-        if (mPort->mGains.size() > 0) {
-            mPort->mGains[0]->getDefaultConfig(&mGain);
+    if (mPolicyAudioPort.get() != nullptr) {
+        mPolicyAudioPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
+        if (mPolicyAudioPort->asAudioPort()->getGains().size() > 0) {
+            mPolicyAudioPort->asAudioPort()->getGains()[0]->getDefaultConfig(&mGain);
         }
     }
 }
@@ -55,7 +56,8 @@
 
 audio_module_handle_t AudioOutputDescriptor::getModuleHandle() const
 {
-    return mPort.get() != nullptr ? mPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
+    return mPolicyAudioPort.get() != nullptr ?
+            mPolicyAudioPort->getModuleHandle() : AUDIO_MODULE_HANDLE_NONE;
 }
 
 audio_patch_handle_t AudioOutputDescriptor::getPatchHandle() const
@@ -68,11 +70,6 @@
     mPatchHandle = handle;
 }
 
-audio_port_handle_t AudioOutputDescriptor::getId() const
-{
-    return mId;
-}
-
 bool AudioOutputDescriptor::sharesHwModuleWith(
         const sp<AudioOutputDescriptor>& outputDesc)
 {
@@ -144,7 +141,7 @@
     return false;
 }
 
-bool AudioOutputDescriptor::isFixedVolume(audio_devices_t device __unused)
+bool AudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes __unused)
 {
     return false;
 }
@@ -152,7 +149,7 @@
 bool AudioOutputDescriptor::setVolume(float volumeDb,
                                       VolumeSource volumeSource,
                                       const StreamTypeVector &/*streams*/,
-                                      audio_devices_t /*device*/,
+                                      const DeviceTypeSet& /*deviceTypes*/,
                                       uint32_t delayMs,
                                       bool force)
 {
@@ -167,9 +164,27 @@
     return false;
 }
 
-void AudioOutputDescriptor::toAudioPortConfig(
-                                                 struct audio_port_config *dstConfig,
-                                                 const struct audio_port_config *srcConfig) const
+status_t AudioOutputDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+                                                     audio_port_config *backupConfig)
+{
+    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+    status_t status = NO_ERROR;
+
+    toAudioPortConfig(&localBackupConfig);
+    if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+        AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+        applyPolicyAudioPortConfig(config);
+    }
+
+    if (backupConfig != NULL) {
+        *backupConfig = localBackupConfig;
+    }
+    return status;
+}
+
+
+void AudioOutputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+                                              const struct audio_port_config *srcConfig) const
 {
     dstConfig->config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE|AUDIO_PORT_CONFIG_CHANNEL_MASK|
                             AUDIO_PORT_CONFIG_FORMAT|AUDIO_PORT_CONFIG_GAIN;
@@ -177,8 +192,8 @@
         dstConfig->config_mask |= srcConfig->config_mask;
     }
     AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
+    toPolicyAudioPortConfig(dstConfig, srcConfig);
 
-    dstConfig->id = mId;
     dstConfig->role = AUDIO_PORT_ROLE_SOURCE;
     dstConfig->type = AUDIO_PORT_TYPE_MIX;
     dstConfig->ext.mix.hw_module = getModuleHandle();
@@ -188,7 +203,7 @@
 void AudioOutputDescriptor::toAudioPort(struct audio_port *port) const
 {
     // Should not be called for duplicated ports, see SwAudioOutputDescriptor::toAudioPortConfig.
-    mPort->toAudioPort(port);
+    mPolicyAudioPort->asAudioPort()->toAudioPort(port);
     port->id = mId;
     port->ext.mix.hw_module = getModuleHandle();
 }
@@ -320,13 +335,13 @@
     return filteredDevices.filter(devices);
 }
 
-bool SwAudioOutputDescriptor::deviceSupportsEncodedFormats(audio_devices_t device)
+bool SwAudioOutputDescriptor::devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes)
 {
     if (isDuplicated()) {
-        return (mOutput1->deviceSupportsEncodedFormats(device)
-                    || mOutput2->deviceSupportsEncodedFormats(device));
+        return (mOutput1->devicesSupportEncodedFormats(deviceTypes)
+                    || mOutput2->devicesSupportEncodedFormats(deviceTypes));
     } else {
-       return mProfile->deviceSupportsEncodedFormats(device);
+       return mProfile->devicesSupportEncodedFormats(deviceTypes);
     }
 }
 
@@ -349,16 +364,16 @@
     AudioOutputDescriptor::setClientActive(client, active);
 }
 
-bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
+bool SwAudioOutputDescriptor::isFixedVolume(const DeviceTypeSet& deviceTypes)
 {
     // unit gain if rerouting to external policy
-    if (device == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {
+    if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
         if (mPolicyMix != NULL) {
             ALOGV("max gain when rerouting for output=%d", mIoHandle);
             return true;
         }
     }
-    if (device == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
+    if (isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
         ALOGV("max gain when output device is telephony tx");
         return true;
     }
@@ -391,12 +406,12 @@
 
 bool SwAudioOutputDescriptor::setVolume(float volumeDb,
                                         VolumeSource vs, const StreamTypeVector &streamTypes,
-                                        audio_devices_t device,
+                                        const DeviceTypeSet& deviceTypes,
                                         uint32_t delayMs,
                                         bool force)
 {
     StreamTypeVector streams = streamTypes;
-    if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, device, delayMs, force)) {
+    if (!AudioOutputDescriptor::setVolume(volumeDb, vs, streamTypes, deviceTypes, delayMs, force)) {
         return false;
     }
     if (streams.empty()) {
@@ -406,7 +421,7 @@
         // APM loops on all group, so filter on active group to set the port gain,
         // let the other groups set the stream volume as per legacy
         // TODO: Pass in the device address and check against it.
-        if (device == devicePort->type() &&
+        if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
                 devicePort->hasGainController(true) && isActive(vs)) {
             ALOGV("%s: device %s has gain controller", __func__, devicePort->toString().c_str());
             // @todo: here we might be in trouble if the SwOutput has several active clients with
@@ -452,8 +467,11 @@
                                        audio_io_handle_t *output)
 {
     mDevices = devices;
-    const String8& address = devices.getFirstValidAddress();
-    audio_devices_t device = devices.types();
+    sp<DeviceDescriptor> device = devices.getDeviceForOpening();
+    LOG_ALWAYS_FATAL_IF(device == nullptr,
+                        "%s failed to get device descriptor for opening "
+                        "with the requested devices, all device types: %s",
+                        __func__, dumpDeviceTypes(devices.types()).c_str());
 
     audio_config_t lConfig;
     if (config == nullptr) {
@@ -483,27 +501,25 @@
     mFlags = (audio_output_flags_t)(mFlags | flags);
 
     ALOGV("opening output for device %s profile %p name %s",
-          mDevices.toString().c_str(), mProfile.get(), mProfile->getName().string());
+          mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
 
     status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
                                                    output,
                                                    &lConfig,
-                                                   &device,
-                                                   address,
+                                                   device,
                                                    &mLatency,
                                                    mFlags);
-    LOG_ALWAYS_FATAL_IF(mDevices.types() != device,
-                        "%s openOutput returned device %08x when given device %08x",
-                        __FUNCTION__, mDevices.types(), device);
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
-                            "%s openOutput returned output handle %d for device %08x",
-                            __FUNCTION__, *output, device);
+                            "%s openOutput returned output handle %d for device %s, "
+                            "selected device %s for opening",
+                            __FUNCTION__, *output, devices.toString().c_str(),
+                            device->toString().c_str());
         mSamplingRate = lConfig.sample_rate;
         mChannelMask = lConfig.channel_mask;
         mFormat = lConfig.format;
-        mId = AudioPort::getNextUniqueId();
+        mId = PolicyAudioPort::getNextUniqueId();
         mIoHandle = *output;
         mProfile->curOpenCount++;
     }
@@ -589,7 +605,7 @@
         return INVALID_OPERATION;
     }
 
-    mId = AudioPort::getNextUniqueId();
+    mId = PolicyAudioPort::getNextUniqueId();
     mIoHandle = *ioHandle;
     mOutput1 = output1;
     mOutput2 = output2;
@@ -632,12 +648,12 @@
 
 bool HwAudioOutputDescriptor::setVolume(float volumeDb,
                                         VolumeSource volumeSource, const StreamTypeVector &streams,
-                                        audio_devices_t device,
+                                        const DeviceTypeSet& deviceTypes,
                                         uint32_t delayMs,
                                         bool force)
 {
-    bool changed =
-        AudioOutputDescriptor::setVolume(volumeDb, volumeSource, streams, device, delayMs, force);
+    bool changed = AudioOutputDescriptor::setVolume(
+            volumeDb, volumeSource, streams, deviceTypes, delayMs, force);
 
     if (changed) {
       // TODO: use gain controller on source device if any to adjust volume
@@ -664,7 +680,8 @@
     for (size_t i = 0; i < this->size(); i++) {
         const sp<SwAudioOutputDescriptor> outputDesc = this->valueAt(i);
         if (outputDesc->isActive(volumeSource, inPastMs, sysTime)
-                && ((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) == 0)) {
+                && (!(outputDesc->devices()
+                        .containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL)))) {
             return true;
         }
     }
@@ -676,7 +693,7 @@
     nsecs_t sysTime = systemTime();
     for (size_t i = 0; i < size(); i++) {
         const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
-        if (((outputDesc->devices().types() & APM_AUDIO_OUT_DEVICE_REMOTE_ALL) != 0) &&
+        if (outputDesc->devices().containsDeviceAmongTypes(APM_AUDIO_OUT_DEVICE_REMOTE_ALL) &&
                 outputDesc->isActive(volumeSource, inPastMs, sysTime)) {
             // do not consider re routing (when the output is going to a dynamic policy)
             // as "remote playback"
@@ -707,9 +724,8 @@
     for (size_t i = 0; i < size(); i++) {
         sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
         if (!outputDesc->isDuplicated() &&
-             outputDesc->devices().types()  & AUDIO_DEVICE_OUT_ALL_A2DP &&
-             outputDesc->deviceSupportsEncodedFormats(
-                     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP)) {
+             outputDesc->devices().containsDeviceAmongTypes(getAudioDeviceOutAllA2dpSet()) &&
+             outputDesc->devicesSupportEncodedFormats(getAudioDeviceOutAllA2dpSet())) {
             return this->keyAt(i);
         }
     }
@@ -725,7 +741,7 @@
         sp<HwModule> primaryHwModule = primaryOutput->mProfile->getModule();
 
         for (const auto &outputProfile : primaryHwModule->getOutputProfiles()) {
-            if (outputProfile->supportsDeviceTypes(AUDIO_DEVICE_OUT_ALL_A2DP)) {
+            if (outputProfile->supportsDeviceTypes(getAudioDeviceOutAllA2dpSet())) {
                 return true;
             }
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index 3a4db90..bf0cc94 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -18,7 +18,6 @@
 //#define LOG_NDEBUG 0
 
 #include "AudioPatch.h"
-#include "AudioGain.h"
 #include "TypeConverter.h"
 
 #include <log/log.h>
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index c42923a..20c0a24 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -20,9 +20,8 @@
 #include "AudioPolicyMix.h"
 #include "TypeConverter.h"
 #include "HwModule.h"
-#include "AudioPort.h"
+#include "PolicyAudioPort.h"
 #include "IOProfile.h"
-#include "AudioGain.h"
 #include <AudioOutputDescriptor.h>
 
 namespace android {
@@ -456,9 +455,9 @@
         }
         // check if this mix goes to a device in the list of devices
         bool deviceMatch = false;
+        const AudioDeviceTypeAddr mixDevice(mix->mDeviceType, mix->mDeviceAddress.string());
         for (size_t j = 0; j < devices.size(); j++) {
-            if (devices[j].mType == mix->mDeviceType
-                    && devices[j].mAddress == mix->mDeviceAddress) {
+            if (mixDevice.equals(devices[j])) {
                 deviceMatch = true;
                 break;
             }
@@ -523,7 +522,7 @@
             }
         }
         if (ruleAllowsUid) {
-            devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress));
+            devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress.string()));
         }
     }
     return NO_ERROR;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
deleted file mode 100644
index c11490a..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::AudioPort"
-//#define LOG_NDEBUG 0
-#include "TypeConverter.h"
-#include "AudioPort.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include <policy.h>
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-namespace android {
-
-// --- AudioPort class implementation
-void AudioPort::attach(const sp<HwModule>& module)
-{
-    ALOGV("%s: attaching module %s to port %s", __FUNCTION__, getModuleName(), mName.string());
-    mModule = module;
-}
-
-void AudioPort::detach()
-{
-    mModule = nullptr;
-}
-
-// Note that is a different namespace than AudioFlinger unique IDs
-audio_port_handle_t AudioPort::getNextUniqueId()
-{
-    return getNextHandle();
-}
-
-audio_module_handle_t AudioPort::getModuleHandle() const
-{
-    return mModule != 0 ? mModule->getHandle() : AUDIO_MODULE_HANDLE_NONE;
-}
-
-uint32_t AudioPort::getModuleVersionMajor() const
-{
-    return mModule != 0 ? mModule->getHalVersionMajor() : 0;
-}
-
-const char *AudioPort::getModuleName() const
-{
-    return mModule != 0 ? mModule->getName() : "invalid module";
-}
-
-void AudioPort::toAudioPort(struct audio_port *port) const
-{
-    // TODO: update this function once audio_port structure reflects the new profile definition.
-    // For compatibility reason: flatening the AudioProfile into audio_port structure.
-    SortedVector<audio_format_t> flatenedFormats;
-    SampleRateVector flatenedRates;
-    ChannelsVector flatenedChannels;
-    for (const auto& profile : mProfiles) {
-        if (profile->isValid()) {
-            audio_format_t formatToExport = profile->getFormat();
-            const SampleRateVector &ratesToExport = profile->getSampleRates();
-            const ChannelsVector &channelsToExport = profile->getChannels();
-
-            if (flatenedFormats.indexOf(formatToExport) < 0) {
-                flatenedFormats.add(formatToExport);
-            }
-            for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
-                uint32_t rate = ratesToExport[rateIndex];
-                if (flatenedRates.indexOf(rate) < 0) {
-                    flatenedRates.add(rate);
-                }
-            }
-            for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
-                audio_channel_mask_t channels = channelsToExport[chanIndex];
-                if (flatenedChannels.indexOf(channels) < 0) {
-                    flatenedChannels.add(channels);
-                }
-            }
-            if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
-                    flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
-                    flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
-                ALOGE("%s: bailing out: cannot export profiles to port config", __FUNCTION__);
-                return;
-            }
-        }
-    }
-    port->role = mRole;
-    port->type = mType;
-    strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
-    port->num_sample_rates = flatenedRates.size();
-    port->num_channel_masks = flatenedChannels.size();
-    port->num_formats = flatenedFormats.size();
-    for (size_t i = 0; i < flatenedRates.size(); i++) {
-        port->sample_rates[i] = flatenedRates[i];
-    }
-    for (size_t i = 0; i < flatenedChannels.size(); i++) {
-        port->channel_masks[i] = flatenedChannels[i];
-    }
-    for (size_t i = 0; i < flatenedFormats.size(); i++) {
-        port->formats[i] = flatenedFormats[i];
-    }
-
-    ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
-
-    uint32_t i;
-    for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
-        port->gains[i] = mGains[i]->getGain();
-    }
-    port->num_gains = i;
-}
-
-void AudioPort::importAudioPort(const sp<AudioPort>& port, bool force __unused)
-{
-    for (const auto& profileToImport : port->mProfiles) {
-        if (profileToImport->isValid()) {
-            // Import only valid port, i.e. valid format, non empty rates and channels masks
-            bool hasSameProfile = false;
-            for (const auto& profile : mProfiles) {
-                if (*profile == *profileToImport) {
-                    // never import a profile twice
-                    hasSameProfile = true;
-                    break;
-                }
-            }
-            if (hasSameProfile) { // never import a same profile twice
-                continue;
-            }
-            addAudioProfile(profileToImport);
-        }
-    }
-}
-
-status_t AudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
-{
-    status_t status = NO_ERROR;
-    auto config_mask = config->config_mask;
-    if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
-        config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
-        status = checkGain(&config->gain, config->gain.index);
-        if (status != NO_ERROR) {
-            return status;
-        }
-    }
-    if (config_mask != 0) {
-        // TODO should we check sample_rate / channel_mask / format separately?
-        status = mProfiles.checkExactProfile(config->sample_rate,
-                                             config->channel_mask,
-                                             config->format);
-    }
-    return status;
-}
-
-void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
-{
-    pickedRate = 0;
-    // For direct outputs, pick minimum sampling rate: this helps ensuring that the
-    // channel count / sampling rate combination chosen will be supported by the connected
-    // sink
-    if (isDirectOutput()) {
-        uint32_t samplingRate = UINT_MAX;
-        for (size_t i = 0; i < samplingRates.size(); i ++) {
-            if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
-                samplingRate = samplingRates[i];
-            }
-        }
-        pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
-    } else {
-        uint32_t maxRate = SAMPLE_RATE_HZ_MAX;
-
-        // For mixed output and inputs, use max mixer sampling rates. Do not
-        // limit sampling rate otherwise
-        // For inputs, also see checkCompatibleSamplingRate().
-        if (mType != AUDIO_PORT_TYPE_MIX) {
-            maxRate = UINT_MAX;
-        }
-        // TODO: should mSamplingRates[] be ordered in terms of our preference
-        // and we return the first (and hence most preferred) match?  This is of concern if
-        // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
-        for (size_t i = 0; i < samplingRates.size(); i ++) {
-            if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
-                pickedRate = samplingRates[i];
-            }
-        }
-    }
-}
-
-void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
-                                const ChannelsVector &channelMasks) const
-{
-    pickedChannelMask = AUDIO_CHANNEL_NONE;
-    // For direct outputs, pick minimum channel count: this helps ensuring that the
-    // channel count / sampling rate combination chosen will be supported by the connected
-    // sink
-    if (isDirectOutput()) {
-        uint32_t channelCount = UINT_MAX;
-        for (size_t i = 0; i < channelMasks.size(); i ++) {
-            uint32_t cnlCount;
-            if (useInputChannelMask()) {
-                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
-            } else {
-                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
-            }
-            if ((cnlCount < channelCount) && (cnlCount > 0)) {
-                pickedChannelMask = channelMasks[i];
-                channelCount = cnlCount;
-            }
-        }
-    } else {
-        uint32_t channelCount = 0;
-        uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
-        // For mixed output and inputs, use max mixer channel count. Do not
-        // limit channel count otherwise
-        if (mType != AUDIO_PORT_TYPE_MIX) {
-            maxCount = UINT_MAX;
-        }
-        for (size_t i = 0; i < channelMasks.size(); i ++) {
-            uint32_t cnlCount;
-            if (useInputChannelMask()) {
-                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
-            } else {
-                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
-            }
-            if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
-                pickedChannelMask = channelMasks[i];
-                channelCount = cnlCount;
-            }
-        }
-    }
-}
-
-/* format in order of increasing preference */
-const audio_format_t AudioPort::sPcmFormatCompareTable[] = {
-        AUDIO_FORMAT_DEFAULT,
-        AUDIO_FORMAT_PCM_16_BIT,
-        AUDIO_FORMAT_PCM_8_24_BIT,
-        AUDIO_FORMAT_PCM_24_BIT_PACKED,
-        AUDIO_FORMAT_PCM_32_BIT,
-        AUDIO_FORMAT_PCM_FLOAT,
-};
-
-int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
-{
-    // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
-    // compressed format and better than any PCM format. This is by design of pickFormat()
-    if (!audio_is_linear_pcm(format1)) {
-        if (!audio_is_linear_pcm(format2)) {
-            return 0;
-        }
-        return 1;
-    }
-    if (!audio_is_linear_pcm(format2)) {
-        return -1;
-    }
-
-    int index1 = -1, index2 = -1;
-    for (size_t i = 0;
-            (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
-            i ++) {
-        if (sPcmFormatCompareTable[i] == format1) {
-            index1 = i;
-        }
-        if (sPcmFormatCompareTable[i] == format2) {
-            index2 = i;
-        }
-    }
-    // format1 not found => index1 < 0 => format2 > format1
-    // format2 not found => index2 < 0 => format2 < format1
-    return index1 - index2;
-}
-
-uint32_t AudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
-{
-    if (format1 == format2) {
-        return 0;
-    }
-    if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
-        return kFormatDistanceMax;
-    }
-    int diffBytes = (int)audio_bytes_per_sample(format1) -
-            audio_bytes_per_sample(format2);
-
-    return abs(diffBytes);
-}
-
-bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
-                                    audio_format_t currentFormat,
-                                    audio_format_t targetFormat)
-{
-    return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
-}
-
-void AudioPort::pickAudioProfile(uint32_t &samplingRate,
-                                 audio_channel_mask_t &channelMask,
-                                 audio_format_t &format) const
-{
-    format = AUDIO_FORMAT_DEFAULT;
-    samplingRate = 0;
-    channelMask = AUDIO_CHANNEL_NONE;
-
-    // special case for uninitialized dynamic profile
-    if (!mProfiles.hasValidProfile()) {
-        return;
-    }
-    audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
-    // For mixed output and inputs, use best mixer output format.
-    // Do not limit format otherwise
-    if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
-        bestFormat = AUDIO_FORMAT_INVALID;
-    }
-
-    for (size_t i = 0; i < mProfiles.size(); i ++) {
-        if (!mProfiles[i]->isValid()) {
-            continue;
-        }
-        audio_format_t formatToCompare = mProfiles[i]->getFormat();
-        if ((compareFormats(formatToCompare, format) > 0) &&
-                (compareFormats(formatToCompare, bestFormat) <= 0)) {
-            uint32_t pickedSamplingRate = 0;
-            audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
-            pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
-            pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
-
-            if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
-                    && pickedSamplingRate != 0) {
-                format = formatToCompare;
-                channelMask = pickedChannelMask;
-                samplingRate = pickedSamplingRate;
-                // TODO: shall we return on the first one or still trying to pick a better Profile?
-            }
-        }
-    }
-    ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__, mName.string(),
-          samplingRate, channelMask, format);
-}
-
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
-{
-    if (index < 0 || (size_t)index >= mGains.size()) {
-        return BAD_VALUE;
-    }
-    return mGains[index]->checkConfig(gainConfig);
-}
-
-void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
-{
-    if (!mName.isEmpty()) {
-        dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
-    }
-    if (verbose) {
-        mProfiles.dump(dst, spaces);
-
-        if (mGains.size() != 0) {
-            dst->appendFormat("%*s- gains:\n", spaces, "");
-            for (size_t i = 0; i < mGains.size(); i++) {
-                mGains[i]->dump(dst, spaces + 2, i);
-            }
-        }
-    }
-}
-
-void AudioPort::log(const char* indent) const
-{
-    ALOGI("%s Port[nm:%s, type:%d, role:%d]", indent, mName.string(), mType, mRole);
-}
-
-// --- AudioPortConfig class implementation
-
-status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
-                                               struct audio_port_config *backupConfig)
-{
-    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
-    status_t status = NO_ERROR;
-
-    toAudioPortConfig(&localBackupConfig);
-
-    sp<AudioPort> audioport = getAudioPort();
-    if (audioport == 0) {
-        status = NO_INIT;
-        goto exit;
-    }
-    status = audioport->checkExactAudioProfile(config);
-    if (status != NO_ERROR) {
-        goto exit;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-        mSamplingRate = config->sample_rate;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-        mChannelMask = config->channel_mask;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-        mFormat = config->format;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
-        mGain = config->gain;
-    }
-    if (config->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
-        mFlags = config->flags;
-    }
-
-exit:
-    if (status != NO_ERROR) {
-        applyAudioPortConfig(&localBackupConfig);
-    }
-    if (backupConfig != NULL) {
-        *backupConfig = localBackupConfig;
-    }
-    return status;
-}
-
-namespace {
-
-template<typename T>
-void updateField(
-        const T& portConfigField, T audio_port_config::*port_config_field,
-        struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig,
-        unsigned int configMask, T defaultValue)
-{
-    if (dstConfig->config_mask & configMask) {
-        if ((srcConfig != nullptr) && (srcConfig->config_mask & configMask)) {
-            dstConfig->*port_config_field = srcConfig->*port_config_field;
-        } else {
-            dstConfig->*port_config_field = portConfigField;
-        }
-    } else {
-        dstConfig->*port_config_field = defaultValue;
-    }
-}
-
-} // namespace
-
-void AudioPortConfig::toAudioPortConfig(struct audio_port_config *dstConfig,
-                                        const struct audio_port_config *srcConfig) const
-{
-    updateField(mSamplingRate, &audio_port_config::sample_rate,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_SAMPLE_RATE, 0u);
-    updateField(mChannelMask, &audio_port_config::channel_mask,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_CHANNEL_MASK,
-            (audio_channel_mask_t)AUDIO_CHANNEL_NONE);
-    updateField(mFormat, &audio_port_config::format,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FORMAT, AUDIO_FORMAT_INVALID);
-
-    sp<AudioPort> audioport = getAudioPort();
-    if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
-        dstConfig->gain = mGain;
-        if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
-                && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
-            dstConfig->gain = srcConfig->gain;
-        }
-    } else {
-        dstConfig->gain.index = -1;
-    }
-    if (dstConfig->gain.index != -1) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_GAIN;
-    } else {
-        dstConfig->config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
-    }
-
-    updateField(mFlags, &audio_port_config::flags,
-            dstConfig, srcConfig, AUDIO_PORT_CONFIG_FLAGS, { AUDIO_INPUT_FLAG_NONE });
-}
-
-bool AudioPortConfig::hasGainController(bool canUseForVolume) const
-{
-    sp<AudioPort> audioport = getAudioPort();
-    if (audioport == nullptr) {
-        return false;
-    }
-    return canUseForVolume ? audioport->getGains().canUseForVolume()
-                           : audioport->getGains().size() > 0;
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
deleted file mode 100644
index 69d6b0c..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <set>
-#include <string>
-
-#define LOG_TAG "APM::AudioProfile"
-//#define LOG_NDEBUG 0
-
-#include <media/AudioResamplerPublic.h>
-#include <utils/Errors.h>
-
-#include "AudioGain.h"
-#include "AudioPort.h"
-#include "AudioProfile.h"
-#include "HwModule.h"
-#include "TypeConverter.h"
-
-namespace android {
-
-ChannelsVector ChannelsVector::asInMask() const
-{
-    ChannelsVector inMaskVector;
-    for (const auto& channel : *this) {
-        if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
-            inMaskVector.add(audio_channel_mask_out_to_in(channel));
-        }
-    }
-    return inMaskVector;
-}
-
-ChannelsVector ChannelsVector::asOutMask() const
-{
-    ChannelsVector outMaskVector;
-    for (const auto& channel : *this) {
-        if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
-            outMaskVector.add(audio_channel_mask_in_to_out(channel));
-        }
-    }
-    return outMaskVector;
-}
-
-bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
-{
-    return (left.getFormat() == compareTo.getFormat()) &&
-            (left.getChannels() == compareTo.getChannels()) &&
-            (left.getSampleRates() == compareTo.getSampleRates());
-}
-
-static AudioProfile* createFullDynamicImpl()
-{
-    AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
-            ChannelsVector(), SampleRateVector());
-    dynamicProfile->setDynamicFormat(true);
-    dynamicProfile->setDynamicChannels(true);
-    dynamicProfile->setDynamicRate(true);
-    return dynamicProfile;
-}
-
-// static
-sp<AudioProfile> AudioProfile::createFullDynamic()
-{
-    static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
-    return dynamicProfile;
-}
-
-AudioProfile::AudioProfile(audio_format_t format,
-                           audio_channel_mask_t channelMasks,
-                           uint32_t samplingRate) :
-        mName(String8("")),
-        mFormat(format)
-{
-    mChannelMasks.add(channelMasks);
-    mSamplingRates.add(samplingRate);
-}
-
-AudioProfile::AudioProfile(audio_format_t format,
-                           const ChannelsVector &channelMasks,
-                           const SampleRateVector &samplingRateCollection) :
-        mName(String8("")),
-        mFormat(format),
-        mChannelMasks(channelMasks),
-        mSamplingRates(samplingRateCollection) {}
-
-void AudioProfile::setChannels(const ChannelsVector &channelMasks)
-{
-    if (mIsDynamicChannels) {
-        mChannelMasks = channelMasks;
-    }
-}
-
-void AudioProfile::setSampleRates(const SampleRateVector &sampleRates)
-{
-    if (mIsDynamicRate) {
-        mSamplingRates = sampleRates;
-    }
-}
-
-void AudioProfile::clear()
-{
-    if (mIsDynamicChannels) {
-        mChannelMasks.clear();
-    }
-    if (mIsDynamicRate) {
-        mSamplingRates.clear();
-    }
-}
-
-status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
-                                  audio_format_t format) const
-{
-    if (audio_formats_match(format, mFormat) &&
-            supportsChannels(channelMask) &&
-            supportsRate(samplingRate)) {
-        return NO_ERROR;
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
-                                                   uint32_t &updatedSamplingRate) const
-{
-    ALOG_ASSERT(samplingRate > 0);
-
-    if (mSamplingRates.isEmpty()) {
-        updatedSamplingRate = samplingRate;
-        return NO_ERROR;
-    }
-
-    // Search for the closest supported sampling rate that is above (preferred)
-    // or below (acceptable) the desired sampling rate, within a permitted ratio.
-    // The sampling rates are sorted in ascending order.
-    size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
-
-    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
-    if (orderOfDesiredRate < mSamplingRates.size()) {
-        uint32_t candidate = mSamplingRates[orderOfDesiredRate];
-        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
-            updatedSamplingRate = candidate;
-            return NO_ERROR;
-        }
-    }
-    // But if we have to up-sample from a lower sampling rate, that's OK.
-    if (orderOfDesiredRate != 0) {
-        uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
-        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
-            updatedSamplingRate = candidate;
-            return NO_ERROR;
-        }
-    }
-    // leave updatedSamplingRate unmodified
-    return BAD_VALUE;
-}
-
-status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-                                                  audio_channel_mask_t &updatedChannelMask,
-                                                  audio_port_type_t portType,
-                                                  audio_port_role_t portRole) const
-{
-    if (mChannelMasks.isEmpty()) {
-        updatedChannelMask = channelMask;
-        return NO_ERROR;
-    }
-    const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
-    const bool isIndex = audio_channel_mask_get_representation(channelMask)
-            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
-    const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
-    int bestMatch = 0;
-    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
-        audio_channel_mask_t supported = mChannelMasks[i];
-        if (supported == channelMask) {
-            // Exact matches always taken.
-            updatedChannelMask = channelMask;
-            return NO_ERROR;
-        }
-
-        // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
-        if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
-            // Approximate (best) match:
-            // The match score measures how well the supported channel mask matches the
-            // desired mask, where increasing-is-better.
-            //
-            // TODO: Some tweaks may be needed.
-            // Should be a static function of the data processing library.
-            //
-            // In priority:
-            // match score = 1000 if legacy channel conversion equivalent (always prefer this)
-            // OR
-            // match score += 100 if the channel mask representations match
-            // match score += number of channels matched.
-            // match score += 100 if the channel mask representations DO NOT match
-            //   but the profile has positional channel mask and less than 2 channels.
-            //   This is for audio HAL convention to not list index masks for less than 2 channels
-            //
-            // If there are no matched channels, the mask may still be accepted
-            // but the playback or record will be silent.
-            const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
-                    == AUDIO_CHANNEL_REPRESENTATION_INDEX);
-            const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
-            int match;
-            if (isIndex && isSupportedIndex) {
-                // index equivalence
-                match = 100 + __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask)
-                            & audio_channel_mask_get_bits(supported));
-            } else if (isIndex && !isSupportedIndex) {
-                const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
-                match = __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
-                if (supportedChannelCount <= FCC_2) {
-                    match += 100;
-                }
-            } else if (!isIndex && isSupportedIndex) {
-                const uint32_t equivalentBits = (1 << channelCount) - 1;
-                match = __builtin_popcount(
-                        equivalentBits & audio_channel_mask_get_bits(supported));
-            } else {
-                // positional equivalence
-                match = 100 + __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask)
-                            & audio_channel_mask_get_bits(supported));
-                switch (supported) {
-                case AUDIO_CHANNEL_IN_FRONT_BACK:
-                case AUDIO_CHANNEL_IN_STEREO:
-                    if (channelMask == AUDIO_CHANNEL_IN_MONO) {
-                        match = 1000;
-                    }
-                    break;
-                case AUDIO_CHANNEL_IN_MONO:
-                    if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
-                            || channelMask == AUDIO_CHANNEL_IN_STEREO) {
-                        match = 1000;
-                    }
-                    break;
-                default:
-                    break;
-                }
-            }
-            if (match > bestMatch) {
-                bestMatch = match;
-                updatedChannelMask = supported;
-            }
-        }
-    }
-    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-void AudioProfile::dump(String8 *dst, int spaces) const
-{
-    dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
-             mIsDynamicChannels ? "[dynamic channels]" : "",
-             mIsDynamicRate ? "[dynamic rates]" : "");
-    if (mName.length() != 0) {
-        dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
-    }
-    std::string formatLiteral;
-    if (FormatConverter::toString(mFormat, formatLiteral)) {
-        dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
-    }
-    if (!mSamplingRates.isEmpty()) {
-        dst->appendFormat("%*s- sampling rates:", spaces, "");
-        for (size_t i = 0; i < mSamplingRates.size(); i++) {
-            dst->appendFormat("%d", mSamplingRates[i]);
-            dst->append(i == (mSamplingRates.size() - 1) ? "" : ", ");
-        }
-        dst->append("\n");
-    }
-
-    if (!mChannelMasks.isEmpty()) {
-        dst->appendFormat("%*s- channel masks:", spaces, "");
-        for (size_t i = 0; i < mChannelMasks.size(); i++) {
-            dst->appendFormat("0x%04x", mChannelMasks[i]);
-            dst->append(i == (mChannelMasks.size() - 1) ? "" : ", ");
-        }
-        dst->append("\n");
-    }
-}
-
-ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
-{
-    ssize_t index = Vector::add(profile);
-    // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
-    // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
-    // [](const audio_format_t *format1, const audio_format_t *format2) {
-    //     return compareFormats(*format1, *format2);
-    // }
-    sort(compareFormats);
-    return index;
-}
-
-ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
-{
-    // Check valid profile to add:
-    if (!profileToAdd->hasValidFormat()) {
-        return -1;
-    }
-    if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
-        FormatVector formats;
-        formats.add(profileToAdd->getFormat());
-        setFormats(FormatVector(formats));
-        return 0;
-    }
-    if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
-        setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
-        return 0;
-    }
-    if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
-        setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
-        return 0;
-    }
-    // Go through the list of profile to avoid duplicates
-    for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
-        const sp<AudioProfile> &profile = itemAt(profileIndex);
-        if (profile->isValid() && profile == profileToAdd) {
-            // Nothing to do
-            return profileIndex;
-        }
-    }
-    profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
-    return add(profileToAdd);
-}
-
-status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
-                                               audio_channel_mask_t channelMask,
-                                               audio_format_t format) const
-{
-    if (isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (const auto& profile : *this) {
-        if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
-                                                    audio_channel_mask_t &channelMask,
-                                                    audio_format_t &format,
-                                                    audio_port_type_t portType,
-                                                    audio_port_role_t portRole) const
-{
-    if (isEmpty()) {
-        return NO_ERROR;
-    }
-
-    const bool checkInexact = // when port is input and format is linear pcm
-            portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
-            && audio_is_linear_pcm(format);
-
-    // iterate from best format to worst format (reverse order)
-    for (ssize_t i = size() - 1; i >= 0 ; --i) {
-        const sp<AudioProfile> profile = itemAt(i);
-        audio_format_t formatToCompare = profile->getFormat();
-        if (formatToCompare == format ||
-                (checkInexact
-                        && formatToCompare != AUDIO_FORMAT_DEFAULT
-                        && audio_is_linear_pcm(formatToCompare))) {
-            // Compatible profile has been found, checks if this profile has compatible
-            // rate and channels as well
-            audio_channel_mask_t updatedChannels;
-            uint32_t updatedRate;
-            if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
-                                                    portType, portRole) == NO_ERROR &&
-                    profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
-                // for inexact checks we take the first linear pcm format due to sorting.
-                format = formatToCompare;
-                channelMask = updatedChannels;
-                samplingRate = updatedRate;
-                return NO_ERROR;
-            }
-        }
-    }
-    return BAD_VALUE;
-}
-
-void AudioProfileVector::clearProfiles()
-{
-    for (size_t i = size(); i != 0; ) {
-        sp<AudioProfile> profile = itemAt(--i);
-        if (profile->isDynamicFormat() && profile->hasValidFormat()) {
-            removeAt(i);
-            continue;
-        }
-        profile->clear();
-    }
-}
-
-// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
-// The result is ordered according to 'order'.
-template<typename T, typename Order>
-std::vector<typename T::value_type> intersectFilterAndOrder(
-        const T& input1, const T& input2, const Order& order)
-{
-    std::set<typename T::value_type> set1{input1.begin(), input1.end()};
-    std::set<typename T::value_type> set2{input2.begin(), input2.end()};
-    std::set<typename T::value_type> common;
-    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
-            std::inserter(common, common.begin()));
-    std::vector<typename T::value_type> result;
-    for (const auto& e : order) {
-        if (common.find(e) != common.end()) result.push_back(e);
-    }
-    return result;
-}
-
-// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
-// 'comp' is a comparator function.
-template<typename T, typename Compare>
-std::vector<typename T::value_type> intersectAndOrder(
-        const T& input1, const T& input2, Compare comp)
-{
-    std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
-    std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
-    std::vector<typename T::value_type> result;
-    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
-            std::back_inserter(result), comp);
-    return result;
-}
-
-status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
-            const std::vector<audio_format_t>& preferredFormats,
-            const std::vector<audio_channel_mask_t>& preferredOutputChannels,
-            bool preferHigherSamplingRates,
-            audio_config_base *bestOutputConfig) const
-{
-    auto formats = intersectFilterAndOrder(getSupportedFormats(),
-            outputProfiles.getSupportedFormats(), preferredFormats);
-    // Pick the best compatible profile.
-    for (const auto& f : formats) {
-        sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
-        sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
-        if (inputProfile == nullptr || outputProfile == nullptr) {
-            continue;
-        }
-        auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(),
-                outputProfile->getChannels(), preferredOutputChannels);
-        if (channels.empty()) {
-            continue;
-        }
-        auto sampleRates = preferHigherSamplingRates ?
-                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
-                        std::greater<typename SampleRateVector::value_type>()) :
-                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
-                        std::less<typename SampleRateVector::value_type>());
-        if (sampleRates.empty()) {
-            continue;
-        }
-        ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
-                __func__, *channels.begin(), *sampleRates.begin(), f);
-        bestOutputConfig->format = f;
-        bestOutputConfig->sample_rate = *sampleRates.begin();
-        bestOutputConfig->channel_mask = *channels.begin();
-        return NO_ERROR;
-    }
-    return BAD_VALUE;
-}
-
-sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->isValid()) {
-            return itemAt(i);
-        }
-    }
-    return 0;
-}
-
-sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
-            return itemAt(i);
-        }
-    }
-    return 0;
-}
-
-FormatVector AudioProfileVector::getSupportedFormats() const
-{
-    FormatVector supportedFormats;
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->hasValidFormat()) {
-            supportedFormats.add(itemAt(i)->getFormat());
-        }
-    }
-    return supportedFormats;
-}
-
-bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicChannels()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool AudioProfileVector::hasDynamicProfile() const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->isDynamic()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicRate()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-void AudioProfileVector::setFormats(const FormatVector &formats)
-{
-    // Only allow to change the format of dynamic profile
-    sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
-    if (dynamicFormatProfile == 0) {
-        return;
-    }
-    for (size_t i = 0; i < formats.size(); i++) {
-        sp<AudioProfile> profile = new AudioProfile(formats[i],
-                dynamicFormatProfile->getChannels(),
-                dynamicFormatProfile->getSampleRates());
-        profile->setDynamicFormat(true);
-        profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
-        profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
-        add(profile);
-    }
-}
-
-void AudioProfileVector::dump(String8 *dst, int spaces) const
-{
-    dst->appendFormat("%*s- Profiles:\n", spaces, "");
-    for (size_t i = 0; i < size(); i++) {
-        dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
-        itemAt(i)->dump(dst, spaces + 8);
-    }
-}
-
-sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
-{
-    for (size_t i = 0; i < size(); i++) {
-        if (itemAt(i)->getFormat() == format) {
-            return itemAt(i);
-        }
-    }
-    return 0;
-}
-
-void AudioProfileVector::setSampleRatesFor(
-        const SampleRateVector &sampleRates, audio_format_t format)
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicRate()) {
-            if (profile->hasValidRates()) {
-                // Need to create a new profile with same format
-                sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
-                        sampleRates);
-                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
-                add(profileToAdd);
-            } else {
-                profile->setSampleRates(sampleRates);
-            }
-            return;
-        }
-    }
-}
-
-void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
-{
-    for (size_t i = 0; i < size(); i++) {
-        sp<AudioProfile> profile = itemAt(i);
-        if (profile->getFormat() == format && profile->isDynamicChannels()) {
-            if (profile->hasValidChannels()) {
-                // Need to create a new profile with same format
-                sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
-                        profile->getSampleRates());
-                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
-                add(profileToAdd);
-            } else {
-                profile->setChannels(channelMasks);
-            }
-            return;
-        }
-    }
-}
-
-// static
-int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
-                                       const sp<AudioProfile> *profile2)
-{
-    return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
-}
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
new file mode 100644
index 0000000..8ccb8b9
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfileVectorHelper.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <set>
+#include <string>
+
+#define LOG_TAG "APM::AudioProfileVectorHelper"
+//#define LOG_NDEBUG 0
+
+#include <media/AudioContainers.h>
+#include <media/AudioResamplerPublic.h>
+#include <utils/Errors.h>
+
+#include "AudioProfileVectorHelper.h"
+#include "HwModule.h"
+#include "PolicyAudioPort.h"
+#include "policy.h"
+
+namespace android {
+
+void sortAudioProfiles(AudioProfileVector &audioProfileVector) {
+    std::sort(audioProfileVector.begin(), audioProfileVector.end(),
+            [](const sp<AudioProfile> & a, const sp<AudioProfile> & b)
+            {
+                return PolicyAudioPort::compareFormats(a->getFormat(), b->getFormat()) < 0;
+            });
+}
+
+ssize_t addAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                               const sp<AudioProfile> &profile)
+{
+    ssize_t ret = audioProfileVector.add(profile);
+    // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+    sortAudioProfiles(audioProfileVector);
+    return ret;
+}
+
+sp<AudioProfile> getAudioProfileForFormat(const AudioProfileVector &audioProfileVector,
+                                          audio_format_t format)
+{
+    for (const auto &profile : audioProfileVector) {
+        if (profile->getFormat() == format) {
+            return profile;
+        }
+    }
+    return nullptr;
+}
+
+void setSampleRatesForAudioProfiles(AudioProfileVector &audioProfileVector,
+                                    const SampleRateSet &sampleRateSet,
+                                    audio_format_t format)
+{
+    for (const auto &profile : audioProfileVector) {
+        if (profile->getFormat() == format && profile->isDynamicRate()) {
+            if (profile->hasValidRates()) {
+                // Need to create a new profile with same format
+                sp<AudioProfile> profileToAdd = new AudioProfile(
+                        format, profile->getChannels(), sampleRateSet);
+                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                addAudioProfileAndSort(audioProfileVector, profileToAdd);
+            } else {
+                profile->setSampleRates(sampleRateSet);
+            }
+            return;
+        }
+    }
+}
+
+void setChannelsForAudioProfiles(AudioProfileVector &audioProfileVector,
+                                 const ChannelMaskSet &channelMaskSet,
+                                 audio_format_t format)
+{
+    for (const auto &profile : audioProfileVector) {
+        if (profile->getFormat() == format && profile->isDynamicChannels()) {
+            if (profile->hasValidChannels()) {
+                // Need to create a new profile with same format
+                sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMaskSet,
+                        profile->getSampleRates());
+                profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+                addAudioProfileAndSort(audioProfileVector, profileToAdd);
+            } else {
+                profile->setChannels(channelMaskSet);
+            }
+            return;
+        }
+    }
+}
+
+void addProfilesForFormats(AudioProfileVector &audioProfileVector, const FormatVector &formatVector)
+{
+    // Only allow to change the format of dynamic profile
+    sp<AudioProfile> dynamicFormatProfile = getAudioProfileForFormat(
+            audioProfileVector, gDynamicFormat);
+    if (!dynamicFormatProfile) {
+        return;
+    }
+    for (const auto &format : formatVector) {
+        sp<AudioProfile> profile = new AudioProfile(format,
+                dynamicFormatProfile->getChannels(),
+                dynamicFormatProfile->getSampleRates());
+        profile->setDynamicFormat(true);
+        profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+        profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+        addAudioProfileAndSort(audioProfileVector, profile);
+    }
+}
+
+void addDynamicAudioProfileAndSort(AudioProfileVector &audioProfileVector,
+                                      const sp<AudioProfile> &profileToAdd)
+{
+    // Check valid profile to add:
+    if (!profileToAdd->hasValidFormat()) {
+        ALOGW("Adding dynamic audio profile without valid format");
+        return;
+    }
+    if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+        FormatVector formats;
+        formats.push_back(profileToAdd->getFormat());
+        addProfilesForFormats(audioProfileVector, FormatVector(formats));
+        return;
+    }
+    if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+        setSampleRatesForAudioProfiles(
+                audioProfileVector, profileToAdd->getSampleRates(), profileToAdd->getFormat());
+        return;
+    }
+    if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+        setChannelsForAudioProfiles(
+                audioProfileVector, profileToAdd->getChannels(), profileToAdd->getFormat());
+        return;
+    }
+    // Go through the list of profile to avoid duplicates
+    for (size_t profileIndex = 0; profileIndex < audioProfileVector.size(); profileIndex++) {
+        const sp<AudioProfile> &profile = audioProfileVector.at(profileIndex);
+        if (profile->isValid() && profile == profileToAdd) {
+            // Nothing to do
+            return;
+        }
+    }
+    profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+    addAudioProfileAndSort(audioProfileVector, profileToAdd);
+}
+
+void appendAudioProfiles(AudioProfileVector &audioProfileVector,
+                         const AudioProfileVector &audioProfileVectorToAppend)
+{
+    audioProfileVector.insert(audioProfileVector.end(),
+                              audioProfileVectorToAppend.begin(),
+                              audioProfileVectorToAppend.end());
+}
+
+status_t checkExact(const sp<AudioProfile> &audioProfile,
+                    uint32_t samplingRate,
+                    audio_channel_mask_t channelMask,
+                    audio_format_t format)
+{
+    if (audio_formats_match(format, audioProfile->getFormat()) &&
+            audioProfile->supportsChannels(channelMask) &&
+            audioProfile->supportsRate(samplingRate)) {
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
+status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
+                                     uint32_t samplingRate,
+                                     uint32_t &updatedSamplingRate)
+{
+    ALOG_ASSERT(samplingRate > 0);
+
+    const SampleRateSet sampleRates = audioProfile->getSampleRates();
+    if (sampleRates.empty()) {
+        updatedSamplingRate = samplingRate;
+        return NO_ERROR;
+    }
+
+    // Search for the closest supported sampling rate that is above (preferred)
+    // or below (acceptable) the desired sampling rate, within a permitted ratio.
+    // The sampling rates are sorted in ascending order.
+    auto desiredRate = sampleRates.lower_bound(samplingRate);
+
+    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+    if (desiredRate != sampleRates.end()) {
+        if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+            updatedSamplingRate = *desiredRate;
+            return NO_ERROR;
+        }
+    }
+    // But if we have to up-sample from a lower sampling rate, that's OK.
+    if (desiredRate != sampleRates.begin()) {
+        uint32_t candidate = *(--desiredRate);
+        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
+            updatedSamplingRate = candidate;
+            return NO_ERROR;
+        }
+    }
+    // leave updatedSamplingRate unmodified
+    return BAD_VALUE;
+}
+
+status_t checkCompatibleChannelMask(const sp<AudioProfile> &audioProfile,
+                                    audio_channel_mask_t channelMask,
+                                    audio_channel_mask_t &updatedChannelMask,
+                                    audio_port_type_t portType,
+                                    audio_port_role_t portRole)
+{
+    const ChannelMaskSet channelMasks = audioProfile->getChannels();
+    if (channelMasks.empty()) {
+        updatedChannelMask = channelMask;
+        return NO_ERROR;
+    }
+    const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
+    const bool isIndex = audio_channel_mask_get_representation(channelMask)
+            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+    const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
+    int bestMatch = 0;
+    for (const auto &supported : channelMasks) {
+        if (supported == channelMask) {
+            // Exact matches always taken.
+            updatedChannelMask = channelMask;
+            return NO_ERROR;
+        }
+
+        // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+        if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+            // Approximate (best) match:
+            // The match score measures how well the supported channel mask matches the
+            // desired mask, where increasing-is-better.
+            //
+            // TODO: Some tweaks may be needed.
+            // Should be a static function of the data processing library.
+            //
+            // In priority:
+            // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+            // OR
+            // match score += 100 if the channel mask representations match
+            // match score += number of channels matched.
+            // match score += 100 if the channel mask representations DO NOT match
+            //   but the profile has positional channel mask and less than 2 channels.
+            //   This is for audio HAL convention to not list index masks for less than 2 channels
+            //
+            // If there are no matched channels, the mask may still be accepted
+            // but the playback or record will be silent.
+            const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+                    == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+            const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
+            int match;
+            if (isIndex && isSupportedIndex) {
+                // index equivalence
+                match = 100 + __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask)
+                            & audio_channel_mask_get_bits(supported));
+            } else if (isIndex && !isSupportedIndex) {
+                const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
+                match = __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
+                if (supportedChannelCount <= FCC_2) {
+                    match += 100;
+                }
+            } else if (!isIndex && isSupportedIndex) {
+                const uint32_t equivalentBits = (1 << channelCount) - 1;
+                match = __builtin_popcount(
+                        equivalentBits & audio_channel_mask_get_bits(supported));
+            } else {
+                // positional equivalence
+                match = 100 + __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask)
+                            & audio_channel_mask_get_bits(supported));
+                switch (supported) {
+                case AUDIO_CHANNEL_IN_FRONT_BACK:
+                case AUDIO_CHANNEL_IN_STEREO:
+                    if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+                        match = 1000;
+                    }
+                    break;
+                case AUDIO_CHANNEL_IN_MONO:
+                    if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+                            || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+                        match = 1000;
+                    }
+                    break;
+                default:
+                    break;
+                }
+            }
+            if (match > bestMatch) {
+                bestMatch = match;
+                updatedChannelMask = supported;
+            }
+        }
+    }
+    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
+}
+
+status_t checkExactProfile(const AudioProfileVector& audioProfileVector,
+                           const uint32_t samplingRate,
+                           audio_channel_mask_t channelMask,
+                           audio_format_t format)
+{
+    if (audioProfileVector.empty()) {
+        return NO_ERROR;
+    }
+
+    for (const auto& profile : audioProfileVector) {
+        if (checkExact(profile, samplingRate, channelMask, format) == NO_ERROR) {
+            return NO_ERROR;
+        }
+    }
+    return BAD_VALUE;
+}
+
+status_t checkCompatibleProfile(const AudioProfileVector &audioProfileVector,
+                                uint32_t &samplingRate,
+                                audio_channel_mask_t &channelMask,
+                                audio_format_t &format,
+                                audio_port_type_t portType,
+                                audio_port_role_t portRole)
+{
+    if (audioProfileVector.empty()) {
+        return NO_ERROR;
+    }
+
+    const bool checkInexact = // when port is input and format is linear pcm
+            portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
+            && audio_is_linear_pcm(format);
+
+    // iterate from best format to worst format (reverse order)
+    for (ssize_t i = audioProfileVector.size() - 1; i >= 0 ; --i) {
+        const sp<AudioProfile> profile = audioProfileVector.at(i);
+        audio_format_t formatToCompare = profile->getFormat();
+        if (formatToCompare == format ||
+                (checkInexact
+                        && formatToCompare != AUDIO_FORMAT_DEFAULT
+                        && audio_is_linear_pcm(formatToCompare))) {
+            // Compatible profile has been found, checks if this profile has compatible
+            // rate and channels as well
+            audio_channel_mask_t updatedChannels;
+            uint32_t updatedRate;
+            if (checkCompatibleChannelMask(profile, channelMask, updatedChannels,
+                                           portType, portRole) == NO_ERROR &&
+                    checkCompatibleSamplingRate(profile, samplingRate, updatedRate) == NO_ERROR) {
+                // for inexact checks we take the first linear pcm format due to sorting.
+                format = formatToCompare;
+                channelMask = updatedChannels;
+                samplingRate = updatedRate;
+                return NO_ERROR;
+            }
+        }
+    }
+    return BAD_VALUE;
+}
+
+// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
+// The result is ordered according to 'order'.
+template<typename T, typename Order>
+std::vector<typename T::value_type> intersectFilterAndOrder(
+        const T& input1, const T& input2, const Order& order)
+{
+    std::set<typename T::value_type> set1{input1.begin(), input1.end()};
+    std::set<typename T::value_type> set2{input2.begin(), input2.end()};
+    std::set<typename T::value_type> common;
+    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+            std::inserter(common, common.begin()));
+    std::vector<typename T::value_type> result;
+    for (const auto& e : order) {
+        if (common.find(e) != common.end()) result.push_back(e);
+    }
+    return result;
+}
+
+// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
+// 'comp' is a comparator function.
+template<typename T, typename Compare>
+std::vector<typename T::value_type> intersectAndOrder(
+        const T& input1, const T& input2, Compare comp)
+{
+    std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
+    std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
+    std::vector<typename T::value_type> result;
+    std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+            std::back_inserter(result), comp);
+    return result;
+}
+
+status_t findBestMatchingOutputConfig(
+        const AudioProfileVector &audioProfileVector,
+        const AudioProfileVector &outputProfileVector,
+        const std::vector<audio_format_t> &preferredFormatVector, // order: most pref -> least pref
+        const std::vector<audio_channel_mask_t> &preferredOutputChannelVector,
+        bool preferHigherSamplingRates,
+        audio_config_base &bestOutputConfig)
+{
+    auto formats = intersectFilterAndOrder(audioProfileVector.getSupportedFormats(),
+            outputProfileVector.getSupportedFormats(), preferredFormatVector);
+    // Pick the best compatible profile.
+    for (const auto& f : formats) {
+        sp<AudioProfile> inputProfile = audioProfileVector.getFirstValidProfileFor(f);
+        sp<AudioProfile> outputProfile = outputProfileVector.getFirstValidProfileFor(f);
+        if (inputProfile == nullptr || outputProfile == nullptr) {
+            continue;
+        }
+        auto channels = intersectFilterAndOrder(asOutMask(inputProfile->getChannels()),
+                outputProfile->getChannels(), preferredOutputChannelVector);
+        if (channels.empty()) {
+            continue;
+        }
+        auto sampleRates = preferHigherSamplingRates ?
+                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+                        std::greater<typename SampleRateSet::value_type>()) :
+                intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+                        std::less<typename SampleRateSet::value_type>());
+        if (sampleRates.empty()) {
+            continue;
+        }
+        ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
+                __func__, *channels.begin(), *sampleRates.begin(), f);
+        bestOutputConfig.format = f;
+        bestOutputConfig.sample_rate = *sampleRates.begin();
+        bestOutputConfig.channel_mask = *channels.begin();
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
index 79f0919..2a18f19 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -19,7 +19,6 @@
 
 #include "AudioRoute.h"
 #include "HwModule.h"
-#include "AudioGain.h"
 
 namespace android
 {
@@ -27,25 +26,26 @@
 void AudioRoute::dump(String8 *dst, int spaces) const
 {
     dst->appendFormat("%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
-    dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+    dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().c_str());
     if (mSources.size() != 0) {
         dst->appendFormat("%*s- Sources: \n", spaces, "");
         for (size_t i = 0; i < mSources.size(); i++) {
-            dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+            dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().c_str());
         }
     }
     dst->append("\n");
 }
 
-bool AudioRoute::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const
+bool AudioRoute::supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                               const sp<PolicyAudioPort> &dstPort) const
 {
     if (mSink == 0 || dstPort == 0 || dstPort != mSink) {
         return false;
     }
-    ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().string());
+    ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().c_str());
     for (const auto &sourcePort : mSources) {
         if (sourcePort == srcPort) {
-            ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().string());
+            ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().c_str());
             return true;
         }
     }
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index ad07ab1..1dc7020 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -21,7 +21,6 @@
 #include <utils/Log.h>
 #include <utils/String8.h>
 #include <TypeConverter.h>
-#include "AudioGain.h"
 #include "AudioOutputDescriptor.h"
 #include "AudioPatch.h"
 #include "ClientDescriptor.h"
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index ecd5b34..86dbba8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -22,52 +22,56 @@
 #include <set>
 #include "DeviceDescriptor.h"
 #include "TypeConverter.h"
-#include "AudioGain.h"
 #include "HwModule.h"
 
 namespace android {
 
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
-        DeviceDescriptor(type, FormatVector{}, tagName)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+        DeviceDescriptor(type, "" /*tagName*/)
 {
 }
 
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
-        const String8 &tagName) :
-    AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
-              audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
-                                             AUDIO_PORT_ROLE_SOURCE),
-    mTagName(tagName), mDeviceType(type), mEncodedFormats(encodedFormats)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+                                   const std::string &tagName,
+                                   const FormatVector &encodedFormats) :
+        DeviceDescriptor(type, tagName, "" /*address*/, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+                                   const std::string &tagName,
+                                   const std::string &address,
+                                   const FormatVector &encodedFormats) :
+        DeviceDescriptor(AudioDeviceTypeAddr(type, address), tagName, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr,
+                                   const std::string &tagName,
+                                   const FormatVector &encodedFormats) :
+        DeviceDescriptorBase(deviceTypeAddr), mTagName(tagName), mEncodedFormats(encodedFormats)
 {
     mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT;
-    if (audio_is_remote_submix_device(type)) {
-        mAddress = String8("0");
-    }
     /* If framework runs against a pre 5.0 Audio HAL, encoded formats are absent from the config.
      * FIXME: APM should know the version of the HAL and don't add the formats for V5.0.
      * For now, the workaround to remove AC3 and IEC61937 support on HDMI is to declare
      * something like 'encodedFormats="AUDIO_FORMAT_PCM_16_BIT"' on the HDMI devicePort.
      */
-    if (type == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.isEmpty()) {
-        mEncodedFormats.add(AUDIO_FORMAT_AC3);
-        mEncodedFormats.add(AUDIO_FORMAT_IEC61937);
+    if (mDeviceTypeAddr.mType == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.empty()) {
+        mEncodedFormats.push_back(AUDIO_FORMAT_AC3);
+        mEncodedFormats.push_back(AUDIO_FORMAT_IEC61937);
     }
 }
 
-audio_port_handle_t DeviceDescriptor::getId() const
-{
-    return mId;
-}
-
 void DeviceDescriptor::attach(const sp<HwModule>& module)
 {
-    AudioPort::attach(module);
+    PolicyAudioPort::attach(module);
     mId = getNextUniqueId();
 }
 
 void DeviceDescriptor::detach() {
     mId = AUDIO_PORT_HANDLE_NONE;
-    AudioPort::detach();
+    PolicyAudioPort::detach();
 }
 
 template<typename T>
@@ -88,7 +92,7 @@
         return false;
     }
 
-    return (mDeviceType == other->mDeviceType) && (mAddress == other->mAddress) &&
+    return mDeviceTypeAddr.equals(other->mDeviceTypeAddr) &&
            checkEqual(mEncodedFormats, other->mEncodedFormats);
 }
 
@@ -97,7 +101,7 @@
     if (!device_has_encoding_capability(type())) {
         return true;
     }
-    if (mEncodedFormats.isEmpty()) {
+    if (mEncodedFormats.empty()) {
         return true;
     }
 
@@ -106,7 +110,7 @@
 
 bool DeviceDescriptor::supportsFormat(audio_format_t format)
 {
-    if (mEncodedFormats.isEmpty()) {
+    if (mEncodedFormats.empty()) {
         return true;
     }
 
@@ -118,13 +122,69 @@
     return false;
 }
 
+status_t DeviceDescriptor::applyAudioPortConfig(const struct audio_port_config *config,
+                                                audio_port_config *backupConfig)
+{
+    struct audio_port_config localBackupConfig = { .config_mask = config->config_mask };
+    status_t status = NO_ERROR;
+
+    toAudioPortConfig(&localBackupConfig);
+    if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) {
+        AudioPortConfig::applyAudioPortConfig(config, backupConfig);
+        applyPolicyAudioPortConfig(config);
+    }
+
+    if (backupConfig != NULL) {
+        *backupConfig = localBackupConfig;
+    }
+    return status;
+}
+
+void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
+                                         const struct audio_port_config *srcConfig) const
+{
+    DeviceDescriptorBase::toAudioPortConfig(dstConfig, srcConfig);
+    toPolicyAudioPortConfig(dstConfig, srcConfig);
+
+    dstConfig->ext.device.hw_module = getModuleHandle();
+}
+
+void DeviceDescriptor::toAudioPort(struct audio_port *port) const
+{
+    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
+    DeviceDescriptorBase::toAudioPort(port);
+    port->ext.device.hw_module = getModuleHandle();
+}
+
+void DeviceDescriptor::importAudioPortAndPickAudioProfile(
+        const sp<PolicyAudioPort>& policyPort, bool force) {
+    if (!force && !policyPort->asAudioPort()->hasDynamicAudioProfile()) {
+        return;
+    }
+    AudioPort::importAudioPort(policyPort->asAudioPort());
+    policyPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
+}
+
+void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
+{
+    String8 extraInfo;
+    if (!mTagName.empty()) {
+        extraInfo.appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.c_str());
+    }
+
+    std::string descBaseDumpStr;
+    DeviceDescriptorBase::dump(&descBaseDumpStr, spaces, index, extraInfo.string(), verbose);
+    dst->append(descBaseDumpStr.c_str());
+}
+
+
 void DeviceVector::refreshTypes()
 {
-    mDeviceTypes = AUDIO_DEVICE_NONE;
+    mDeviceTypes.clear();
     for (size_t i = 0; i < size(); i++) {
-        mDeviceTypes |= itemAt(i)->type();
+        mDeviceTypes.insert(itemAt(i)->type());
     }
-    ALOGV("DeviceVector::refreshTypes() mDeviceTypes %08x", mDeviceTypes);
+    ALOGV("DeviceVector::refreshTypes() mDeviceTypes %s", dumpDeviceTypes(mDeviceTypes).c_str());
 }
 
 ssize_t DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
@@ -199,17 +259,6 @@
     return devices;
 }
 
-audio_devices_t DeviceVector::getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const
-{
-    audio_devices_t deviceTypes = AUDIO_DEVICE_NONE;
-    for (const auto& device : *this) {
-        if (device->getModuleHandle() == moduleHandle) {
-            deviceTypes |= device->type();
-        }
-    }
-    return deviceTypes;
-}
-
 sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address,
                                              audio_format_t format) const
 {
@@ -219,11 +268,11 @@
             // If format is specified, match it and ignore address
             // Otherwise if address is specified match it
             // Otherwise always match
-            if (((address == "" || itemAt(i)->address() == address) &&
+            if (((address == "" || (itemAt(i)->address().compare(address.c_str()) == 0)) &&
                  format == AUDIO_FORMAT_DEFAULT) ||
                 (itemAt(i)->supportsFormat(format) && format != AUDIO_FORMAT_DEFAULT)) {
                 device = itemAt(i);
-                if (itemAt(i)->address() == address) {
+                if (itemAt(i)->address().compare(address.c_str()) == 0) {
                     break;
                 }
             }
@@ -246,17 +295,15 @@
     return nullptr;
 }
 
-DeviceVector DeviceVector::getDevicesFromTypeMask(audio_devices_t type) const
+DeviceVector DeviceVector::getDevicesFromTypes(const DeviceTypeSet& types) const
 {
     DeviceVector devices;
-    bool isOutput = audio_is_output_devices(type);
-    type &= ~AUDIO_DEVICE_BIT_IN;
-    for (size_t i = 0; (i < size()) && (type != AUDIO_DEVICE_NONE); i++) {
-        bool curIsOutput = audio_is_output_devices(itemAt(i)->type());
-        audio_devices_t curType = itemAt(i)->type() & ~AUDIO_DEVICE_BIT_IN;
-        if ((isOutput == curIsOutput) && ((type & curType) != 0)) {
+    if (types.empty()) {
+        return devices;
+    }
+    for (size_t i = 0; i < size(); i++) {
+        if (types.count(itemAt(i)->type()) != 0) {
             devices.add(itemAt(i));
-            type &= ~curType;
             ALOGV("DeviceVector::%s() for type %08x found %p",
                     __func__, itemAt(i)->type(), itemAt(i).get());
         }
@@ -264,7 +311,7 @@
     return devices;
 }
 
-sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const std::string &tagName) const
 {
     for (const auto& device : *this) {
         if (device->getTagName() == tagName) {
@@ -274,6 +321,56 @@
     return nullptr;
 }
 
+DeviceVector DeviceVector::getFirstDevicesFromTypes(
+        std::vector<audio_devices_t> orderedTypes) const
+{
+    DeviceVector devices;
+    for (auto deviceType : orderedTypes) {
+        if (!(devices = getDevicesFromType(deviceType)).isEmpty()) {
+            break;
+        }
+    }
+    return devices;
+}
+
+sp<DeviceDescriptor> DeviceVector::getFirstExistingDevice(
+        std::vector<audio_devices_t> orderedTypes) const {
+    sp<DeviceDescriptor> device;
+    for (auto deviceType : orderedTypes) {
+        if ((device = getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT)) != nullptr) {
+            break;
+        }
+    }
+    return device;
+}
+
+sp<DeviceDescriptor> DeviceVector::getDeviceForOpening() const
+{
+    if (isEmpty()) {
+        // Return nullptr if this collection is empty.
+        return nullptr;
+    } else if (areAllOfSameDeviceType(types(), audio_is_input_device)) {
+        // For input case, return the first one when there is only one device.
+        return size() > 1 ? nullptr : *begin();
+    } else if (areAllOfSameDeviceType(types(), audio_is_output_device)) {
+        // For output case, return the device descriptor according to apm strategy.
+        audio_devices_t deviceType = apm_extract_one_audio_device(types());
+        return deviceType == AUDIO_DEVICE_NONE ? nullptr :
+                getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT);
+    }
+    // Return null pointer if the devices are not all input/output device.
+    return nullptr;
+}
+
+void DeviceVector::replaceDevicesByType(
+        audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) {
+    DeviceVector devicesToRemove = getDevicesFromType(typeToRemove);
+    if (!devicesToRemove.isEmpty() && !devicesToAdd.isEmpty()) {
+        remove(devicesToRemove);
+        add(devicesToAdd);
+    }
+}
+
 void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const
 {
     if (isEmpty()) {
@@ -285,84 +382,6 @@
     }
 }
 
-void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
-                                         const struct audio_port_config *srcConfig) const
-{
-    dstConfig->config_mask = AUDIO_PORT_CONFIG_GAIN;
-    if (mSamplingRate != 0) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
-    }
-    if (mChannelMask != AUDIO_CHANNEL_NONE) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
-    }
-    if (mFormat != AUDIO_FORMAT_INVALID) {
-        dstConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
-    }
-
-    if (srcConfig != NULL) {
-        dstConfig->config_mask |= srcConfig->config_mask;
-    }
-
-    AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
-
-    dstConfig->id = mId;
-    dstConfig->role = audio_is_output_device(mDeviceType) ?
-                        AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
-    dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
-    dstConfig->ext.device.type = mDeviceType;
-
-    //TODO Understand why this test is necessary. i.e. why at boot time does it crash
-    // without the test?
-    // This has been demonstrated to NOT be true (at start up)
-    // ALOG_ASSERT(mModule != NULL);
-    dstConfig->ext.device.hw_module = getModuleHandle();
-    (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mAddress.string());
-}
-
-void DeviceDescriptor::toAudioPort(struct audio_port *port) const
-{
-    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceType);
-    AudioPort::toAudioPort(port);
-    port->id = mId;
-    toAudioPortConfig(&port->active_config);
-    port->ext.device.type = mDeviceType;
-    port->ext.device.hw_module = getModuleHandle();
-    (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mAddress.string());
-}
-
-void DeviceDescriptor::importAudioPort(const sp<AudioPort>& port, bool force) {
-    if (!force && !port->hasDynamicAudioProfile()) {
-        return;
-    }
-    AudioPort::importAudioPort(port);
-    port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
-}
-
-void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
-{
-    dst->appendFormat("%*sDevice %d:\n", spaces, "", index + 1);
-    if (mId != 0) {
-        dst->appendFormat("%*s- id: %2d\n", spaces, "", mId);
-    }
-    if (!mTagName.isEmpty()) {
-        dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
-    }
-
-    dst->appendFormat("%*s- type: %-48s\n", spaces, "", ::android::toString(mDeviceType).c_str());
-
-    if (mAddress.size() != 0) {
-        dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
-    }
-    AudioPort::dump(dst, spaces, verbose);
-}
-
-std::string DeviceDescriptor::toString() const
-{
-    std::stringstream sstream;
-    sstream << "type:0x" << std::hex << type() << ",@:" << mAddress;
-    return sstream.str();
-}
-
 std::string DeviceVector::toString() const
 {
     if (isEmpty()) {
@@ -411,13 +430,4 @@
     return filteredDevices;
 }
 
-void DeviceDescriptor::log() const
-{
-    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceType,
-          ::android::toString(mDeviceType).c_str(),
-          mAddress.string());
-
-    AudioPort::log("  ");
-}
-
 } // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 1f9b725..886e4c9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -19,7 +19,6 @@
 
 #include "HwModule.h"
 #include "IOProfile.h"
-#include "AudioGain.h"
 #include <policy.h>
 #include <system/audio.h>
 
@@ -42,7 +41,7 @@
     }
 }
 
-status_t HwModule::addOutputProfile(const String8& name, const audio_config_t *config,
+status_t HwModule::addOutputProfile(const std::string& name, const audio_config_t *config,
                                     audio_devices_t device, const String8& address)
 {
     sp<IOProfile> profile = new OutputProfile(name);
@@ -50,8 +49,7 @@
     profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
                                               config->sample_rate));
 
-    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
-    devDesc->setAddress(address);
+    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
     addDynamicDevice(devDesc);
     // Reciprocally attach the device to the module
     devDesc->attach(this);
@@ -96,7 +94,7 @@
     }
 }
 
-status_t HwModule::removeOutputProfile(const String8& name)
+status_t HwModule::removeOutputProfile(const std::string& name)
 {
     for (size_t i = 0; i < mOutputProfiles.size(); i++) {
         if (mOutputProfiles[i]->getName() == name) {
@@ -111,27 +109,26 @@
     return NO_ERROR;
 }
 
-status_t HwModule::addInputProfile(const String8& name, const audio_config_t *config,
+status_t HwModule::addInputProfile(const std::string& name, const audio_config_t *config,
                                    audio_devices_t device, const String8& address)
 {
     sp<IOProfile> profile = new InputProfile(name);
     profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
                                               config->sample_rate));
 
-    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
-    devDesc->setAddress(address);
+    sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
     addDynamicDevice(devDesc);
     // Reciprocally attach the device to the module
     devDesc->attach(this);
     profile->addSupportedDevice(devDesc);
 
     ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
-          name.string(), config->sample_rate, config->channel_mask);
+          name.c_str(), config->sample_rate, config->channel_mask);
 
     return addInputProfile(profile);
 }
 
-status_t HwModule::removeInputProfile(const String8& name)
+status_t HwModule::removeInputProfile(const std::string& name)
 {
     for (size_t i = 0; i < mInputProfiles.size(); i++) {
         if (mInputProfiles[i]->getName() == name) {
@@ -157,7 +154,7 @@
 sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
 {
     sp<DeviceDescriptor> sinkDevice = 0;
-    if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+    if (route->getSink()->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
         sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
     }
     return sinkDevice;
@@ -167,7 +164,7 @@
 {
     DeviceVector sourceDevices;
     for (const auto& source : route->getSources()) {
-        if (source->getType() == AUDIO_PORT_TYPE_DEVICE) {
+        if (source->asAudioPort()->getType() == AUDIO_PORT_TYPE_DEVICE) {
             sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(source->getTagName()));
         }
     }
@@ -187,20 +184,20 @@
     for (const auto& stream : mInputProfiles) {
         DeviceVector sourceDevices;
         for (const auto& route : stream->getRoutes()) {
-            sp<AudioPort> sink = route->getSink();
+            sp<PolicyAudioPort> sink = route->getSink();
             if (sink == 0 || stream != sink) {
                 ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
                 continue;
             }
             DeviceVector sourceDevicesForRoute = getRouteSourceDevices(route);
             if (sourceDevicesForRoute.isEmpty()) {
-                ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+                ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
                 continue;
             }
             sourceDevices.add(sourceDevicesForRoute);
         }
         if (sourceDevices.isEmpty()) {
-            ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+            ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().c_str());
             continue;
         }
         stream->setSupportedDevices(sourceDevices);
@@ -208,14 +205,14 @@
     for (const auto& stream : mOutputProfiles) {
         DeviceVector sinkDevices;
         for (const auto& route : stream->getRoutes()) {
-            sp<AudioPort> source = route->getSources().findByTagName(stream->getTagName());
+            sp<PolicyAudioPort> source = findByTagName(route->getSources(), stream->getTagName());
             if (source == 0 || stream != source) {
                 ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
                 continue;
             }
             sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(route);
             if (sinkDevice == 0) {
-                ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+                ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().c_str());
                 continue;
             }
             sinkDevices.add(sinkDevice);
@@ -230,7 +227,8 @@
     mHandle = handle;
 }
 
-bool HwModule::supportsPatch(const sp<AudioPort> &srcPort, const sp<AudioPort> &dstPort) const {
+bool HwModule::supportsPatch(const sp<PolicyAudioPort> &srcPort,
+                             const sp<PolicyAudioPort> &dstPort) const {
     for (const auto &route : mRoutes) {
         if (route->supportsPatch(srcPort, dstPort)) {
             return true;
@@ -260,7 +258,7 @@
     }
     mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
     mDynamicDevices.dump(dst, String8("Dynamic"),  2, true);
-    mRoutes.dump(dst, 2);
+    dumpAudioRouteVector(mRoutes, dst, 2);
 }
 
 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -273,14 +271,14 @@
     return nullptr;
 }
 
-sp <HwModule> HwModuleCollection::getModuleForDeviceTypes(audio_devices_t type,
-                                                          audio_format_t encodedFormat) const
+sp <HwModule> HwModuleCollection::getModuleForDeviceType(audio_devices_t type,
+                                                         audio_format_t encodedFormat) const
 {
     for (const auto& module : *this) {
         const auto& profiles = audio_is_output_device(type) ?
                 module->getOutputProfiles() : module->getInputProfiles();
         for (const auto& profile : profiles) {
-            if (profile->supportsDeviceTypes(type)) {
+            if (profile->supportsDeviceTypes({type})) {
                 if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
                     DeviceVector declaredDevices = module->getDeclaredDevices();
                     sp <DeviceDescriptor> deviceDesc =
@@ -300,7 +298,7 @@
 sp<HwModule> HwModuleCollection::getModuleForDevice(const sp<DeviceDescriptor> &device,
                                                      audio_format_t encodedFormat) const
 {
-    return getModuleForDeviceTypes(device->type(), encodedFormat);
+    return getModuleForDeviceType(device->type(), encodedFormat);
 }
 
 DeviceVector HwModuleCollection::getAvailableDevicesFromModuleName(
@@ -335,8 +333,8 @@
             }
             if (allowToCreate) {
                 moduleDevice->attach(hwModule);
-                moduleDevice->setAddress(devAddress);
-                moduleDevice->setName(String8(name));
+                moduleDevice->setAddress(devAddress.string());
+                moduleDevice->setName(name);
             }
             return moduleDevice;
         }
@@ -354,15 +352,15 @@
                                                       const char *name,
                                                       const audio_format_t encodedFormat) const
 {
-    sp<HwModule> hwModule = getModuleForDeviceTypes(type, encodedFormat);
+    sp<HwModule> hwModule = getModuleForDeviceType(type, encodedFormat);
     if (hwModule == 0) {
         ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
               address);
         return nullptr;
     }
-    sp<DeviceDescriptor> device = new DeviceDescriptor(type, String8(name));
-    device->setName(String8(name));
-    device->setAddress(String8(address));
+
+    sp<DeviceDescriptor> device = new DeviceDescriptor(type, name, address);
+    device->setName(name);
     device->setEncodedFormat(encodedFormat);
 
   // Add the device to the list of dynamic devices
@@ -382,7 +380,7 @@
             // @todo quid of audio profile? import the profile from device of the same type?
             const auto &isoTypeDeviceForProfile =
                 profile->getSupportedDevices().getDevice(type, String8(), AUDIO_FORMAT_DEFAULT);
-            device->importAudioPort(isoTypeDeviceForProfile, true /* force */);
+            device->importAudioPortAndPickAudioProfile(isoTypeDeviceForProfile, true /* force */);
 
             ALOGV("%s: adding device %s to profile %s", __FUNCTION__,
                   device->toString().c_str(), profile->getTagName().c_str());
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index f755fcd..bf1a0f7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,7 +20,6 @@
 #include <system/audio-base.h>
 #include "IOProfile.h"
 #include "HwModule.h"
-#include "AudioGain.h"
 #include "TypeConverter.h"
 
 namespace android {
@@ -108,7 +107,9 @@
 
 void IOProfile::dump(String8 *dst) const
 {
-    AudioPort::dump(dst, 4);
+    std::string portStr;
+    AudioPort::dump(&portStr, 4);
+    dst->append(portStr.c_str());
 
     dst->appendFormat("    - flags: 0x%04x", getFlags());
     std::string flagsLiteral;
diff --git a/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
new file mode 100644
index 0000000..8c61b90
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/PolicyAudioPort.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::PolicyAudioPort"
+//#define LOG_NDEBUG 0
+#include "TypeConverter.h"
+#include "PolicyAudioPort.h"
+#include "HwModule.h"
+#include <policy.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+namespace android {
+
+// --- PolicyAudioPort class implementation
+void PolicyAudioPort::attach(const sp<HwModule>& module)
+{
+    ALOGV("%s: attaching module %s to port %s",
+            __FUNCTION__, getModuleName(), asAudioPort()->getName().c_str());
+    mModule = module;
+}
+
+void PolicyAudioPort::detach()
+{
+    mModule = nullptr;
+}
+
+// Note that is a different namespace than AudioFlinger unique IDs
+audio_port_handle_t PolicyAudioPort::getNextUniqueId()
+{
+    return getNextHandle();
+}
+
+audio_module_handle_t PolicyAudioPort::getModuleHandle() const
+{
+    return mModule != 0 ? mModule->getHandle() : AUDIO_MODULE_HANDLE_NONE;
+}
+
+uint32_t PolicyAudioPort::getModuleVersionMajor() const
+{
+    return mModule != 0 ? mModule->getHalVersionMajor() : 0;
+}
+
+const char *PolicyAudioPort::getModuleName() const
+{
+    return mModule != 0 ? mModule->getName() : "invalid module";
+}
+
+status_t PolicyAudioPort::checkExactAudioProfile(const struct audio_port_config *config) const
+{
+    status_t status = NO_ERROR;
+    auto config_mask = config->config_mask;
+    if (config_mask & AUDIO_PORT_CONFIG_GAIN) {
+        config_mask &= ~AUDIO_PORT_CONFIG_GAIN;
+        status = asAudioPort()->checkGain(&config->gain, config->gain.index);
+        if (status != NO_ERROR) {
+            return status;
+        }
+    }
+    if (config_mask != 0) {
+        // TODO should we check sample_rate / channel_mask / format separately?
+        status = checkExactProfile(asAudioPort()->getAudioProfiles(), config->sample_rate,
+                config->channel_mask, config->format);
+    }
+    return status;
+}
+
+void PolicyAudioPort::pickSamplingRate(uint32_t &pickedRate,
+                                       const SampleRateSet &samplingRates) const
+{
+    pickedRate = 0;
+    // For direct outputs, pick minimum sampling rate: this helps ensuring that the
+    // channel count / sampling rate combination chosen will be supported by the connected
+    // sink
+    if (isDirectOutput()) {
+        uint32_t samplingRate = UINT_MAX;
+        for (const auto rate : samplingRates) {
+            if ((rate < samplingRate) && (rate > 0)) {
+                samplingRate = rate;
+            }
+        }
+        pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+    } else {
+        uint32_t maxRate = SAMPLE_RATE_HZ_MAX;
+
+        // For mixed output and inputs, use max mixer sampling rates. Do not
+        // limit sampling rate otherwise
+        // For inputs, also see checkCompatibleSamplingRate().
+        if (asAudioPort()->getType() == AUDIO_PORT_TYPE_MIX) {
+            maxRate = UINT_MAX;
+        }
+        // TODO: should mSamplingRates[] be ordered in terms of our preference
+        // and we return the first (and hence most preferred) match?  This is of concern if
+        // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+        for (const auto rate : samplingRates) {
+            if ((rate > pickedRate) && (rate <= maxRate)) {
+                pickedRate = rate;
+            }
+        }
+    }
+}
+
+void PolicyAudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+                                      const ChannelMaskSet &channelMasks) const
+{
+    pickedChannelMask = AUDIO_CHANNEL_NONE;
+    // For direct outputs, pick minimum channel count: this helps ensuring that the
+    // channel count / sampling rate combination chosen will be supported by the connected
+    // sink
+    if (isDirectOutput()) {
+        uint32_t channelCount = UINT_MAX;
+        for (const auto channelMask : channelMasks) {
+            uint32_t cnlCount;
+            if (asAudioPort()->useInputChannelMask()) {
+                cnlCount = audio_channel_count_from_in_mask(channelMask);
+            } else {
+                cnlCount = audio_channel_count_from_out_mask(channelMask);
+            }
+            if ((cnlCount < channelCount) && (cnlCount > 0)) {
+                pickedChannelMask = channelMask;
+                channelCount = cnlCount;
+            }
+        }
+    } else {
+        uint32_t channelCount = 0;
+        uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
+
+        // For mixed output and inputs, use max mixer channel count. Do not
+        // limit channel count otherwise
+        if (asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) {
+            maxCount = UINT_MAX;
+        }
+        for (const auto channelMask : channelMasks) {
+            uint32_t cnlCount;
+            if (asAudioPort()->useInputChannelMask()) {
+                cnlCount = audio_channel_count_from_in_mask(channelMask);
+            } else {
+                cnlCount = audio_channel_count_from_out_mask(channelMask);
+            }
+            if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+                pickedChannelMask = channelMask;
+                channelCount = cnlCount;
+            }
+        }
+    }
+}
+
+/* format in order of increasing preference */
+const audio_format_t PolicyAudioPort::sPcmFormatCompareTable[] = {
+        AUDIO_FORMAT_DEFAULT,
+        AUDIO_FORMAT_PCM_16_BIT,
+        AUDIO_FORMAT_PCM_8_24_BIT,
+        AUDIO_FORMAT_PCM_24_BIT_PACKED,
+        AUDIO_FORMAT_PCM_32_BIT,
+        AUDIO_FORMAT_PCM_FLOAT,
+};
+
+int PolicyAudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
+{
+    // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
+    // compressed format and better than any PCM format. This is by design of pickFormat()
+    if (!audio_is_linear_pcm(format1)) {
+        if (!audio_is_linear_pcm(format2)) {
+            return 0;
+        }
+        return 1;
+    }
+    if (!audio_is_linear_pcm(format2)) {
+        return -1;
+    }
+
+    int index1 = -1, index2 = -1;
+    for (size_t i = 0;
+            (i < ARRAY_SIZE(sPcmFormatCompareTable)) && ((index1 == -1) || (index2 == -1));
+            i ++) {
+        if (sPcmFormatCompareTable[i] == format1) {
+            index1 = i;
+        }
+        if (sPcmFormatCompareTable[i] == format2) {
+            index2 = i;
+        }
+    }
+    // format1 not found => index1 < 0 => format2 > format1
+    // format2 not found => index2 < 0 => format2 < format1
+    return index1 - index2;
+}
+
+uint32_t PolicyAudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
+{
+    if (format1 == format2) {
+        return 0;
+    }
+    if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
+        return kFormatDistanceMax;
+    }
+    int diffBytes = (int)audio_bytes_per_sample(format1) -
+            audio_bytes_per_sample(format2);
+
+    return abs(diffBytes);
+}
+
+bool PolicyAudioPort::isBetterFormatMatch(audio_format_t newFormat,
+                                          audio_format_t currentFormat,
+                                          audio_format_t targetFormat)
+{
+    return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
+}
+
+void PolicyAudioPort::pickAudioProfile(uint32_t &samplingRate,
+                                       audio_channel_mask_t &channelMask,
+                                       audio_format_t &format) const
+{
+    format = AUDIO_FORMAT_DEFAULT;
+    samplingRate = 0;
+    channelMask = AUDIO_CHANNEL_NONE;
+
+    // special case for uninitialized dynamic profile
+    if (!asAudioPort()->hasValidAudioProfile()) {
+        return;
+    }
+    audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+    // For mixed output and inputs, use best mixer output format.
+    // Do not limit format otherwise
+    if ((asAudioPort()->getType() != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
+        bestFormat = AUDIO_FORMAT_INVALID;
+    }
+
+    const AudioProfileVector& audioProfiles = asAudioPort()->getAudioProfiles();
+    for (size_t i = 0; i < audioProfiles.size(); i ++) {
+        if (!audioProfiles[i]->isValid()) {
+            continue;
+        }
+        audio_format_t formatToCompare = audioProfiles[i]->getFormat();
+        if ((compareFormats(formatToCompare, format) > 0) &&
+                (compareFormats(formatToCompare, bestFormat) <= 0)) {
+            uint32_t pickedSamplingRate = 0;
+            audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+            pickChannelMask(pickedChannelMask, audioProfiles[i]->getChannels());
+            pickSamplingRate(pickedSamplingRate, audioProfiles[i]->getSampleRates());
+
+            if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+                    && pickedSamplingRate != 0) {
+                format = formatToCompare;
+                channelMask = pickedChannelMask;
+                samplingRate = pickedSamplingRate;
+                // TODO: shall we return on the first one or still trying to pick a better Profile?
+            }
+        }
+    }
+    ALOGV("%s Port[nm:%s] profile rate=%d, format=%d, channels=%d", __FUNCTION__,
+            asAudioPort()->getName().c_str(), samplingRate, channelMask, format);
+}
+
+// --- PolicyAudioPortConfig class implementation
+
+status_t PolicyAudioPortConfig::validationBeforeApplyConfig(
+        const struct audio_port_config *config) const
+{
+    sp<PolicyAudioPort> policyAudioPort = getPolicyAudioPort();
+    return policyAudioPort ? policyAudioPort->checkExactAudioProfile(config) : NO_INIT;
+}
+
+void PolicyAudioPortConfig::toPolicyAudioPortConfig(struct audio_port_config *dstConfig,
+                                                    const struct audio_port_config *srcConfig) const
+{
+    if (dstConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+        if ((srcConfig != nullptr) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_FLAGS)) {
+            dstConfig->flags = srcConfig->flags;
+        } else {
+            dstConfig->flags = mFlags;
+        }
+    } else {
+        dstConfig->flags = { AUDIO_INPUT_FLAG_NONE };
+    }
+}
+
+
+
+} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 5f820c2..4376802 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -199,6 +199,7 @@
     struct Attributes
     {
         static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
+        static constexpr const char *callScreenModeSupported= "call_screen_mode_supported";
     };
 
     static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
@@ -406,8 +407,8 @@
             samplingRatesFromString(samplingRates, ","));
 
     profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
-    profile->setDynamicChannels(profile->getChannels().isEmpty());
-    profile->setDynamicRate(profile->getSampleRates().isEmpty());
+    profile->setDynamicChannels(profile->getChannels().empty());
+    profile->setDynamicRate(profile->getSampleRates().empty());
 
     return profile;
 }
@@ -430,16 +431,19 @@
     audio_port_role_t portRole = (role == Attributes::roleSource) ?
             AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
 
-    Element mixPort = new IOProfile(String8(name.c_str()), portRole);
+    Element mixPort = new IOProfile(name, portRole);
 
     AudioProfileTraits::Collection profiles;
     status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
     if (status != NO_ERROR) {
         return Status::fromStatusT(status);
     }
-    if (profiles.isEmpty()) {
-        profiles.add(AudioProfile::createFullDynamic());
+    if (profiles.empty()) {
+        profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
     }
+    // The audio profiles are in order of listed in audio policy configuration file.
+    // Sort audio profiles accroding to the format.
+    sortAudioProfiles(profiles);
     mixPort->setAudioProfiles(profiles);
 
     std::string flags = getXmlAttribute(child, Attributes::flags);
@@ -508,22 +512,20 @@
     if (!encodedFormatsLiteral.empty()) {
         encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
     }
-    Element deviceDesc = new DeviceDescriptor(type, encodedFormats, String8(name.c_str()));
-
     std::string address = getXmlAttribute(cur, Attributes::address);
-    if (!address.empty()) {
-        ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
-        deviceDesc->setAddress(String8(address.c_str()));
-    }
+    Element deviceDesc = new DeviceDescriptor(type, name, address, encodedFormats);
 
     AudioProfileTraits::Collection profiles;
     status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
     if (status != NO_ERROR) {
         return Status::fromStatusT(status);
     }
-    if (profiles.isEmpty()) {
-        profiles.add(AudioProfile::createFullDynamic());
+    if (profiles.empty()) {
+        profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
     }
+    // The audio profiles are in order of listed in audio policy configuration file.
+    // Sort audio profiles accroding to the format.
+    sortAudioProfiles(profiles);
     deviceDesc->setAudioProfiles(profiles);
 
     // Deserialize AudioGain children
@@ -532,7 +534,7 @@
         return Status::fromStatusT(status);
     }
     ALOGV("%s: adding device tag %s type %08x address %s", __func__,
-          deviceDesc->getName().string(), type, deviceDesc->address().string());
+          deviceDesc->getName().c_str(), type, deviceDesc->address().c_str());
     return deviceDesc;
 }
 
@@ -555,7 +557,7 @@
         return Status::fromStatusT(BAD_VALUE);
     }
     // Convert Sink name to port pointer
-    sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
+    sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
     if (sink == NULL) {
         ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
         return Status::fromStatusT(BAD_VALUE);
@@ -568,13 +570,13 @@
         return Status::fromStatusT(BAD_VALUE);
     }
     // Tokenize and Convert Sources name to port pointer
-    AudioPortVector sources;
+    PolicyAudioPortVector sources;
     std::unique_ptr<char[]> sourcesLiteral{strndup(
                 sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
     char *devTag = strtok(sourcesLiteral.get(), ",");
     while (devTag != NULL) {
         if (strlen(devTag) != 0) {
-            sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
+            sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
             if (source == NULL) {
                 ALOGE("%s: no source found with name=%s", __func__, devTag);
                 return Status::fromStatusT(BAD_VALUE);
@@ -586,7 +588,7 @@
 
     sink->addRoute(route);
     for (size_t i = 0; i < sources.size(); i++) {
-        sp<AudioPort> source = sources.itemAt(i);
+        sp<PolicyAudioPort> source = sources.itemAt(i);
         source->addRoute(route);
     }
     route->setSources(sources);
@@ -648,7 +650,7 @@
                         ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
                                 reinterpret_cast<const char*>(attachedDevice.get()));
                         sp<DeviceDescriptor> device = module->getDeclaredDevices().
-                                getDeviceFromTagName(String8(reinterpret_cast<const char*>(
+                                getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
                                                         attachedDevice.get())));
                         ctx->addAvailableDevice(device);
                     }
@@ -663,7 +665,7 @@
                 ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
                         reinterpret_cast<const char*>(defaultOutputDevice.get()));
                 sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
-                        String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
+                        std::string(reinterpret_cast<const char*>(defaultOutputDevice.get())));
                 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                     ctx->setDefaultOutputDevice(device);
                     ALOGV("%s: default is %08x",
@@ -679,14 +681,17 @@
 {
     for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
         if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
-            std::string speakerDrcEnabled =
-                    getXmlAttribute(cur, Attributes::speakerDrcEnabled);
-            bool isSpeakerDrcEnabled;
-            if (!speakerDrcEnabled.empty() &&
-                    convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
-                config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+            bool value;
+            std::string attr = getXmlAttribute(cur, Attributes::speakerDrcEnabled);
+            if (!attr.empty() &&
+                    convertTo<std::string, bool>(attr, value)) {
+                config->setSpeakerDrcEnabled(value);
             }
-            return NO_ERROR;
+            attr = getXmlAttribute(cur, Attributes::callScreenModeSupported);
+            if (!attr.empty() &&
+                    convertTo<std::string, bool>(attr, value)) {
+                config->setCallScreenModeSupported(value);
+            }
         }
     }
     return NO_ERROR;
diff --git a/services/audiopolicy/config/audio_policy_volumes.xml b/services/audiopolicy/config/audio_policy_volumes.xml
index ec64a7c..27bd3ff 100644
--- a/services/audiopolicy/config/audio_policy_volumes.xml
+++ b/services/audiopolicy/config/audio_policy_volumes.xml
@@ -44,7 +44,7 @@
     <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
                                              ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
     <volume stream="AUDIO_STREAM_VOICE_CALL" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
-                                             ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+                                             ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
     <volume stream="AUDIO_STREAM_SYSTEM" deviceCategory="DEVICE_CATEGORY_HEADSET">
         <point>1,-3000</point>
         <point>33,-2600</point>
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index d0775ad..b87c71d 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -44,4 +44,7 @@
         "libaudiopolicycomponents",
         "libaudiopolicyengine_config",
     ],
+    shared_libs: [
+        "libaudiofoundation",
+    ],
 }
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index c538f52..ab8eff3 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -27,6 +27,7 @@
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <media/AudioAttributes.h>
+#include <media/AudioContainers.h>
 
 namespace android {
 
@@ -77,12 +78,12 @@
 
     std::string getDeviceAddress() const { return mDeviceAddress; }
 
-    void setDeviceTypes(audio_devices_t devices)
+    void setDeviceTypes(const DeviceTypeSet& devices)
     {
         mApplicableDevices = devices;
     }
 
-    audio_devices_t getDeviceTypes() const { return mApplicableDevices; }
+    DeviceTypeSet getDeviceTypes() const { return mApplicableDevices; }
 
     audio_attributes_t getAttributesForStreamType(audio_stream_type_t stream) const;
     audio_stream_type_t getStreamTypeForAttributes(const audio_attributes_t &attr) const;
@@ -109,7 +110,7 @@
     /**
      * Applicable device(s) type mask for this strategy.
      */
-    audio_devices_t mApplicableDevices = AUDIO_DEVICE_NONE;
+    DeviceTypeSet mApplicableDevices;
 };
 
 class ProductStrategyMap : public std::map<product_strategy_t, sp<ProductStrategy> >
@@ -144,7 +145,7 @@
      */
     audio_attributes_t getAttributesForProductStrategy(product_strategy_t strategy) const;
 
-    audio_devices_t getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
+    DeviceTypeSet getDeviceTypesForProductStrategy(product_strategy_t strategy) const;
 
     std::string getDeviceAddressForProductStrategy(product_strategy_t strategy) const;
 
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index d3d0904..2e75ff1 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -91,9 +91,9 @@
         return valueFor(device);
     }
 
-    virtual int getVolumeIndex(audio_devices_t device) const
+    virtual int getVolumeIndex(const DeviceTypeSet& deviceTypes) const
     {
-        device = Volume::getDeviceForVolume(device);
+        audio_devices_t device = Volume::getDeviceForVolume(deviceTypes);
         // there is always a valid entry for AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME
         if (mIndexCur.find(device) == end(mIndexCur)) {
             device = AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME;
@@ -114,7 +114,7 @@
 
     bool hasVolumeIndexForDevice(audio_devices_t device) const
     {
-        device = Volume::getDeviceForVolume(device);
+        device = Volume::getDeviceForVolume({device});
         return mIndexCur.find(device) != end(mIndexCur);
     }
 
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index ac3e462..14c9dd1 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -143,8 +143,9 @@
 {
     dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
     std::string deviceLiteral;
-    if (!OutputDeviceConverter::toString(mApplicableDevices, deviceLiteral)) {
-        ALOGE("%s: failed to convert device %d", __FUNCTION__, mApplicableDevices);
+    if (!deviceTypesToString(mApplicableDevices, deviceLiteral)) {
+        ALOGE("%s: failed to convert device %s",
+              __FUNCTION__, dumpDeviceTypes(mApplicableDevices).c_str());
     }
     dst->appendFormat("%*sSelected Device: {type:%s, @:%s}\n", spaces + 2, "",
                        deviceLiteral.c_str(), mDeviceAddress.c_str());
@@ -236,14 +237,14 @@
 }
 
 
-audio_devices_t ProductStrategyMap::getDeviceTypesForProductStrategy(
+DeviceTypeSet ProductStrategyMap::getDeviceTypesForProductStrategy(
         product_strategy_t strategy) const
 {
     if (find(strategy) == end()) {
         ALOGE("Invalid %d strategy requested, returning device for default strategy", strategy);
         product_strategy_t defaultStrategy = getDefault();
         if (defaultStrategy == PRODUCT_STRATEGY_NONE) {
-            return AUDIO_DEVICE_NONE;
+            return {AUDIO_DEVICE_NONE};
         }
         return at(getDefault())->getDeviceTypes();
     }
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
index ebd82a7..349f969 100644
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerObserver.h
@@ -16,8 +16,7 @@
 
 #pragma once
 
-#include <AudioGain.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <AudioPatch.h>
 #include <IOProfile.h>
 #include <DeviceDescriptor.h>
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index c27dc88..8f522f0 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -33,6 +33,7 @@
 
     ],
     shared_libs: [
+        "libaudiofoundation",
         "liblog",
         "libcutils",
         "libutils",
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 3987294..0a88685 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -32,6 +32,7 @@
 #include <policy.h>
 #include <AudioIODescriptorInterface.h>
 #include <ParameterManagerWrapper.h>
+#include <media/AudioContainers.h>
 
 #include <media/TypeConverter.h>
 
@@ -167,11 +168,13 @@
     mPolicyParameterMgr->setDeviceConnectionState(devDesc, state);
 
     if (audio_is_output_device(devDesc->type())) {
+        // FIXME: Use DeviceTypeSet when the interface is ready
         return mPolicyParameterMgr->setAvailableOutputDevices(
-                    getApmObserver()->getAvailableOutputDevices().types());
+                    deviceTypesToBitMask(getApmObserver()->getAvailableOutputDevices().types()));
     } else if (audio_is_input_device(devDesc->type())) {
+        // FIXME: Use DeviceTypeSet when the interface is ready
         return mPolicyParameterMgr->setAvailableInputDevices(
-                    getApmObserver()->getAvailableInputDevices().types());
+                    deviceTypesToBitMask(getApmObserver()->getAvailableInputDevices().types()));
     }
     return BAD_TYPE;
 }
@@ -211,7 +214,7 @@
     }
     const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
-    uint32_t availableOutputDevicesType = availableOutputDevices.types();
+    DeviceTypeSet availableOutputDevicesTypes = availableOutputDevices.types();
 
     /** This is the only case handled programmatically because the PFW is unable to know the
      * activity of streams.
@@ -223,7 +226,7 @@
      *
      * -When media is not playing anymore, fall back on the sonification behavior
      */
-    audio_devices_t devices = AUDIO_DEVICE_NONE;
+    DeviceTypeSet deviceTypes;
     if (ps == getProductStrategyForStream(AUDIO_STREAM_NOTIFICATION) &&
             !is_state_in_call(getPhoneState()) &&
             !outputs.isActiveRemotely(toVolumeSource(AUDIO_STREAM_MUSIC),
@@ -232,7 +235,7 @@
                              SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
         product_strategy_t strategyForMedia =
                 getProductStrategyForStream(AUDIO_STREAM_MUSIC);
-        devices = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
+        deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyForMedia);
     } else if (ps == getProductStrategyForStream(AUDIO_STREAM_ACCESSIBILITY) &&
         (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
          outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM)))) {
@@ -240,36 +243,37 @@
             // compressed format as they would likely not be mixed and dropped.
             // Device For Sonification conf file has HDMI, SPDIF and HDMI ARC unreacheable.
         product_strategy_t strategyNotification = getProductStrategyForStream(AUDIO_STREAM_RING);
-        devices = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
+        deviceTypes = productStrategies.getDeviceTypesForProductStrategy(strategyNotification);
     } else {
-        devices = productStrategies.getDeviceTypesForProductStrategy(ps);
+        deviceTypes = productStrategies.getDeviceTypesForProductStrategy(ps);
     }
-    if (devices == AUDIO_DEVICE_NONE ||
-            (devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
+    if (deviceTypes.empty() ||
+            Intersection(deviceTypes, availableOutputDevicesTypes).empty()) {
         auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
         ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
         return DeviceVector(defaultDevice);
     }
-    if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
+    if (/*device_distinguishes_on_address(*deviceTypes.begin())*/ isSingleDeviceType(
+            deviceTypes, AUDIO_DEVICE_OUT_BUS)) {
         // We do expect only one device for these types of devices
         // Criterion device address garantee this one is available
         // If this criterion is not wished, need to ensure this device is available
         const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
-        ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
-        auto busDevice = availableOutputDevices.getDevice(devices, address, AUDIO_FORMAT_DEFAULT);
+        ALOGV("%s:device %s %s %d",
+                __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), address.c_str(), ps);
+        auto busDevice = availableOutputDevices.getDevice(
+                *deviceTypes.begin(), address, AUDIO_FORMAT_DEFAULT);
         if (busDevice == nullptr) {
-            ALOGE("%s:unavailable device 0x%x %s, fallback on default", __func__, devices,
-                  address.c_str());
+            ALOGE("%s:unavailable device %s %s, fallback on default", __func__,
+                  dumpDeviceTypes(deviceTypes).c_str(), address.c_str());
             auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
             ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
             return DeviceVector(defaultDevice);
         }
-        return DeviceVector(availableOutputDevices.getDevice(devices,
-                                                             address,
-                                                             AUDIO_FORMAT_DEFAULT));
+        return DeviceVector(busDevice);
     }
-    ALOGV("%s:device 0x%x %d", __FUNCTION__, devices, ps);
-    return availableOutputDevices.getDevicesFromTypeMask(devices);
+    ALOGV("%s:device %s %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), ps);
+    return availableOutputDevices.getDevicesFromTypes(deviceTypes);
 }
 
 DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@@ -366,7 +370,8 @@
         ALOGE("%s: set device %d on invalid strategy %d", __FUNCTION__, devices, strategy);
         return false;
     }
-    getProductStrategies().at(strategy)->setDeviceTypes(devices);
+    // FIXME: stop using deviceTypesFromBitMask when the interface is ready
+    getProductStrategies().at(strategy)->setDeviceTypes(deviceTypesFromBitMask(devices));
     return true;
 }
 
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 4b57444..465a6f9 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -259,7 +259,7 @@
     std::string criterionName = audio_is_output_device(devDesc->type()) ?
                 gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
 
-    ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->address().string(),
+    ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->address().c_str(),
           state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
     ISelectionCriterionInterface *criterion =
             getElement<ISelectionCriterionInterface>(criterionName, mPolicyCriteria);
@@ -271,7 +271,7 @@
 
     auto criterionType = criterion->getCriterionType();
     int deviceAddressId;
-    if (not criterionType->getNumericalValue(devDesc->address().string(), deviceAddressId)) {
+    if (not criterionType->getNumericalValue(devDesc->address().c_str(), deviceAddressId)) {
         ALOGW("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->address().c_str());
         return BAD_TYPE;
     }
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 5bfad29..8443008 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,8 +16,7 @@
 
 #pragma once
 
-#include <AudioGain.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <HwModule.h>
 #include <DeviceDescriptor.h>
 #include <system/audio.h>
diff --git a/services/audiopolicy/enginedefault/Android.bp b/services/audiopolicy/enginedefault/Android.bp
index 2b9cf09..aaf4158 100644
--- a/services/audiopolicy/enginedefault/Android.bp
+++ b/services/audiopolicy/enginedefault/Android.bp
@@ -21,6 +21,7 @@
         "libaudiopolicyengine_config",
     ],
     shared_libs: [
+        "libaudiofoundation",
         "liblog",
         "libcutils",
         "libutils",
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index c602f3a..2a5cd49 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -27,10 +27,11 @@
 #include "Engine.h"
 #include <android-base/macros.h>
 #include <AudioPolicyManagerObserver.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <IOProfile.h>
 #include <AudioIODescriptorInterface.h>
 #include <policy.h>
+#include <media/AudioContainers.h>
 #include <utils/String8.h>
 #include <utils/Log.h>
 
@@ -136,27 +137,23 @@
     return EngineBase::setForceUse(usage, config);
 }
 
-audio_devices_t Engine::getDeviceForStrategyInt(legacy_strategy strategy,
-                                                DeviceVector availableOutputDevices,
-                                                DeviceVector availableInputDevices,
-                                                const SwAudioOutputCollection &outputs,
-                                                uint32_t outputDeviceTypesToIgnore) const
+DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
+                                              DeviceVector availableOutputDevices,
+                                              DeviceVector availableInputDevices,
+                                              const SwAudioOutputCollection &outputs) const
 {
-    uint32_t device = AUDIO_DEVICE_NONE;
-    uint32_t availableOutputDevicesType =
-            availableOutputDevices.types() & ~outputDeviceTypesToIgnore;
+    DeviceVector devices;
 
     switch (strategy) {
 
     case STRATEGY_TRANSMITTED_THROUGH_SPEAKER:
-        device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+        devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         break;
 
     case STRATEGY_SONIFICATION_RESPECTFUL:
         if (isInCall() || outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
-            device = getDeviceForStrategyInt(
-                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
         } else {
             bool media_active_locally =
                     outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_MUSIC),
@@ -165,17 +162,18 @@
                         toVolumeSource(AUDIO_STREAM_ACCESSIBILITY),
                         SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY);
             // routing is same as media without the "remote" device
-            device = getDeviceForStrategyInt(STRATEGY_MEDIA,
+            availableOutputDevices.remove(availableOutputDevices.getDevicesFromType(
+                    AUDIO_DEVICE_OUT_REMOTE_SUBMIX));
+            devices = getDevicesForStrategyInt(STRATEGY_MEDIA,
                     availableOutputDevices,
-                    availableInputDevices, outputs,
-                    AUDIO_DEVICE_OUT_REMOTE_SUBMIX | outputDeviceTypesToIgnore);
+                    availableInputDevices, outputs);
             // if no media is playing on the device, check for mandatory use of "safe" speaker
             // when media would have played on speaker, and the safe speaker path is available
-            if (!media_active_locally
-                    && (device & AUDIO_DEVICE_OUT_SPEAKER)
-                    && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
-                device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-                device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+            if (!media_active_locally) {
+                devices.replaceDevicesByType(
+                        AUDIO_DEVICE_OUT_SPEAKER,
+                        availableOutputDevices.getDevicesFromType(
+                                AUDIO_DEVICE_OUT_SPEAKER_SAFE));
             }
         }
         break;
@@ -183,9 +181,8 @@
     case STRATEGY_DTMF:
         if (!isInCall()) {
             // when off call, DTMF strategy follows the same rules as MEDIA strategy
-            device = getDeviceForStrategyInt(
-                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         // when in call, DTMF and PHONE strategies follow the same rules
@@ -197,24 +194,28 @@
         //   - cannot route from voice call RX OR
         //   - audio HAL version is < 3.0 and TX device is on the primary HW module
         if (getPhoneState() == AUDIO_MODE_IN_CALL) {
-            audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
+            audio_devices_t txDevice = getDeviceForInputSource(
+                    AUDIO_SOURCE_VOICE_COMMUNICATION)->type();
             sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
-            audio_devices_t availPrimaryInputDevices =
-                 availableInputDevices.getDeviceTypesFromHwModule(primaryOutput->getModuleHandle());
+            LOG_ALWAYS_FATAL_IF(primaryOutput == nullptr, "Primary output not found");
+            DeviceVector availPrimaryInputDevices =
+                    availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
 
             // TODO: getPrimaryOutput return only devices from first module in
             // audio_policy_configuration.xml, hearing aid is not there, but it's
             // a primary device
             // FIXME: this is not the right way of solving this problem
-            audio_devices_t availPrimaryOutputDevices =
-                (primaryOutput->supportedDevices().types() | AUDIO_DEVICE_OUT_HEARING_AID) &
-                availableOutputDevices.types();
+            DeviceVector availPrimaryOutputDevices = availableOutputDevices.getDevicesFromTypes(
+                    primaryOutput->supportedDevices().types());
+            availPrimaryOutputDevices.add(
+                    availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID));
 
-            if (((availableInputDevices.types() &
-                    AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
-                    (((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
-                         (primaryOutput->getAudioPort()->getModuleVersionMajor() < 3))) {
-                availableOutputDevicesType = availPrimaryOutputDevices;
+            if ((availableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
+                    String8(""), AUDIO_FORMAT_DEFAULT) == nullptr) ||
+                    ((availPrimaryInputDevices.getDevice(
+                            txDevice, String8(""), AUDIO_FORMAT_DEFAULT) != nullptr) &&
+                            (primaryOutput->getPolicyAudioPort()->getModuleVersionMajor() < 3))) {
+                availableOutputDevices = availPrimaryOutputDevices;
             }
         }
         // for phone strategy, we first consider the forced use and then the available devices by
@@ -222,49 +223,40 @@
         switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
         case AUDIO_POLICY_FORCE_BT_SCO:
             if (!isInCall() || strategy != STRATEGY_DTMF) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-                if (device) break;
+                devices = availableOutputDevices.getDevicesFromType(
+                        AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT);
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
-            if (device) break;
+            devices = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
+            if (!devices.isEmpty()) break;
             // if SCO device is requested but no SCO device is available, fall back to default case
             FALLTHROUGH_INTENDED;
 
         default:    // FORCE_NONE
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
-            if (device) break;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
+            if (!devices.isEmpty()) break;
             // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
             if (!isInCall() &&
                     (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
                      outputs.isA2dpSupported()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
-                if (device) break;
+                devices = availableOutputDevices.getFirstDevicesFromTypes({
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES});
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
-            if (device) break;
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
-            if (device) break;
+            devices = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET,
+                    AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET,
+                    AUDIO_DEVICE_OUT_USB_DEVICE});
+            if (!devices.isEmpty()) break;
             if (!isInCall()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
-                if (device) break;
+                devices = availableOutputDevices.getFirstDevicesFromTypes({
+                        AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,
+                        AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE);
             break;
 
         case AUDIO_POLICY_FORCE_SPEAKER:
@@ -273,22 +265,18 @@
             if (!isInCall() &&
                     (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
                      outputs.isA2dpSupported()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
-                if (device) break;
+                devices = availableOutputDevices.getDevicesFromType(
+                        AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER);
+                if (!devices.isEmpty()) break;
             }
             if (!isInCall()) {
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
-                if (device) break;
-                device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
-                if (device) break;
+                devices = availableOutputDevices.getFirstDevicesFromTypes({
+                        AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE,
+                        AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL,
+                        AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET});
+                if (!devices.isEmpty()) break;
             }
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
             break;
         }
     break;
@@ -298,9 +286,8 @@
         // If incall, just select the STRATEGY_PHONE device
         if (isInCall() ||
                 outputs.isActiveLocally(toVolumeSource(AUDIO_STREAM_VOICE_CALL))) {
-            device = getDeviceForStrategyInt(
-                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         FALLTHROUGH_INTENDED;
@@ -313,41 +300,37 @@
 
         if ((strategy == STRATEGY_SONIFICATION) ||
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
-            device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+            devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
 
         // if SCO headset is connected and we are told to use it, play ringtone over
         // speaker and BT SCO
-        if ((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) {
-            uint32_t device2 = AUDIO_DEVICE_NONE;
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
-            }
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
-            }
+        if (!availableOutputDevices.getDevicesFromTypes(getAudioDeviceOutAllScoSet()).isEmpty()) {
+            DeviceVector devices2;
+            devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+                    AUDIO_DEVICE_OUT_BLUETOOTH_SCO});
             // Use ONLY Bluetooth SCO output when ringing in vibration mode
             if (!((getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
                     && (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
                 if (getForceUse(AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING)
                         == AUDIO_POLICY_FORCE_BT_SCO) {
-                    if (device2 != AUDIO_DEVICE_NONE) {
-                        device = device2;
+                    if (!devices2.isEmpty()) {
+                        devices = devices2;
                         break;
                     }
                 }
             }
             // Use both Bluetooth SCO and phone default output when ringing in normal mode
             if (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) {
-                if ((strategy == STRATEGY_SONIFICATION) &&
-                        (device & AUDIO_DEVICE_OUT_SPEAKER) &&
-                        (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
-                    device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-                    device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+                if (strategy == STRATEGY_SONIFICATION) {
+                    devices.replaceDevicesByType(
+                            AUDIO_DEVICE_OUT_SPEAKER,
+                            availableOutputDevices.getDevicesFromType(
+                                    AUDIO_DEVICE_OUT_SPEAKER_SAFE));
                 }
-                if (device2 != AUDIO_DEVICE_NONE) {
-                    device |= device2;
+                if (!devices2.isEmpty()) {
+                    devices.add(devices2);
                     break;
                 }
             }
@@ -361,25 +344,20 @@
             // compressed format as they would likely not be mixed and dropped.
             for (size_t i = 0; i < outputs.size(); i++) {
                 sp<AudioOutputDescriptor> desc = outputs.valueAt(i);
-                audio_devices_t devices = desc->devices().types() &
-                    (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC);
-                if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) &&
-                        devices != AUDIO_DEVICE_NONE) {
-                    availableOutputDevicesType = availableOutputDevices.types() & ~devices;
+                if (desc->isActive() && !audio_is_linear_pcm(desc->getFormat())) {
+                    availableOutputDevices.remove(desc->devices().getDevicesFromTypes({
+                            AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_SPDIF,
+                            AUDIO_DEVICE_OUT_HDMI_ARC}));
                 }
             }
-            availableOutputDevices =
-                    availableOutputDevices.getDevicesFromTypeMask(availableOutputDevicesType);
             if (outputs.isActive(toVolumeSource(AUDIO_STREAM_RING)) ||
                     outputs.isActive(toVolumeSource(AUDIO_STREAM_ALARM))) {
-                return getDeviceForStrategyInt(
-                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+                return getDevicesForStrategyInt(
+                    STRATEGY_SONIFICATION, availableOutputDevices, availableInputDevices, outputs);
             }
             if (isInCall()) {
-                return getDeviceForStrategyInt(
-                        STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
-                        outputDeviceTypesToIgnore);
+                return getDevicesForStrategyInt(
+                        STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             }
         }
         // For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
@@ -388,128 +366,116 @@
     // FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
     case STRATEGY_REROUTING:
     case STRATEGY_MEDIA: {
-        uint32_t device2 = AUDIO_DEVICE_NONE;
+        DeviceVector devices2;
         if (strategy != STRATEGY_SONIFICATION) {
             // no sonification on remote submix (e.g. WFD)
-            if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
-                                                 String8("0"), AUDIO_FORMAT_DEFAULT) != 0) {
-                device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+            sp<DeviceDescriptor> remoteSubmix;
+            if ((remoteSubmix = availableOutputDevices.getDevice(
+                    AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0"),
+                    AUDIO_FORMAT_DEFAULT)) != nullptr) {
+                devices2.add(remoteSubmix);
             }
         }
         if (isInCall() && (strategy == STRATEGY_MEDIA)) {
-            device = getDeviceForStrategyInt(
-                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs,
-                    outputDeviceTypesToIgnore);
+            devices = getDevicesForStrategyInt(
+                    STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);
             break;
         }
         // FIXME: Find a better solution to prevent routing to BT hearing aid(b/122931261).
-        if ((device2 == AUDIO_DEVICE_NONE) &&
+        if ((devices2.isEmpty()) &&
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
         }
-        if ((device2 == AUDIO_DEVICE_NONE) &&
+        if ((devices2.isEmpty()) &&
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&
                  outputs.isA2dpSupported()) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
-            }
-            if (device2 == AUDIO_DEVICE_NONE) {
-                device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
-            }
+            devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER});
         }
-        if ((device2 == AUDIO_DEVICE_NONE) &&
+        if ((devices2.isEmpty()) &&
             (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+        if (devices2.isEmpty()) {
+            devices2 = availableOutputDevices.getFirstDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_LINE,
+                    AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_USB_HEADSET,
+                    AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE,
+                    AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET});
         }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_HEADSET;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;
-        }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
-        }
-        if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+        if ((devices2.isEmpty()) && (strategy != STRATEGY_SONIFICATION)) {
             // no sonification on aux digital (e.g. HDMI)
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_AUX_DIGITAL);
         }
-        if ((device2 == AUDIO_DEVICE_NONE) &&
+        if ((devices2.isEmpty()) &&
                 (getForceUse(AUDIO_POLICY_FORCE_FOR_DOCK) == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+            devices2 = availableOutputDevices.getDevicesFromType(
+                    AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
         }
-        if (device2 == AUDIO_DEVICE_NONE) {
-            device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
+        if (devices2.isEmpty()) {
+            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
         }
-        int device3 = AUDIO_DEVICE_NONE;
+        DeviceVector devices3;
         if (strategy == STRATEGY_MEDIA) {
             // ARC, SPDIF and AUX_LINE can co-exist with others.
-            device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC;
-            device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF);
-            device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE);
+            devices3 = availableOutputDevices.getDevicesFromTypes({
+                    AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_SPDIF, AUDIO_DEVICE_OUT_AUX_LINE});
         }
 
-        device2 |= device3;
+        devices2.add(devices3);
         // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
         // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
-        device |= device2;
+        devices.add(devices2);
 
         // If hdmi system audio mode is on, remove speaker out of output list.
         if ((strategy == STRATEGY_MEDIA) &&
             (getForceUse(AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO) ==
                 AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {
-            device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+            devices.remove(devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
         }
 
         // for STRATEGY_SONIFICATION:
         // if SPEAKER was selected, and SPEAKER_SAFE is available, use SPEAKER_SAFE instead
-        if ((strategy == STRATEGY_SONIFICATION) &&
-                (device & AUDIO_DEVICE_OUT_SPEAKER) &&
-                (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
-            device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-            device &= ~AUDIO_DEVICE_OUT_SPEAKER;
+        if (strategy == STRATEGY_SONIFICATION) {
+            devices.replaceDevicesByType(
+                    AUDIO_DEVICE_OUT_SPEAKER,
+                    availableOutputDevices.getDevicesFromType(
+                            AUDIO_DEVICE_OUT_SPEAKER_SAFE));
         }
         } break;
 
     default:
-        ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+        ALOGW("getDevicesForStrategy() unknown strategy: %d", strategy);
         break;
     }
 
-    if (device == AUDIO_DEVICE_NONE) {
-        ALOGV("getDeviceForStrategy() no device found for strategy %d", strategy);
-        device = getApmObserver()->getDefaultOutputDevice()->type();
-        ALOGE_IF(device == AUDIO_DEVICE_NONE,
-                 "getDeviceForStrategy() no default device defined");
+    if (devices.isEmpty()) {
+        ALOGV("getDevicesForStrategy() no device found for strategy %d", strategy);
+        sp<DeviceDescriptor> defaultOutputDevice = getApmObserver()->getDefaultOutputDevice();
+        if (defaultOutputDevice != nullptr) {
+            devices.add(defaultOutputDevice);
+        }
+        ALOGE_IF(devices.isEmpty(),
+                 "getDevicesForStrategy() no default device defined");
     }
-    ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
-    return device;
+
+    ALOGVV("getDevices"
+           "ForStrategy() strategy %d, device %x", strategy, devices.types());
+    return devices;
 }
 
 
-audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
+sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) const
 {
     const DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();
     const DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
     const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
-    audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
+    DeviceVector availableDevices = availableInputDevices;
     sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
-    audio_devices_t availablePrimaryDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
-        primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
-    uint32_t device = AUDIO_DEVICE_NONE;
+    DeviceVector availablePrimaryDevices = primaryOutput == nullptr ? DeviceVector()
+            : availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
+    sp<DeviceDescriptor> device;
 
     // when a call is active, force device selection to match source VOICE_COMMUNICATION
     // for most other input sources to avoid rerouting call TX audio
@@ -532,57 +498,48 @@
     switch (inputSource) {
     case AUDIO_SOURCE_DEFAULT:
     case AUDIO_SOURCE_MIC:
-    if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
-        device = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
-    } else if ((getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) &&
-        (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
-        device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-        device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-        device = AUDIO_DEVICE_IN_USB_HEADSET;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-        device = AUDIO_DEVICE_IN_USB_DEVICE;
-    } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-        device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-    }
-    break;
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_BLUETOOTH_A2DP, String8(""), AUDIO_FORMAT_DEFAULT);
+        if (device != nullptr) break;
+        if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
+            device = availableDevices.getDevice(
+                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+            if (device != nullptr) break;
+        }
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
+        break;
 
     case AUDIO_SOURCE_VOICE_COMMUNICATION:
         // Allow only use of devices on primary input if in call and HAL does not support routing
         // to voice call path.
         if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
-                (availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
-            availableDeviceTypes = availablePrimaryDeviceTypes;
+                (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_TELEPHONY_TX,
+                        String8(""), AUDIO_FORMAT_DEFAULT)) == nullptr) {
+            LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found");
+            availableDevices = availablePrimaryDevices;
         }
 
         switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) {
         case AUDIO_POLICY_FORCE_BT_SCO:
             // if SCO device is requested but no SCO device is available, fall back to default case
-            if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
-                device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+            device = availableDevices.getDevice(
+                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+            if (device != nullptr) {
                 break;
             }
             FALLTHROUGH_INTENDED;
 
         default:    // FORCE_NONE
-            if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-                device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-                device = AUDIO_DEVICE_IN_USB_HEADSET;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-                device = AUDIO_DEVICE_IN_USB_DEVICE;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-            }
+            device = availableDevices.getFirstExistingDevice({
+                    AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                    AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
             break;
 
         case AUDIO_POLICY_FORCE_SPEAKER:
-            if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
-                device = AUDIO_DEVICE_IN_BACK_MIC;
-            } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-            }
+            device = availableDevices.getFirstExistingDevice({
+                    AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC});
             break;
         }
         break;
@@ -591,77 +548,63 @@
     case AUDIO_SOURCE_UNPROCESSED:
     case AUDIO_SOURCE_HOTWORD:
         if (inputSource == AUDIO_SOURCE_HOTWORD) {
-            availableDeviceTypes = availablePrimaryDeviceTypes;
+            // We should not use primary output criteria for Hotword but rather limit
+            // to devices attached to the same HW module as the build in mic
+            LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found");
+            availableDevices = availablePrimaryDevices;
         }
-        if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO &&
-                availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
-            device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-            device = AUDIO_DEVICE_IN_USB_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-            device = AUDIO_DEVICE_IN_USB_DEVICE;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+        if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) {
+            device = availableDevices.getDevice(
+                    AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT);
+            if (device != nullptr) break;
         }
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
         break;
     case AUDIO_SOURCE_CAMCORDER:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {
-            device = AUDIO_DEVICE_IN_BACK_MIC;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-            // This is specifically for a device without built-in mic
-            device = AUDIO_DEVICE_IN_USB_DEVICE;
-        }
+        // For a device without built-in mic, adding usb device
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC,
+                AUDIO_DEVICE_IN_USB_DEVICE});
         break;
     case AUDIO_SOURCE_VOICE_DOWNLINK:
     case AUDIO_SOURCE_VOICE_CALL:
     case AUDIO_SOURCE_VOICE_UPLINK:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {
-            device = AUDIO_DEVICE_IN_VOICE_CALL;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_VOICE_CALL, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     case AUDIO_SOURCE_VOICE_PERFORMANCE:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
-            device = AUDIO_DEVICE_IN_WIRED_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) {
-            device = AUDIO_DEVICE_IN_USB_HEADSET;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
-            device = AUDIO_DEVICE_IN_USB_DEVICE;
-        } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
-            device = AUDIO_DEVICE_IN_BUILTIN_MIC;
-        }
+        device = availableDevices.getFirstExistingDevice({
+                AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET,
+                AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC});
         break;
     case AUDIO_SOURCE_REMOTE_SUBMIX:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
-            device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_REMOTE_SUBMIX, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     case AUDIO_SOURCE_FM_TUNER:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {
-            device = AUDIO_DEVICE_IN_FM_TUNER;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_FM_TUNER, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     case AUDIO_SOURCE_ECHO_REFERENCE:
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_ECHO_REFERENCE) {
-            device = AUDIO_DEVICE_IN_ECHO_REFERENCE;
-        }
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_ECHO_REFERENCE, String8(""), AUDIO_FORMAT_DEFAULT);
         break;
     default:
         ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
         break;
     }
-    if (device == AUDIO_DEVICE_NONE) {
+    if (device == nullptr) {
         ALOGV("getDeviceForInputSource() no device found for source %d", inputSource);
-        if (availableDeviceTypes & AUDIO_DEVICE_IN_STUB) {
-            device = AUDIO_DEVICE_IN_STUB;
-        }
-        ALOGE_IF(device == AUDIO_DEVICE_NONE,
+        device = availableDevices.getDevice(
+                AUDIO_DEVICE_IN_STUB, String8(""), AUDIO_FORMAT_DEFAULT);
+        ALOGE_IF(device == nullptr,
                  "getDeviceForInputSource() no default device defined");
     }
-    ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+    ALOGV_IF(device != nullptr,
+             "getDeviceForInputSource()input source %d, device %08x",
+             inputSource, device->type());
     return device;
 }
 
@@ -684,11 +627,9 @@
 
     auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
                 mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
-    audio_devices_t devices = getDeviceForStrategyInt(legacyStrategy,
-                                                      availableOutputDevices,
-                                                      availableInputDevices, outputs,
-                                                      (uint32_t)AUDIO_DEVICE_NONE);
-    return availableOutputDevices.getDevicesFromTypeMask(devices);
+    return getDevicesForStrategyInt(legacyStrategy,
+                                    availableOutputDevices,
+                                    availableInputDevices, outputs);
 }
 
 DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
@@ -747,17 +688,21 @@
     if (device != nullptr) {
         return device;
     }
-    audio_devices_t deviceType = getDeviceForInputSource(attr.source);
 
-    if (audio_is_remote_submix_device(deviceType)) {
-        address = "0";
-        std::size_t pos;
-        std::string tags { attr.tags };
-        if ((pos = tags.find("addr=")) != std::string::npos) {
-            address = tags.substr(pos + std::strlen("addr="));
-        }
+    device = getDeviceForInputSource(attr.source);
+    if (device == nullptr || !audio_is_remote_submix_device(device->type())) {
+        // Return immediately if the device is null or it is not a remote submix device.
+        return device;
     }
-    return availableInputDevices.getDevice(deviceType,
+
+    // For remote submix device, try to find the device by address.
+    address = "0";
+    std::size_t pos;
+    std::string tags { attr.tags };
+    if ((pos = tags.find("addr=")) != std::string::npos) {
+        address = tags.substr(pos + std::strlen("addr="));
+    }
+    return availableInputDevices.getDevice(device->type(),
                                            String8(address.c_str()),
                                            AUDIO_FORMAT_DEFAULT);
 }
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 62938cf..4360c6f 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -18,7 +18,6 @@
 
 #include "EngineBase.h"
 #include "EngineInterface.h"
-#include <AudioGain.h>
 #include <policy.h>
 
 namespace android
@@ -74,15 +73,14 @@
 
     status_t setDefaultDevice(audio_devices_t device);
 
-    audio_devices_t getDeviceForStrategyInt(legacy_strategy strategy,
-                                            DeviceVector availableOutputDevices,
-                                            DeviceVector availableInputDevices,
-                                            const SwAudioOutputCollection &outputs,
-                                            uint32_t outputDeviceTypesToIgnore) const;
+    DeviceVector getDevicesForStrategyInt(legacy_strategy strategy,
+                                          DeviceVector availableOutputDevices,
+                                          DeviceVector availableInputDevices,
+                                          const SwAudioOutputCollection &outputs) const;
 
     DeviceVector getDevicesForProductStrategy(product_strategy_t strategy) const;
 
-    audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
+    sp<DeviceDescriptor> getDeviceForInputSource(audio_source_t inputSource) const;
 
     DeviceStrategyMap mDevicesForStrategies;
 
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index 8fbeff9..1fa0d19 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -9,6 +9,7 @@
     export_include_dirs: ["."],
 
     shared_libs: [
+        "libaudiofoundation",
         "libcutils",
         "libdl",
         "libutils",
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b0b63d9..355e4f0 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -73,6 +73,26 @@
         AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
         AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
 
+template <typename T>
+bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    if (left.size() != right.size()) {
+        return false;
+    }
+    for (size_t index = 0; index < right.size(); index++) {
+        if (left[index] != right[index]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+template <typename T>
+bool operator!= (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    return !(left == right);
+}
+
 // ----------------------------------------------------------------------------
 // AudioPolicyInterface implementation
 // ----------------------------------------------------------------------------
@@ -92,7 +112,7 @@
 void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
                                                         audio_policy_dev_state_t state)
 {
-    AudioParameter param(device->address());
+    AudioParameter param(String8(device->address().c_str()));
     const String8 key(state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE ?
                 AudioParameter::keyDeviceConnect : AudioParameter::keyDeviceDisconnect);
     param.addInt(key, device->type());
@@ -405,7 +425,7 @@
     if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
 
     // Check if the device is currently connected
-    DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromTypeMask(device);
+    DeviceVector deviceList = mAvailableOutputDevices.getDevicesFromType(device);
     if (deviceList.empty()) {
         // Nothing to do: device is not connected
         return NO_ERROR;
@@ -419,8 +439,8 @@
     // Case 1: A2DP active device switches from primary to primary
     // module
     // Case 2: A2DP device config changes on primary module.
-    if (device & AUDIO_DEVICE_OUT_ALL_A2DP) {
-        sp<HwModule> module = mHwModules.getModuleForDeviceTypes(device, encodedFormat);
+    if (audio_is_a2dp_out_device(device)) {
+        sp<HwModule> module = mHwModules.getModuleForDeviceType(device, encodedFormat);
         audio_module_handle_t primaryHandle = mPrimaryOutput->getModuleHandle();
         if (availablePrimaryOutputDevices().contains(devDesc) &&
            (module != 0 && module->getHandle() == primaryHandle)) {
@@ -476,8 +496,8 @@
         ALOGE("%s() unable to get primary module", __func__);
         return NO_INIT;
     }
-    DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypeMask(
-            AUDIO_DEVICE_OUT_ALL_A2DP);
+    DeviceVector declaredDevices = primaryModule->getDeclaredDevices().getDevicesFromTypes(
+            getAudioDeviceOutAllA2dpSet());
     for (const auto& device : declaredDevices) {
         formatSet.insert(device->encodedFormats().begin(), device->encodedFormats().end());
     }
@@ -491,7 +511,8 @@
     bool createRxPatch = false;
     uint32_t muteWaitMs = 0;
 
-    if(!hasPrimaryOutput() || mPrimaryOutput->devices().types() == AUDIO_DEVICE_OUT_STUB) {
+    if(!hasPrimaryOutput() ||
+            mPrimaryOutput->devices().onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_STUB)) {
         return muteWaitMs;
     }
     ALOG_ASSERT(!rxDevices.isEmpty(), "updateCallRouting() no selected output device");
@@ -515,9 +536,9 @@
     }
 
     auto telephonyRxModule =
-        mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
+        mHwModules.getModuleForDeviceType(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
     auto telephonyTxModule =
-        mHwModules.getModuleForDeviceTypes(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
+        mHwModules.getModuleForDeviceType(AUDIO_DEVICE_OUT_TELEPHONY_TX, AUDIO_FORMAT_DEFAULT);
     // retrieve Rx Source and Tx Sink device descriptors
     sp<DeviceDescriptor> rxSourceDevice =
         mAvailableInputDevices.getDevice(AUDIO_DEVICE_IN_TELEPHONY_RX,
@@ -628,20 +649,6 @@
     return audioPatch;
 }
 
-sp<DeviceDescriptor> AudioPolicyManager::findDevice(
-        const DeviceVector& devices, audio_devices_t device) const {
-    DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
-    ALOG_ASSERT(!deviceList.isEmpty(),
-            "%s() selected device type %#x is not in devices list", __func__, device);
-    return deviceList.itemAt(0);
-}
-
-audio_devices_t AudioPolicyManager::getModuleDeviceTypes(
-        const DeviceVector& devices, const char *moduleId) const {
-    sp<HwModule> mod = mHwModules.getModuleFromName(moduleId);
-    return mod != 0 ? devices.getDeviceTypesFromHwModule(mod->getHandle()) : AUDIO_DEVICE_NONE;
-}
-
 bool AudioPolicyManager::isDeviceOfModule(
         const sp<DeviceDescriptor>& devDesc, const char *moduleId) const {
     sp<HwModule> module = mHwModules.getModuleFromName(moduleId);
@@ -675,8 +682,8 @@
      * Switching to or from incall state or switching between telephony and VoIP lead to force
      * routing command.
      */
-    bool force = ((is_state_in_call(oldState) != is_state_in_call(state))
-                  || (is_state_in_call(state) && (state != oldState)));
+    bool force = ((isStateInCall(oldState) != isStateInCall(state))
+                  || (isStateInCall(state) && (state != oldState)));
 
     // check for device and output changes triggered by new phone state
     checkForDeviceAndOutputChanges();
@@ -861,7 +868,7 @@
                 continue;
             }
             // reject profiles if connected device does not support codec
-            if (!curProfile->deviceSupportsEncodedFormats(devices.types())) {
+            if (!curProfile->devicesSupportEncodedFormats(devices.types())) {
                 continue;
             }
             if (!directOnly) return curProfile;
@@ -938,7 +945,8 @@
         audio_output_flags_t *flags,
         audio_port_handle_t *selectedDeviceId,
         bool *isRequestedDeviceForExclusiveUse,
-        std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
+        std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+        output_type_t *outputType)
 {
     DeviceVector outputDevices;
     const audio_port_handle_t requestedPortId = *selectedDeviceId;
@@ -946,6 +954,7 @@
     const sp<DeviceDescriptor> requestedDevice =
         mAvailableOutputDevices.getDeviceFromId(requestedPortId);
 
+    *outputType = API_OUTPUT_INVALID;
     status_t status = getAudioAttributes(resultAttr, attr, *stream);
     if (status != NO_ERROR) {
         return status;
@@ -984,7 +993,13 @@
                                                   mix->mDeviceAddress,
                                                   AUDIO_FORMAT_DEFAULT);
         *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
+
         ALOGV("getOutputForAttr() returns output %d", *output);
+        if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
+            *outputType = API_OUT_MIX_PLAYBACK;
+        } else {
+            *outputType = API_OUTPUT_LEGACY;
+        }
         return NO_ERROR;
     }
     // Virtual sources must always be dynamicaly or explicitly routed
@@ -1005,10 +1020,10 @@
     // FIXME: provide a more generic approach which is not device specific and move this back
     // to getOutputForDevice.
     // TODO: Remove check of AUDIO_STREAM_MUSIC once migration is completed on the app side.
-    if (outputDevices.types() == AUDIO_DEVICE_OUT_TELEPHONY_TX &&
+    if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX) &&
         (*stream == AUDIO_STREAM_MUSIC  || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
         audio_is_linear_pcm(config->format) &&
-        isInCall()) {
+        isCallAudioAccessible()) {
         if (requestedPortId != AUDIO_PORT_HANDLE_NONE) {
             *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
             *isRequestedDeviceForExclusiveUse = true;
@@ -1041,6 +1056,12 @@
 
     *selectedDeviceId = getFirstDeviceId(outputDevices);
 
+    if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
+        *outputType = API_OUTPUT_TELEPHONY_TX;
+    } else {
+        *outputType = API_OUTPUT_LEGACY;
+    }
+
     ALOGV("%s returns output %d selectedDeviceId %d", __func__, *output, *selectedDeviceId);
 
     return NO_ERROR;
@@ -1055,7 +1076,8 @@
                                               audio_output_flags_t *flags,
                                               audio_port_handle_t *selectedDeviceId,
                                               audio_port_handle_t *portId,
-                                              std::vector<audio_io_handle_t> *secondaryOutputs)
+                                              std::vector<audio_io_handle_t> *secondaryOutputs,
+                                              output_type_t *outputType)
 {
     // The supplied portId must be AUDIO_PORT_HANDLE_NONE
     if (*portId != AUDIO_PORT_HANDLE_NONE) {
@@ -1075,7 +1097,7 @@
 
     status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
             config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
-            &secondaryOutputDescs);
+            &secondaryOutputDescs, outputType);
     if (status != NO_ERROR) {
         return status;
     }
@@ -1089,7 +1111,7 @@
         .channel_mask = config->channel_mask,
         .format = config->format,
     };
-    *portId = AudioPort::getNextUniqueId();
+    *portId = PolicyAudioPort::getNextUniqueId();
 
     sp<TrackClientDescriptor> clientDesc =
         new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
@@ -1186,9 +1208,9 @@
             if (!desc->isDuplicated() && (profile == desc->mProfile)) {
                 // reuse direct output if currently open by the same client
                 // and configured with same parameters
-                if ((config->sample_rate == desc->mSamplingRate) &&
-                    (config->format == desc->mFormat) &&
-                    (channelMask == desc->mChannelMask) &&
+                if ((config->sample_rate == desc->getSamplingRate()) &&
+                    (config->format == desc->getFormat()) &&
+                    (channelMask == desc->getChannelMask()) &&
                     (session == desc->mDirectClientSession)) {
                     desc->mDirectOpenCount++;
                     ALOGI("%s reusing direct output %d for session %d", __func__, 
@@ -1215,7 +1237,7 @@
             for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
                 const struct audio_port_config *sink = &patch->mPatch.sinks[j];
                 if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
-                        (sink->ext.device.type & devices.types()) != AUDIO_DEVICE_NONE &&
+                        devices.containsDeviceWithType(sink->ext.device.type) &&
                         (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
                                 AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
                     releaseAudioPatch(patch->mHandle, mUidCached);
@@ -1228,13 +1250,13 @@
 
         // only accept an output with the requested parameters
         if (status != NO_ERROR ||
-            (config->sample_rate != 0 && config->sample_rate != outputDesc->mSamplingRate) ||
-            (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->mFormat) ||
-            (channelMask != 0 && channelMask != outputDesc->mChannelMask)) {
+            (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+            (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+            (channelMask != 0 && channelMask != outputDesc->getChannelMask())) {
             ALOGV("%s failed opening direct output: output %d sample rate %d %d," 
                     "format %d %d, channel mask %04x %04x", __func__, output, config->sample_rate,
-                    outputDesc->mSamplingRate, config->format, outputDesc->mFormat,
-                    channelMask, outputDesc->mChannelMask);
+                    outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
+                    channelMask, outputDesc->getChannelMask());
             if (output != AUDIO_IO_HANDLE_NONE) {
                 outputDesc->close();
             }
@@ -1340,19 +1362,19 @@
     // Each IOProfile represents a MixPort from audio_policy_configuration.xml
     for (const auto &inProfile : inputProfiles) {
         if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
-            msdProfiles.appendVector(inProfile->getAudioProfiles());
+            appendAudioProfiles(msdProfiles, inProfile->getAudioProfiles());
         }
     }
     AudioProfileVector deviceProfiles;
     for (const auto &outProfile : outputProfiles) {
         if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) {
-            deviceProfiles.appendVector(outProfile->getAudioProfiles());
+            appendAudioProfiles(deviceProfiles, outProfile->getAudioProfiles());
         }
     }
     struct audio_config_base bestSinkConfig;
-    status_t result = msdProfiles.findBestMatchingOutputConfig(deviceProfiles,
+    status_t result = findBestMatchingOutputConfig(msdProfiles, deviceProfiles,
             compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
-            &bestSinkConfig);
+            bestSinkConfig);
     if (result != NO_ERROR) {
         ALOGD("%s() no matching profiles found for device: %s, hwAvSync: %d",
                 __func__, outputDevice->toString().c_str(), hwAvSync);
@@ -1505,13 +1527,13 @@
         // If haptic channel is specified, use the haptic output if present.
         // When using haptic output, same audio format and sample rate are required.
         const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
-            outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
+            outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
         if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
             continue;
         }
         if (outputHapticChannelCount >= hapticChannelCount
-            && format == outputDesc->mFormat
-            && samplingRate == outputDesc->mSamplingRate) {
+            && format == outputDesc->getFormat()
+            && samplingRate == outputDesc->getSamplingRate()) {
                 currentMatchCriteria[0] = outputHapticChannelCount;
         }
 
@@ -1519,12 +1541,13 @@
         currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
 
         // channel mask and channel count match
-        uint32_t outputChannelCount = audio_channel_count_from_out_mask(outputDesc->mChannelMask);
+        uint32_t outputChannelCount = audio_channel_count_from_out_mask(
+                outputDesc->getChannelMask());
         if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
             channelCount <= outputChannelCount) {
             if ((audio_channel_mask_get_representation(channelMask) ==
-                    audio_channel_mask_get_representation(outputDesc->mChannelMask)) &&
-                    ((channelMask & outputDesc->mChannelMask) == channelMask)) {
+                    audio_channel_mask_get_representation(outputDesc->getChannelMask())) &&
+                    ((channelMask & outputDesc->getChannelMask()) == channelMask)) {
                 currentMatchCriteria[2] = outputChannelCount;
             }
             currentMatchCriteria[3] = outputChannelCount;
@@ -1532,8 +1555,8 @@
 
         // sampling rate match
         if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
-                samplingRate <= outputDesc->mSamplingRate) {
-            currentMatchCriteria[4] = outputDesc->mSamplingRate;
+                samplingRate <= outputDesc->getSamplingRate()) {
+            currentMatchCriteria[4] = outputDesc->getSamplingRate();
         }
 
         // performance flags match
@@ -1542,8 +1565,8 @@
         // format match
         if (format != AUDIO_FORMAT_INVALID) {
             currentMatchCriteria[6] =
-                AudioPort::kFormatDistanceMax -
-                AudioPort::formatDistance(format, outputDesc->mFormat);
+                PolicyAudioPort::kFormatDistanceMax -
+                PolicyAudioPort::formatDistance(format, outputDesc->getFormat());
         }
 
         // primary output match
@@ -1757,14 +1780,15 @@
     }
 
     if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
-            mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
+            mEngine->getForceUse(
+                    AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
         setStrategyMute(streamToStrategy(AUDIO_STREAM_ALARM), true, outputDesc);
     }
 
     // Automatically enable the remote submix input when output is started on a re routing mix
     // of type MIX_TYPE_RECORDERS
-    if (audio_is_remote_submix_device(devices.types()) && policyMix != NULL &&
-        policyMix->mMixType == MIX_TYPE_RECORDERS) {
+    if (isSingleDeviceType(devices.types(), &audio_is_remote_submix_device) &&
+        policyMix != NULL && policyMix->mMixType == MIX_TYPE_RECORDERS) {
         setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
                                     AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                     address,
@@ -1811,7 +1835,8 @@
             // Automatically disable the remote submix input when output is stopped on a
             // re routing mix of type MIX_TYPE_RECORDERS
             sp<AudioPolicyMix> policyMix = outputDesc->mPolicyMix.promote();
-            if (audio_is_remote_submix_device(outputDesc->devices().types()) &&
+            if (isSingleDeviceType(
+                    outputDesc->devices().types(), &audio_is_remote_submix_device) &&
                 policyMix != NULL &&
                 policyMix->mMixType == MIX_TYPE_RECORDERS) {
                 setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
@@ -2067,7 +2092,7 @@
 
     isSoundTrigger = attributes.source == AUDIO_SOURCE_HOTWORD &&
         mSoundTriggerSessions.indexOfKey(session) >= 0;
-    *portId = AudioPort::getNextUniqueId();
+    *portId = PolicyAudioPort::getNextUniqueId();
 
     clientDesc = new RecordClientDescriptor(*portId, riid, uid, session, attributes, *config,
                                             requestedDeviceId, attributes.source, flags,
@@ -2410,7 +2435,8 @@
         const sp<AudioInputDescriptor> input = mInputs.valueAt(i);
         if (input->clientsList().size() == 0
                 || !mAvailableInputDevices.containsAtLeastOne(input->supportedDevices())
-                || (input->getAudioPort()->getFlags() & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
+                || (input->getPolicyAudioPort()->getFlags()
+                        & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
             inputsToClose.push_back(mInputs.keyAt(i));
         } else {
             bool close = false;
@@ -2470,10 +2496,12 @@
 {
     // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
     // stream by the engine.
+    DeviceTypeSet deviceTypes = {device};
     if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
-        device = mEngine->getOutputDevicesForStream(stream, true /*fromCache*/).types();
+        deviceTypes = mEngine->getOutputDevicesForStream(
+                stream, true /*fromCache*/).types();
     }
-    return getVolumeIndex(getVolumeCurves(stream), *index, device);
+    return getVolumeIndex(getVolumeCurves(stream), *index, deviceTypes);
 }
 
 status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
@@ -2498,19 +2526,20 @@
         return status;
     }
 
-    audio_devices_t curSrcDevice;
+    DeviceTypeSet curSrcDevices;
     auto curCurvAttrs = curves.getAttributes();
     if (!curCurvAttrs.empty() && curCurvAttrs.front() != defaultAttr) {
         auto attr = curCurvAttrs.front();
-        curSrcDevice = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
+        curSrcDevices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false).types();
     } else if (!curves.getStreamTypes().empty()) {
         auto stream = curves.getStreamTypes().front();
-        curSrcDevice = mEngine->getOutputDevicesForStream(stream, false).types();
+        curSrcDevices = mEngine->getOutputDevicesForStream(stream, false).types();
     } else {
         ALOGE("%s: Invalid src %d: no valid attributes nor stream",__func__, vs);
         return BAD_VALUE;
     }
-    curSrcDevice = Volume::getDeviceForVolume(curSrcDevice);
+    audio_devices_t curSrcDevice = Volume::getDeviceForVolume(curSrcDevices);
+    resetDeviceTypes(curSrcDevices, curSrcDevice);
 
     // update volume on all outputs and streams matching the following:
     // - The requested stream (or a stream matching for volume control) is active on the output
@@ -2522,11 +2551,10 @@
     // no specific device volume value exists for currently selected device.
     for (size_t i = 0; i < mOutputs.size(); i++) {
         sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-        audio_devices_t curDevice = desc->devices().types();
+        DeviceTypeSet curDevices = desc->devices().types();
 
-        if (curDevice & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
-            curDevice |= AUDIO_DEVICE_OUT_SPEAKER;
-            curDevice &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+        if (curDevices.erase(AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
+            curDevices.insert(AUDIO_DEVICE_OUT_SPEAKER);
         }
 
         // Inter / intra volume group priority management: Loop on strategies arranged by priority
@@ -2570,7 +2598,7 @@
             if (!applyVolume) {
                 continue; // next output
             }
-            status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevice,
+            status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevices,
                                                    (vs == toVolumeSource(AUDIO_STREAM_SYSTEM)?
                                                         TOUCH_SOUND_FIXED_DELAY_MS : 0));
             if (volStatus != NO_ERROR) {
@@ -2581,12 +2609,14 @@
         if (!(desc->isActive(vs) || isInCall())) {
             continue;
         }
-        if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) && ((curDevice & device) == 0)) {
+        if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME &&
+                curDevices.find(device) == curDevices.end()) {
             continue;
         }
         if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
-            curSrcDevice |= device;
-            applyVolume = (Volume::getDeviceForVolume(curDevice) & curSrcDevice) != 0;
+            curSrcDevices.insert(device);
+            applyVolume = (curSrcDevices.find(
+                    Volume::getDeviceForVolume(curDevices)) != curSrcDevices.end());
         } else {
             applyVolume = !curves.hasVolumeIndexForDevice(curSrcDevice);
         }
@@ -2595,7 +2625,7 @@
             // delayed volume change for system stream to be removed when the problem is
             // handled by system UI
             status_t volStatus = checkAndSetVolume(
-                        curves, vs, index, desc, curDevice,
+                        curves, vs, index, desc, curDevices,
                         ((vs == toVolumeSource(AUDIO_STREAM_SYSTEM))?
                              TOUCH_SOUND_FIXED_DELAY_MS : 0));
             if (volStatus != NO_ERROR) {
@@ -2638,22 +2668,23 @@
 {
     // if device is AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME, return volume for device selected for this
     // stream by the engine.
+    DeviceTypeSet deviceTypes = {device};
     if (device == AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
-        device = mEngine->getOutputDevicesForAttributes(attr, nullptr, true /*fromCache*/).types();
+        DeviceTypeSet deviceTypes = mEngine->getOutputDevicesForAttributes(
+                attr, nullptr, true /*fromCache*/).types();
     }
-    return getVolumeIndex(getVolumeCurves(attr), index, device);
+    return getVolumeIndex(getVolumeCurves(attr), index, deviceTypes);
 }
 
 status_t AudioPolicyManager::getVolumeIndex(const IVolumeCurves &curves,
                                             int &index,
-                                            audio_devices_t device) const
+                                            const DeviceTypeSet& deviceTypes) const
 {
-    if (!audio_is_output_device(device)) {
+    if (isSingleDeviceType(deviceTypes, audio_is_output_device)) {
         return BAD_VALUE;
     }
-    device = Volume::getDeviceForVolume(device);
-    index = curves.getVolumeIndex(device);
-    ALOGV("%s: device %08x index %d", __FUNCTION__, device, index);
+    index = curves.getVolumeIndex(deviceTypes);
+    ALOGV("%s: device %s index %d", __FUNCTION__, dumpDeviceTypes(deviceTypes).c_str(), index);
     return NO_ERROR;
 }
 
@@ -2902,9 +2933,9 @@
             // stereo and let audio flinger do the channel conversion if needed.
             outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
             inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
-            rSubmixModule->addOutputProfile(address, &outputConfig,
+            rSubmixModule->addOutputProfile(address.c_str(), &outputConfig,
                     AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
-            rSubmixModule->addInputProfile(address, &inputConfig,
+            rSubmixModule->addInputProfile(address.c_str(), &inputConfig,
                     AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
 
             if ((res = setDeviceConnectionStateInt(deviceTypeToMakeAvailable,
@@ -3000,8 +3031,8 @@
                     }
                 }
             }
-            rSubmixModule->removeOutputProfile(address);
-            rSubmixModule->removeInputProfile(address);
+            rSubmixModule->removeOutputProfile(address.c_str());
+            rSubmixModule->removeInputProfile(address.c_str());
 
         } else if ((mix.mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER) {
             if (mPolicyMixes.unregisterMix(mix) != NO_ERROR) {
@@ -3042,13 +3073,13 @@
         // reevaluate outputs for all given devices
         for (size_t i = 0; i < devices.size(); i++) {
             sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
-                            devices[i].mType, devices[i].mAddress, String8(),
+                            devices[i].mType, devices[i].mAddress.c_str(), String8(),
                             AUDIO_FORMAT_DEFAULT);
             SortedVector<audio_io_handle_t> outputs;
             if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                     outputs) != NO_ERROR) {
                 ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
-                        " addr=%s", devices[i].mType, devices[i].mAddress.string());
+                        " addr=%s", devices[i].mType, devices[i].mAddress.c_str());
                 return INVALID_OPERATION;
             }
         }
@@ -3213,7 +3244,7 @@
     ALOGV("%s() profile %sfound with name: %s, "
         "sample rate: %u, format: 0x%x, channel_mask: 0x%x, output flags: 0x%x",
         __FUNCTION__, profile != 0 ? "" : "NOT ",
-        (profile != 0 ? profile->getTagName().string() : "null"),
+        (profile != 0 ? profile->getTagName().c_str() : "null"),
         config.sample_rate, config.format, config.channel_mask, output_flags);
     return (profile != 0);
 }
@@ -3417,8 +3448,8 @@
         }
 
         // TODO: reconfigure output format and channels here
-        ALOGV("createAudioPatch() setting device %08x on output %d",
-              devices.types(), outputDesc->mIoHandle);
+        ALOGV("createAudioPatch() setting device %s on output %d",
+              dumpDeviceTypes(devices.types()).c_str(), outputDesc->mIoHandle);
         setOutputDevices(outputDesc, devices, true, 0, handle);
         index = mAudioPatches.indexOfKey(*handle);
         if (index >= 0) {
@@ -3836,7 +3867,7 @@
         return BAD_VALUE;
     }
 
-    *portId = AudioPort::getNextUniqueId();
+    *portId = PolicyAudioPort::getNextUniqueId();
 
     struct audio_patch dummyPatch = {};
     sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
@@ -3877,7 +3908,7 @@
     if (srcDevice->hasSameHwModuleAs(sinkDevice) &&
             srcDevice->getModuleVersionMajor() >= 3 &&
             sinkDevice->getModule()->supportsPatch(srcDevice, sinkDevice) &&
-            srcDevice->getAudioPort()->mGains.size() > 0) {
+            srcDevice->getAudioPort()->getGains().size() > 0) {
         ALOGV("%s Device to Device route supported by >=3.0 HAL", __FUNCTION__);
         // TODO: may explicitly specify whether we should use HW or SW patch
         //   create patch between src device and output device
@@ -3893,17 +3924,20 @@
         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);
+                &secondaryOutputs, &outputType);
         if (output == AUDIO_IO_HANDLE_NONE) {
-            ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevices.types());
+            ALOGV("%s no output for device %s",
+                  __FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
             return INVALID_OPERATION;
         }
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
         if (outputDesc->isDuplicated()) {
-            ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevices.types());
+            ALOGV("%s output for device %s is duplicated",
+                  __FUNCTION__, dumpDeviceTypes(sinkDevices.types()).c_str());
             return INVALID_OPERATION;
         }
         status_t status = outputDesc->start();
@@ -4012,7 +4046,7 @@
 float AudioPolicyManager::getStreamVolumeDB(
         audio_stream_type_t stream, int index, audio_devices_t device)
 {
-    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, device);
+    return computeVolume(getVolumeCurves(stream), toVolumeSource(stream), index, {device});
 }
 
 status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
@@ -4112,12 +4146,12 @@
 
     sp<SwAudioOutputDescriptor> outputDesc;
     bool profileUpdated = false;
-    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
-            AUDIO_DEVICE_OUT_HDMI);
+    DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
+        AUDIO_DEVICE_OUT_HDMI);
     for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
         // Simulate reconnection to update enabled surround sound formats.
-        String8 address = hdmiOutputDevices[i]->address();
-        String8 name = hdmiOutputDevices[i]->getName();
+        String8 address = String8(hdmiOutputDevices[i]->address().c_str());
+        std::string name = hdmiOutputDevices[i]->getName();
         status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
                                                       AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                                       address.c_str(),
@@ -4134,12 +4168,12 @@
         profileUpdated |= (status == NO_ERROR);
     }
     // FIXME: Why doing this for input HDMI devices if we don't augment their reported formats?
-    DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromTypeMask(
+    DeviceVector hdmiInputDevices = mAvailableInputDevices.getDevicesFromType(
                 AUDIO_DEVICE_IN_HDMI);
     for (size_t i = 0; i < hdmiInputDevices.size(); i++) {
         // Simulate reconnection to update enabled surround sound formats.
-        String8 address = hdmiInputDevices[i]->address();
-        String8 name = hdmiInputDevices[i]->getName();
+        String8 address = String8(hdmiInputDevices[i]->address().c_str());
+        std::string name = hdmiInputDevices[i]->getName();
         status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_IN_HDMI,
                                                       AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                                       address.c_str(),
@@ -4164,11 +4198,11 @@
     return profileUpdated ? NO_ERROR : INVALID_OPERATION;
 }
 
-void AudioPolicyManager::setAppState(uid_t uid, app_state_t state)
+void AudioPolicyManager::setAppState(audio_port_handle_t portId, app_state_t state)
 {
-    ALOGV("%s(uid:%d, state:%d)", __func__, uid, state);
+    ALOGV("%s(portId:%d, state:%d)", __func__, portId, state);
     for (size_t i = 0; i < mInputs.size(); i++) {
-        mInputs.valueAt(i)->setAppState(uid, state);
+        mInputs.valueAt(i)->setAppState(portId, state);
     }
 }
 
@@ -4189,6 +4223,12 @@
     return false;
 }
 
+bool AudioPolicyManager::isCallScreenModeSupported()
+{
+    return getConfig().isCallScreenModeSupported();
+}
+
+
 status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
 {
     ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
@@ -4450,7 +4490,7 @@
                 // give a valid ID to an attached device once confirmed it is reachable
                 if (!device->isAttached()) {
                     device->attach(hwModule);
-                    device->importAudioPort(inProfile, true);
+                    device->importAudioPortAndPickAudioProfile(inProfile, true);
                 }
             }
             inputDesc->close();
@@ -4481,11 +4521,11 @@
     }
     // If microphones address is empty, set it according to device type
     for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
-        if (mAvailableInputDevices[i]->address().isEmpty()) {
+        if (mAvailableInputDevices[i]->address().empty()) {
             if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
-                mAvailableInputDevices[i]->setAddress(String8(AUDIO_BOTTOM_MICROPHONE_ADDRESS));
+                mAvailableInputDevices[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
             } else if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
-                mAvailableInputDevices[i]->setAddress(String8(AUDIO_BACK_MICROPHONE_ADDRESS));
+                mAvailableInputDevices[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
             }
         }
     }
@@ -4530,7 +4570,7 @@
                                    const sp<SwAudioOutputDescriptor>& outputDesc)
 {
     mOutputs.add(output, outputDesc);
-    applyStreamVolumes(outputDesc, AUDIO_DEVICE_NONE, 0 /* delayMs */, true /* force */);
+    applyStreamVolumes(outputDesc, DeviceTypeSet(), 0 /* delayMs */, true /* force */);
     updateMono(output); // update mono status when adding to output list
     selectOutputForMusicEffects();
     nextAudioPortGeneration();
@@ -4554,7 +4594,7 @@
                                                    SortedVector<audio_io_handle_t>& outputs)
 {
     audio_devices_t deviceType = device->type();
-    const String8 &address = device->address();
+    const String8 &address = String8(device->address().c_str());
     sp<SwAudioOutputDescriptor> desc;
 
     if (audio_device_is_digital(deviceType)) {
@@ -4567,7 +4607,7 @@
         for (size_t i = 0; i < mOutputs.size(); i++) {
             desc = mOutputs.valueAt(i);
             if (!desc->isDuplicated() && desc->supportsDevice(device)
-                    && desc->deviceSupportsEncodedFormats(deviceType)) {
+                    && desc->devicesSupportEncodedFormats({deviceType})) {
                 ALOGV("checkOutputsForDevice(): adding opened output %d on device %s",
                       mOutputs.keyAt(i), device->toString().c_str());
                 outputs.add(mOutputs.keyAt(i));
@@ -4606,7 +4646,7 @@
                     // matching profile: save the sample rates, format and channel masks supported
                     // by the profile in our device descriptor
                     if (audio_device_is_digital(deviceType)) {
-                        device->importAudioPort(profile);
+                        device->importAudioPortAndPickAudioProfile(profile);
                     }
                     break;
                 }
@@ -4622,7 +4662,7 @@
             }
 
             ALOGV("opening output for device %08x with params %s profile %p name %s",
-                  deviceType, address.string(), profile.get(), profile->getName().string());
+                  deviceType, address.string(), profile.get(), profile->getName().c_str());
             desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
             audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
             status_t status = desc->open(nullptr, DeviceVector(device),
@@ -4708,7 +4748,7 @@
                 outputs.add(output);
                 // Load digital format info only for digital devices
                 if (audio_device_is_digital(deviceType)) {
-                    device->importAudioPort(profile);
+                    device->importAudioPortAndPickAudioProfile(profile);
                 }
 
                 if (device_distinguishes_on_address(deviceType)) {
@@ -4732,7 +4772,7 @@
             if (!desc->isDuplicated()) {
                 // exact match on device
                 if (device_distinguishes_on_address(deviceType) && desc->supportsDevice(device)
-                        && desc->deviceSupportsEncodedFormats(deviceType)) {
+                        && desc->devicesSupportEncodedFormats({deviceType})) {
                     outputs.add(mOutputs.keyAt(i));
                 } else if (!mAvailableOutputDevices.containsAtLeastOne(desc->supportedDevices())) {
                     ALOGV("checkOutputsForDevice(): disconnecting adding output %d",
@@ -4802,7 +4842,7 @@
                 desc = mInputs.valueAt(input_index);
                 if (desc->mProfile == profile) {
                     if (audio_device_is_digital(device->type())) {
-                        device->importAudioPort(profile);
+                        device->importAudioPortAndPickAudioProfile(profile);
                     }
                     break;
                 }
@@ -4826,7 +4866,7 @@
                                          &input);
 
             if (status == NO_ERROR) {
-                const String8& address = device->address();
+                const String8& address = String8(device->address().c_str());
                 if (!address.isEmpty()) {
                     char *param = audio_device_address_to_parameter(device->type(), address);
                     mpClientInterface->setParameters(input, String8(param));
@@ -4851,7 +4891,7 @@
                 profile_index--;
             } else {
                 if (audio_device_is_digital(device->type())) {
-                    device->importAudioPort(profile);
+                    device->importAudioPortAndPickAudioProfile(profile);
                 }
                 ALOGV("checkInputsForDevice(): adding input %d", input);
             }
@@ -5003,7 +5043,7 @@
                 i, openOutputs.valueAt(i)->isDuplicated(),
                 openOutputs.valueAt(i)->supportedDevices().toString().c_str());
         if (openOutputs.valueAt(i)->supportsAllDevices(devices)
-                && openOutputs.valueAt(i)->deviceSupportsEncodedFormats(devices.types())) {
+                && openOutputs.valueAt(i)->devicesSupportEncodedFormats(devices.types())) {
             ALOGVV("%s() found output %d", __func__, openOutputs.keyAt(i));
             outputs.add(openOutputs.keyAt(i));
         }
@@ -5044,10 +5084,12 @@
     // also take into account external policy-related changes: add all outputs which are
     // associated with policies in the "before" and "after" output vectors
     ALOGVV("%s(): policy related outputs", __func__);
+    bool hasDynamicPolicy = false;
     for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) {
         const sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i);
         if (desc != 0 && desc->mPolicyMix != NULL) {
             srcOutputs.add(desc->mIoHandle);
+            hasDynamicPolicy = true;
             ALOGVV(" previous outputs: adding %d", desc->mIoHandle);
         }
     }
@@ -5055,6 +5097,7 @@
         const sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
         if (desc != 0 && desc->mPolicyMix != NULL) {
             dstOutputs.add(desc->mIoHandle);
+            hasDynamicPolicy = true;
             ALOGVV(" new outputs: adding %d", desc->mIoHandle);
         }
     }
@@ -5063,12 +5106,45 @@
         // get maximum latency of all source outputs to determine the minimum mute time guaranteeing
         // audio from invalidated tracks will be rendered when unmuting
         uint32_t maxLatency = 0;
+        bool invalidate = hasDynamicPolicy;
         for (audio_io_handle_t srcOut : srcOutputs) {
             sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
-            if (desc != 0 && maxLatency < desc->latency()) {
+            if (desc == nullptr) continue;
+
+            if (desc->isStrategyActive(psId) && maxLatency < desc->latency()) {
                 maxLatency = desc->latency();
             }
+
+            if (invalidate) continue;
+
+            for (auto client : desc->clientsList(false /*activeOnly*/)) {
+                if (desc->isDuplicated() || !desc->mProfile->isDirectOutput()) {
+                    // a client on a non direct outputs has necessarily a linear PCM format
+                    // so we can call selectOutput() safely
+                    const audio_io_handle_t newOutput = selectOutput(dstOutputs,
+                                                                     client->flags(),
+                                                                     client->config().format,
+                                                                     client->config().channel_mask,
+                                                                     client->config().sample_rate);
+                    if (newOutput != srcOut) {
+                        invalidate = true;
+                        break;
+                    }
+                } else {
+                    sp<IOProfile> profile = getProfileForOutput(newDevices,
+                                   client->config().sample_rate,
+                                   client->config().format,
+                                   client->config().channel_mask,
+                                   client->flags(),
+                                   true /* directOnly */);
+                    if (profile != desc->mProfile) {
+                        invalidate = true;
+                        break;
+                    }
+                }
+            }
         }
+
         ALOGV_IF(!(srcOutputs.isEmpty() || dstOutputs.isEmpty()),
               "%s: strategy %d, moving from output %s to output %s", __func__, psId,
               std::to_string(srcOutputs[0]).c_str(),
@@ -5076,7 +5152,9 @@
         // mute strategy while moving tracks from one output to another
         for (audio_io_handle_t srcOut : srcOutputs) {
             sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
-            if (desc != 0 && desc->isStrategyActive(psId)) {
+            if (desc == nullptr) continue;
+
+            if (desc->isStrategyActive(psId)) {
                 setStrategyMute(psId, true, desc);
                 setStrategyMute(psId, false, desc, maxLatency * LATENCY_MUTE_FACTOR,
                                 newDevices.types());
@@ -5092,8 +5170,10 @@
             selectOutputForMusicEffects();
         }
         // Move tracks associated to this stream (and linked) from previous output to new output
-        for (auto stream :  mEngine->getStreamTypesForProductStrategy(psId)) {
-            mpClientInterface->invalidateStream(stream);
+        if (invalidate) {
+            for (auto stream :  mEngine->getStreamTypesForProductStrategy(psId)) {
+                mpClientInterface->invalidateStream(stream);
+            }
         }
     }
 }
@@ -5138,9 +5218,8 @@
     }
 
     bool isScoConnected =
-            ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET &
-                    ~AUDIO_DEVICE_BIT_IN) != 0) ||
-            ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0);
+            (mAvailableInputDevices.types().count(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0 ||
+             !Intersection(mAvailableOutputDevices.types(), getAudioDeviceOutAllScoSet()).empty());
 
     // if suspended, restore A2DP output if:
     //      ((SCO device is NOT connected) ||
@@ -5302,12 +5381,13 @@
     }
     /*Filter SPEAKER_SAFE out of results, as AudioService doesn't know about it
       and doesn't really need to.*/
-    DeviceVector speakerSafeDevices = devices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
+    DeviceVector speakerSafeDevices = devices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER_SAFE);
     if (!speakerSafeDevices.isEmpty()) {
-        devices.merge(mAvailableOutputDevices.getDevicesFromTypeMask(AUDIO_DEVICE_OUT_SPEAKER));
+        devices.merge(mAvailableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER));
         devices.remove(speakerSafeDevices);
     }
-    return devices.types();
+    // FIXME: use DeviceTypeSet when Java layer is ready for it.
+    return deviceTypesToBitMask(devices.types());
 }
 
 void AudioPolicyManager::handleNotificationRoutingForStream(audio_stream_type_t stream) {
@@ -5367,7 +5447,7 @@
         auto ttsVolumeSource = toVolumeSource(AUDIO_STREAM_TTS);
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
-            setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, AUDIO_DEVICE_NONE);
+            setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet());
             const uint32_t latency = desc->latency() * 2;
             if (latency > maxLatency) {
                 maxLatency = latency;
@@ -5683,9 +5763,9 @@
 float AudioPolicyManager::computeVolume(IVolumeCurves &curves,
                                         VolumeSource volumeSource,
                                         int index,
-                                        audio_devices_t device)
+                                        const DeviceTypeSet& deviceTypes)
 {
-    float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(device), index);
+    float volumeDb = curves.volIndexToDb(Volume::getDeviceCategory(deviceTypes), index);
 
     // handle the case of accessibility active while a ringtone is playing: if the ringtone is much
     // louder than the accessibility prompt, the prompt cannot be heard, thus masking the touch
@@ -5701,7 +5781,7 @@
             && (AUDIO_MODE_RINGTONE == mEngine->getPhoneState()) &&
             mOutputs.isActive(ringVolumeSrc, 0)) {
         auto &ringCurves = getVolumeCurves(AUDIO_STREAM_RING);
-        const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, device);
+        const float ringVolumeDb = computeVolume(ringCurves, ringVolumeSrc, index, deviceTypes);
         return ringVolumeDb - 4 > volumeDb ? ringVolumeDb - 4 : volumeDb;
     }
 
@@ -5716,9 +5796,9 @@
              volumeSource == toVolumeSource(AUDIO_STREAM_DTMF) ||
              volumeSource == a11yVolumeSrc)) {
         auto &voiceCurves = getVolumeCurves(callVolumeSrc);
-        int voiceVolumeIndex = voiceCurves.getVolumeIndex(device);
+        int voiceVolumeIndex = voiceCurves.getVolumeIndex(deviceTypes);
         const float maxVoiceVolDb =
-                computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, device)
+                computeVolume(voiceCurves, callVolumeSrc, voiceVolumeIndex, deviceTypes)
                 + IN_CALL_EARPIECE_HEADROOM_DB;
         // FIXME: Workaround for call screening applications until a proper audio mode is defined
         // to support this scenario : Exempt the RING stream from the audio cap if the audio was
@@ -5744,9 +5824,10 @@
     // speaker is part of the select devices
     // - if music is playing, always limit the volume to current music volume,
     // with a minimum threshold at -36dB so that notification is always perceived.
-    if ((device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                   AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                   AUDIO_DEVICE_OUT_USB_HEADSET | AUDIO_DEVICE_OUT_HEARING_AID)) &&
+    if (!Intersection(deviceTypes,
+            {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
+             AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADPHONE,
+             AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_HEARING_AID}).empty() &&
             ((volumeSource == alarmVolumeSrc ||
               volumeSource == ringVolumeSrc) ||
              (volumeSource == toVolumeSource(AUDIO_STREAM_NOTIFICATION)) ||
@@ -5761,31 +5842,33 @@
         if (isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY) ||
                 mLimitRingtoneVolume) {
             volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
-            audio_devices_t musicDevice =
+            DeviceTypeSet musicDevice =
                     mEngine->getOutputDevicesForAttributes(attributes_initializer(AUDIO_USAGE_MEDIA),
                                                            nullptr, true /*fromCache*/).types();
             auto &musicCurves = getVolumeCurves(AUDIO_STREAM_MUSIC);
-            float musicVolDb = computeVolume(musicCurves, musicVolumeSrc,
-                                             musicCurves.getVolumeIndex(musicDevice), musicDevice);
+            float musicVolDb = computeVolume(musicCurves,
+                                             musicVolumeSrc,
+                                             musicCurves.getVolumeIndex(musicDevice),
+                                             musicDevice);
             float minVolDb = (musicVolDb > SONIFICATION_HEADSET_VOLUME_MIN_DB) ?
                         musicVolDb : SONIFICATION_HEADSET_VOLUME_MIN_DB;
             if (volumeDb > minVolDb) {
                 volumeDb = minVolDb;
                 ALOGV("computeVolume limiting volume to %f musicVol %f", minVolDb, musicVolDb);
             }
-            if (device & (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
-                          AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)) {
+            if (!Intersection(deviceTypes, {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+                    AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}).empty()) {
                 // on A2DP, also ensure notification volume is not too low compared to media when
                 // intended to be played
                 if ((volumeDb > -96.0f) &&
                         (musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB > volumeDb)) {
-                    ALOGV("%s increasing volume for volume source=%d device=0x%X from %f to %f",
-                          __func__, volumeSource, device, volumeDb,
+                    ALOGV("%s increasing volume for volume source=%d device=%s from %f to %f",
+                          __func__, volumeSource, dumpDeviceTypes(deviceTypes).c_str(), volumeDb,
                           musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB);
                     volumeDb = musicVolDb - SONIFICATION_A2DP_MAX_MEDIA_DIFF_DB;
                 }
             }
-        } else if ((Volume::getDeviceForVolume(device) != AUDIO_DEVICE_OUT_SPEAKER) ||
+        } else if ((Volume::getDeviceForVolume(deviceTypes) != AUDIO_DEVICE_OUT_SPEAKER) ||
                    (!(volumeSource == alarmVolumeSrc || volumeSource == ringVolumeSrc))) {
             volumeDb += SONIFICATION_HEADSET_VOLUME_FACTOR_DB;
         }
@@ -5824,7 +5907,7 @@
                                                VolumeSource volumeSource,
                                                int index,
                                                const sp<AudioOutputDescriptor>& outputDesc,
-                                               audio_devices_t device,
+                                               DeviceTypeSet deviceTypes,
                                                int delayMs,
                                                bool force)
 {
@@ -5850,17 +5933,20 @@
              volumeSource, forceUseForComm);
         return INVALID_OPERATION;
     }
-    if (device == AUDIO_DEVICE_NONE) {
-        device = outputDesc->devices().types();
+    if (deviceTypes.empty()) {
+        deviceTypes = outputDesc->devices().types();
     }
 
-    float volumeDb = computeVolume(curves, volumeSource, index, device);
-    if (outputDesc->isFixedVolume(device) ||
+    float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
+    if (outputDesc->isFixedVolume(deviceTypes) ||
             // Force VoIP volume to max for bluetooth SCO
-            ((isVoiceVolSrc || isBtScoVolSrc) && (device & AUDIO_DEVICE_OUT_ALL_SCO) != 0)) {
+
+            ((isVoiceVolSrc || isBtScoVolSrc) &&
+                    isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device))) {
         volumeDb = 0.0f;
     }
-    outputDesc->setVolume(volumeDb, volumeSource, curves.getStreamTypes(), device, delayMs, force);
+    outputDesc->setVolume(
+            volumeDb, volumeSource, curves.getStreamTypes(), deviceTypes, delayMs, force);
 
     if (isVoiceVolSrc || isBtScoVolSrc) {
         float voiceVolume;
@@ -5879,15 +5965,16 @@
 }
 
 void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
-                                                audio_devices_t device,
-                                                int delayMs,
-                                                bool force)
+                                            const DeviceTypeSet& deviceTypes,
+                                            int delayMs,
+                                            bool force)
 {
     ALOGVV("applyStreamVolumes() for device %08x", device);
     for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
         auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
         checkAndSetVolume(curves, toVolumeSource(volumeGroup),
-                          curves.getVolumeIndex(device), outputDesc, device, delayMs, force);
+                          curves.getVolumeIndex(deviceTypes),
+                          outputDesc, deviceTypes, delayMs, force);
     }
 }
 
@@ -5895,7 +5982,7 @@
                                          bool on,
                                          const sp<AudioOutputDescriptor>& outputDesc,
                                          int delayMs,
-                                         audio_devices_t device)
+                                         DeviceTypeSet deviceTypes)
 {
     std::vector<VolumeSource> sourcesToMute;
     for (auto attributes: mEngine->getAllAttributesForProductStrategy(strategy)) {
@@ -5907,7 +5994,7 @@
         }
     }
     for (auto source : sourcesToMute) {
-        setVolumeSourceMute(source, on, outputDesc, delayMs, device);
+        setVolumeSourceMute(source, on, outputDesc, delayMs, deviceTypes);
     }
 
 }
@@ -5916,10 +6003,10 @@
                                              bool on,
                                              const sp<AudioOutputDescriptor>& outputDesc,
                                              int delayMs,
-                                             audio_devices_t device)
+                                             DeviceTypeSet deviceTypes)
 {
-    if (device == AUDIO_DEVICE_NONE) {
-        device = outputDesc->devices().types();
+    if (deviceTypes.empty()) {
+        deviceTypes = outputDesc->devices().types();
     }
     auto &curves = getVolumeCurves(volumeSource);
     if (on) {
@@ -5928,7 +6015,7 @@
                     (volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE) ||
                      (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
                       AUDIO_POLICY_FORCE_NONE))) {
-                checkAndSetVolume(curves, volumeSource, 0, outputDesc, device, delayMs);
+                checkAndSetVolume(curves, volumeSource, 0, outputDesc, deviceTypes, delayMs);
             }
         }
         // increment mMuteCount after calling checkAndSetVolume() so that volume change is not
@@ -5941,9 +6028,9 @@
         }
         if (outputDesc->decMuteCount(volumeSource) == 0) {
             checkAndSetVolume(curves, volumeSource,
-                              curves.getVolumeIndex(device),
+                              curves.getVolumeIndex(deviceTypes),
                               outputDesc,
-                              device,
+                              deviceTypes,
                               delayMs);
         }
     }
@@ -5997,6 +6084,14 @@
     return is_state_in_call(state);
 }
 
+bool AudioPolicyManager::isCallAudioAccessible()
+{
+    audio_mode_t mode = mEngine->getPhoneState();
+    return (mode == AUDIO_MODE_IN_CALL)
+            || (mode == AUDIO_MODE_IN_COMMUNICATION)
+            || (mode == AUDIO_MODE_CALL_SCREEN);
+}
+
 void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
 {
     for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--)  {
@@ -6085,24 +6180,24 @@
         formatSet.insert(enforcedSurround.begin(), enforcedSurround.end());
     }
     for (const auto& format : formatSet) {
-        formatsPtr->push(format);
+        formatsPtr->push_back(format);
     }
 }
 
-void AudioPolicyManager::modifySurroundChannelMasks(ChannelsVector *channelMasksPtr) {
-    ChannelsVector &channelMasks = *channelMasksPtr;
+void AudioPolicyManager::modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr) {
+    ChannelMaskSet &channelMasks = *channelMasksPtr;
     audio_policy_forced_cfg_t forceUse = mEngine->getForceUse(
             AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND);
 
     // If NEVER, then remove support for channelMasks > stereo.
     if (forceUse == AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER) {
-        for (size_t maskIndex = 0; maskIndex < channelMasks.size(); ) {
-            audio_channel_mask_t channelMask = channelMasks[maskIndex];
+        for (auto it = channelMasks.begin(); it != channelMasks.end();) {
+            audio_channel_mask_t channelMask = *it;
             if (channelMask & ~AUDIO_CHANNEL_OUT_STEREO) {
                 ALOGI("%s: force NEVER, so remove channelMask 0x%08x", __FUNCTION__, channelMask);
-                channelMasks.removeAt(maskIndex);
+                it = channelMasks.erase(it);
             } else {
-                maskIndex++;
+                ++it;
             }
         }
     // If ALWAYS or MANUAL, then make sure we at least support 5.1
@@ -6118,7 +6213,7 @@
         }
         // If not then add 5.1 support.
         if (!supports5dot1) {
-            channelMasks.add(AUDIO_CHANNEL_OUT_5POINT1);
+            channelMasks.insert(AUDIO_CHANNEL_OUT_5POINT1);
             ALOGI("%s: force MANUAL or ALWAYS, so adding channelMask for 5.1 surround", __func__);
         }
     }
@@ -6147,12 +6242,12 @@
                 || isDeviceOfModule(devDesc, AUDIO_HARDWARE_MODULE_ID_MSD)) {
             modifySurroundFormats(devDesc, &formats);
         }
-        profiles.setFormats(formats);
+        addProfilesForFormats(profiles, formats);
     }
 
     for (audio_format_t format : profiles.getSupportedFormats()) {
-        ChannelsVector channelMasks;
-        SampleRateVector samplingRates;
+        ChannelMaskSet channelMasks;
+        SampleRateSet samplingRates;
         AudioParameter requestedParameters;
         requestedParameters.addInt(String8(AudioParameter::keyFormat), format);
 
@@ -6183,7 +6278,8 @@
                 }
             }
         }
-        profiles.addProfileFromHal(new AudioProfile(format, channelMasks, samplingRates));
+        addDynamicAudioProfileAndSort(
+                profiles, new AudioProfile(format, channelMasks, samplingRates));
     }
 }
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 5f651cc..322c188 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -31,15 +31,14 @@
 #include <utils/SortedVector.h>
 #include <media/AudioParameter.h>
 #include <media/AudioPolicy.h>
+#include <media/AudioProfile.h>
 #include <media/PatchBuilder.h>
 #include "AudioPolicyInterface.h"
 
 #include <AudioPolicyManagerObserver.h>
-#include <AudioGain.h>
 #include <AudioPolicyConfig.h>
-#include <AudioPort.h>
+#include <PolicyAudioPort.h>
 #include <AudioPatch.h>
-#include <AudioProfile.h>
 #include <DeviceDescriptor.h>
 #include <IOProfile.h>
 #include <HwModule.h>
@@ -122,7 +121,8 @@
                                   audio_output_flags_t *flags,
                                   audio_port_handle_t *selectedDeviceId,
                                   audio_port_handle_t *portId,
-                                  std::vector<audio_io_handle_t> *secondaryOutputs) override;
+                                  std::vector<audio_io_handle_t> *secondaryOutputs,
+                                  output_type_t *outputType) override;
         virtual status_t startOutput(audio_port_handle_t portId);
         virtual status_t stopOutput(audio_port_handle_t portId);
         virtual void releaseOutput(audio_port_handle_t portId);
@@ -177,7 +177,7 @@
                                      IVolumeCurves &volumeCurves);
 
         status_t getVolumeIndex(const IVolumeCurves &curves, int &index,
-                                audio_devices_t device) const;
+                                const DeviceTypeSet& deviceTypes) const;
 
         // return the strategy corresponding to a given stream type
         virtual uint32_t getStrategyForStream(audio_stream_type_t stream)
@@ -279,7 +279,7 @@
         virtual status_t getHwOffloadEncodingFormatsSupportedForA2DP(
                     std::vector<audio_format_t> *formats);
 
-        virtual void setAppState(uid_t uid, app_state_t state);
+        virtual void setAppState(audio_port_handle_t portId, app_state_t state);
 
         virtual bool isHapticPlaybackSupported();
 
@@ -307,6 +307,8 @@
             return volumeGroup != VOLUME_GROUP_NONE ? NO_ERROR : BAD_VALUE;
         }
 
+        bool isCallScreenModeSupported() override;
+
         status_t initialize();
 
 protected:
@@ -347,7 +349,7 @@
         }
         virtual const DeviceVector getAvailableOutputDevices() const
         {
-            return mAvailableOutputDevices;
+            return mAvailableOutputDevices.filterForEngine();
         }
         virtual const DeviceVector getAvailableInputDevices() const
         {
@@ -423,7 +425,7 @@
         virtual float computeVolume(IVolumeCurves &curves,
                                     VolumeSource volumeSource,
                                     int index,
-                                    audio_devices_t device);
+                                    const DeviceTypeSet& deviceTypes);
 
         // rescale volume index from srcStream within range of dstStream
         int rescaleVolumeIndex(int srcIndex,
@@ -433,12 +435,13 @@
         virtual status_t checkAndSetVolume(IVolumeCurves &curves,
                                            VolumeSource volumeSource, int index,
                                            const sp<AudioOutputDescriptor>& outputDesc,
-                                           audio_devices_t device,
+                                           DeviceTypeSet deviceTypes,
                                            int delayMs = 0, bool force = false);
 
         // apply all stream volumes to the specified output and device
         void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
-                                audio_devices_t device, int delayMs = 0, bool force = false);
+                                const DeviceTypeSet& deviceTypes,
+                                int delayMs = 0, bool force = false);
 
         /**
          * @brief setStrategyMute Mute or unmute all active clients on the considered output
@@ -453,7 +456,7 @@
                              bool on,
                              const sp<AudioOutputDescriptor>& outputDesc,
                              int delayMs = 0,
-                             audio_devices_t device = AUDIO_DEVICE_NONE);
+                             DeviceTypeSet deviceTypes = DeviceTypeSet());
 
         /**
          * @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
@@ -468,7 +471,7 @@
                                  bool on,
                                  const sp<AudioOutputDescriptor>& outputDesc,
                                  int delayMs = 0,
-                                 audio_devices_t device = AUDIO_DEVICE_NONE);
+                                 DeviceTypeSet deviceTypes = DeviceTypeSet());
 
         audio_mode_t getPhoneState();
 
@@ -476,6 +479,8 @@
         virtual bool isInCall();
         // true if given state represents a device in a telephony or VoIP call
         virtual bool isStateInCall(int state);
+        // true if playback to call TX or capture from call RX is possible
+        bool isCallAudioAccessible();
 
         // when a device is connected, checks if an open output can be routed
         // to this device. If none is open, tries to open one of the available outputs.
@@ -647,16 +652,13 @@
         }
         String8 getFirstDeviceAddress(const DeviceVector &devices) const
         {
-            return (devices.size() > 0) ? devices.itemAt(0)->address() : String8("");
+            return (devices.size() > 0) ?
+                    String8(devices.itemAt(0)->address().c_str()) : String8("");
         }
 
         uint32_t updateCallRouting(const DeviceVector &rxDevices, uint32_t delayMs = 0);
         sp<AudioPatch> createTelephonyPatch(bool isRx, const sp<DeviceDescriptor> &device,
                                             uint32_t delayMs);
-        sp<DeviceDescriptor> findDevice(
-                const DeviceVector& devices, audio_devices_t device) const;
-        audio_devices_t getModuleDeviceTypes(
-                const DeviceVector& devices, const char *moduleId) const;
         bool isDeviceOfModule(const sp<DeviceDescriptor>& devDesc, const char *moduleId) const;
 
         status_t startSource(const sp<SwAudioOutputDescriptor>& outputDesc,
@@ -763,7 +765,7 @@
 private:
         // Add or remove AC3 DTS encodings based on user preferences.
         void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr);
-        void modifySurroundChannelMasks(ChannelsVector *channelMasksPtr);
+        void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr);
 
         // Support for Multi-Stream Decoder (MSD) module
         sp<DeviceDescriptor> getMsdAudioInDevice() const;
@@ -808,7 +810,8 @@
                 audio_output_flags_t *flags,
                 audio_port_handle_t *selectedDeviceId,
                 bool *isRequestedDeviceForExclusiveUse,
-                std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
+                std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs,
+                output_type_t *outputType);
         // internal method to return the output handle for the given device and format
         audio_io_handle_t getOutputForDevices(
                 const DeviceVector &devices,
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index d51cc6e..6de0c80 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -39,8 +39,7 @@
 status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
                                                            audio_io_handle_t *output,
                                                            audio_config_t *config,
-                                                           audio_devices_t *devices,
-                                                           const String8& address,
+                                                           const sp<DeviceDescriptorBase>& device,
                                                            uint32_t *latencyMs,
                                                            audio_output_flags_t flags)
 {
@@ -49,7 +48,7 @@
         ALOGW("%s: could not get AudioFlinger", __func__);
         return PERMISSION_DENIED;
     }
-    return af->openOutput(module, output, config, devices, address, latencyMs, flags);
+    return af->openOutput(module, output, config, device, latencyMs, flags);
 }
 
 audio_io_handle_t AudioPolicyService::AudioPolicyClient::openDuplicateOutput(
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index fa8da89..feb930e 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -181,13 +181,13 @@
     if (mAudioPolicyManager == NULL) {
         return NO_INIT;
     }
-    ALOGV("getOutputForAttr()");
+    ALOGV("%s()", __func__);
     Mutex::Autolock _l(mLock);
 
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
     if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
         ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
-                "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+                "%s uid %d tried to pass itself off as %d", __func__, callingUid, uid);
         uid = callingUid;
     }
     if (!mPackageManager.allowPlaybackCapture(uid)) {
@@ -197,32 +197,44 @@
             && !bypassInterruptionPolicyAllowed(pid, uid)) {
         attr->flags &= ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE);
     }
-    audio_output_flags_t originalFlags = flags;
     AutoCallerClear acc;
+    AudioPolicyInterface::output_type_t outputType;
     status_t result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
                                                  config,
                                                  &flags, selectedDeviceId, portId,
-                                                 secondaryOutputs);
+                                                 secondaryOutputs,
+                                                 &outputType);
 
     // FIXME: Introduce a way to check for the the telephony device before opening the output
-    if ((result == NO_ERROR) &&
-        (flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) &&
-        !modifyPhoneStateAllowed(pid, uid)) {
-        // If the app tries to play music through the telephony device and doesn't have permission
-        // the fallback to the default output device.
-        mAudioPolicyManager->releaseOutput(*portId);
-        flags = originalFlags;
-        *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
-        *portId = AUDIO_PORT_HANDLE_NONE;
-        secondaryOutputs->clear();
-        result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, config,
-                                                       &flags, selectedDeviceId, portId,
-                                                       secondaryOutputs);
+    if (result == NO_ERROR) {
+        // enforce permission (if any) required for each type of input
+        switch (outputType) {
+        case AudioPolicyInterface::API_OUTPUT_LEGACY:
+            break;
+        case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
+            if (!modifyPhoneStateAllowed(pid, uid)) {
+                ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
+                    __func__, uid);
+                result = PERMISSION_DENIED;
+            }
+            break;
+        case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
+            if (!modifyAudioRoutingAllowed(pid, uid)) {
+                ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
+                    __func__, uid);
+                result = PERMISSION_DENIED;
+            }
+            break;
+        case AudioPolicyInterface::API_OUTPUT_INVALID:
+        default:
+            LOG_ALWAYS_FATAL("%s() encountered an invalid output type %d",
+                __func__, (int)outputType);
+        }
     }
 
     if (result == NO_ERROR) {
         sp <AudioPlaybackClient> client =
-            new AudioPlaybackClient(*attr, *output, uid, pid, session, *selectedDeviceId, *stream);
+            new AudioPlaybackClient(*attr, *output, uid, pid, session, *portId, *selectedDeviceId, *stream);
         mAudioPlaybackClients.add(*portId, client);
     }
     return result;
@@ -377,8 +389,10 @@
         pid = callingPid;
     }
 
-    // check calling permissions
-    if (!recordingAllowed(opPackageName, pid, uid)) {
+    // check calling permissions.
+    // Capturing from FM_TUNER source is controlled by captureAudioOutputAllowed() only as this
+    // does not affect users privacy as does capturing from an actual microphone.
+    if (!(recordingAllowed(opPackageName, pid, uid) || attr->source == AUDIO_SOURCE_FM_TUNER)) {
         ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
                 __func__, uid, pid);
         return PERMISSION_DENIED;
@@ -388,7 +402,8 @@
     if ((attr->source == AUDIO_SOURCE_VOICE_UPLINK ||
         attr->source == AUDIO_SOURCE_VOICE_DOWNLINK ||
         attr->source == AUDIO_SOURCE_VOICE_CALL ||
-        attr->source == AUDIO_SOURCE_ECHO_REFERENCE) &&
+        attr->source == AUDIO_SOURCE_ECHO_REFERENCE||
+        attr->source == AUDIO_SOURCE_FM_TUNER) &&
         !canCaptureOutput) {
         return PERMISSION_DENIED;
     }
@@ -431,7 +446,7 @@
                 }
                 break;
             case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
-                if (!modifyAudioRoutingAllowed()) {
+                if (!modifyAudioRoutingAllowed(pid, uid)) {
                     ALOGE("getInputForAttr() permission denied: modify audio routing not allowed");
                     status = PERMISSION_DENIED;
                 }
@@ -451,7 +466,7 @@
             return status;
         }
 
-        sp<AudioRecordClient> client = new AudioRecordClient(*attr, *input, uid, pid, session,
+        sp<AudioRecordClient> client = new AudioRecordClient(*attr, *input, uid, pid, session, *portId,
                                                              *selectedDeviceId, opPackageName,
                                                              canCaptureOutput, canCaptureHotword);
         mAudioRecordClients.add(*portId, client);
@@ -494,7 +509,8 @@
     }
 
     // check calling permissions
-    if (!startRecording(client->opPackageName, client->pid, client->uid)) {
+    if (!(startRecording(client->opPackageName, client->pid, client->uid)
+            || client->attributes.source == AUDIO_SOURCE_FM_TUNER)) {
         ALOGE("%s permission denied: recording not allowed for uid %d pid %d",
                 __func__, client->uid, client->pid);
         return PERMISSION_DENIED;
@@ -1325,4 +1341,15 @@
     return NO_ERROR;
 }
 
+bool AudioPolicyService::isCallScreenModeSupported()
+{
+    if (mAudioPolicyManager == NULL) {
+        ALOGW("%s, mAudioPolicyManager == NULL", __func__);
+        return false;
+    }
+    Mutex::Autolock _l(mLock);
+    AutoCallerClear acc;
+    return mAudioPolicyManager->isCallScreenModeSupported();
+}
+
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 90939ce..c8d7d0c 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -406,8 +406,7 @@
 {
 //    Go over all active clients and allow capture (does not force silence) in the
 //    following cases:
-//    Another client in the same UID has already been allowed to capture
-//    OR The client is the assistant
+//    The client is the assistant
 //        AND an accessibility service is on TOP or a RTT call is active
 //                AND the source is VOICE_RECOGNITION or HOTWORD
 //            OR uses VOICE_RECOGNITION AND is on TOP
@@ -423,12 +422,18 @@
 //        AND is on TOP
 //        AND the source is VOICE_RECOGNITION or HOTWORD
 //    OR the client source is virtual (remote submix, call audio TX or RX...)
+//    OR the client source is HOTWORD
+//        AND is on TOP
+//            OR all active clients are using HOTWORD source
+//        AND no call is active
+//            OR client has CAPTURE_AUDIO_OUTPUT privileged permission
 //    OR Any client
 //        AND The assistant is not on TOP
 //        AND is on TOP or latest started
 //        AND there is no active privacy sensitive capture or call
 //            OR client has CAPTURE_AUDIO_OUTPUT privileged permission
 
+
     sp<AudioRecordClient> topActive;
     sp<AudioRecordClient> latestActive;
     sp<AudioRecordClient> latestSensitiveActive;
@@ -443,6 +448,7 @@
     bool rttCallActive =
             (mPhoneState == AUDIO_MODE_IN_CALL || mPhoneState == AUDIO_MODE_IN_COMMUNICATION)
             && mUidPolicy->isRttEnabled();
+    bool onlyHotwordActive = true;
 
     // if Sensor Privacy is enabled then all recordings should be silenced.
     if (mSensorPrivacyPolicy->isSensorPrivacyEnabled()) {
@@ -474,12 +480,11 @@
                 isAssistantOnTop = true;
             }
         }
-        // Assistant capturing for HOTWORD or Accessibility services not considered
+        // Client capturing for HOTWORD or Accessibility services not considered
         // for latest active to avoid masking regular clients started before
         if (current->startTimeNs > latestStartNs
-                && !((current->attributes.source == AUDIO_SOURCE_HOTWORD
-                        || isA11yOnTop || rttCallActive)
-                    && isAssistant)
+                && !(current->attributes.source == AUDIO_SOURCE_HOTWORD
+                        || ((isA11yOnTop || rttCallActive) && isAssistant))
                 && !isAccessibility) {
             latestActive = current;
             latestStartNs = current->startTimeNs;
@@ -491,6 +496,9 @@
             }
             isSensitiveActive = true;
         }
+        if (current->attributes.source != AUDIO_SOURCE_HOTWORD) {
+            onlyHotwordActive = false;
+        }
     }
 
     // if no active client with UI on Top, consider latest active as top
@@ -498,21 +506,12 @@
         topActive = latestActive;
     }
 
-    std::vector<uid_t> enabledUids;
-
     for (size_t i =0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
         if (!current->active) {
             continue;
         }
 
-        // keep capture allowed if another client with the same UID has already
-        // been allowed to capture
-        if (std::find(enabledUids.begin(), enabledUids.end(), current->uid)
-                != enabledUids.end()) {
-            continue;
-        }
-
         audio_source_t source = current->attributes.source;
         bool isTopOrLatestActive = topActive == nullptr ? false : current->uid == topActive->uid;
         bool isLatestSensitive = latestSensitiveActive == nullptr ?
@@ -552,29 +551,32 @@
             }
         } else if (mUidPolicy->isA11yUid(current->uid)) {
             // For accessibility service allow capture if:
-            //     Is on TOP
-            //          AND the source is VOICE_RECOGNITION or HOTWORD
-            //     Or
-            //          The assistant is not on TOP
-            //          AND there is no active privacy sensitive capture or call
+            //     The assistant is not on TOP
+            //         AND there is no active privacy sensitive capture or call
             //             OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+            //     OR
+            //         Is on TOP AND the source is VOICE_RECOGNITION or HOTWORD
+            if (!isAssistantOnTop
+                    && (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) {
+                allowCapture = true;
+            }
             if (isA11yOnTop) {
                 if (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD) {
                     allowCapture = true;
                 }
-            } else {
-                if (!isAssistantOnTop
-                        && (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) {
-                    allowCapture = true;
-                }
+            }
+        } else if (source == AUDIO_SOURCE_HOTWORD) {
+            // For HOTWORD source allow capture when not on TOP if:
+            //     All active clients are using HOTWORD source
+            //     AND no call is active
+            //         OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+            if (onlyHotwordActive && !(isInCall && !current->canCaptureOutput)) {
+                allowCapture = true;
             }
         }
-        setAppState_l(current->uid,
+        setAppState_l(current->portId,
                       allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
                                 APP_STATE_IDLE);
-        if (allowCapture) {
-            enabledUids.push_back(current->uid);
-        }
     }
 }
 
@@ -582,7 +584,7 @@
     for (size_t i = 0; i < mAudioRecordClients.size(); i++) {
         sp<AudioRecordClient> current = mAudioRecordClients[i];
         if (!isVirtualSource(current->attributes.source)) {
-            setAppState_l(current->uid, APP_STATE_IDLE);
+            setAppState_l(current->portId, APP_STATE_IDLE);
         }
     }
 }
@@ -628,17 +630,17 @@
     return false;
 }
 
-void AudioPolicyService::setAppState_l(uid_t uid, app_state_t state)
+void AudioPolicyService::setAppState_l(audio_port_handle_t portId, app_state_t state)
 {
     AutoCallerClear acc;
 
     if (mAudioPolicyManager) {
-        mAudioPolicyManager->setAppState(uid, state);
+        mAudioPolicyManager->setAppState(portId, state);
     }
     sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
     if (af) {
         bool silenced = state == APP_STATE_IDLE;
-        af->setRecordSilenced(uid, silenced);
+        af->setRecordSilenced(portId, silenced);
     }
 }
 
@@ -975,7 +977,8 @@
 
 void AudioPolicyService::UidPolicy::onUidStateChanged(uid_t uid,
                                                       int32_t procState,
-                                                      int64_t procStateSeq __unused) {
+                                                      int64_t procStateSeq __unused,
+                                                      int32_t capability __unused) {
     if (procState != ActivityManager::PROCESS_STATE_UNKNOWN) {
         updateUid(&mCachedUids, uid, true, procState, true);
     }
@@ -1040,8 +1043,7 @@
 
 bool AudioPolicyService::UidPolicy::isA11yOnTop() {
     for (const auto &uid : mCachedUids) {
-        std::vector<uid_t>::iterator it = find(mA11yUids.begin(), mA11yUids.end(), uid.first);
-        if (it == mA11yUids.end()) {
+        if (!isA11yUid(uid.first)) {
             continue;
         }
         if (uid.second.second >= ActivityManager::PROCESS_STATE_TOP
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 74aea0d..2bd02c8 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -259,6 +259,8 @@
 
     virtual status_t setRttEnabled(bool enabled);
 
+            bool isCallScreenModeSupported() override;
+
             status_t doStopOutput(audio_port_handle_t portId);
             void doReleaseOutput(audio_port_handle_t portId);
 
@@ -311,7 +313,7 @@
     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(uid_t uid, app_state_t state);
+    virtual void setAppState_l(audio_port_handle_t portId, app_state_t state);
 
     // Overrides the UID state as if it is idle
     status_t handleSetUidState(Vector<String16>& args, int err);
@@ -371,7 +373,8 @@
         void onUidActive(uid_t uid) override;
         void onUidGone(uid_t uid, bool disabled) override;
         void onUidIdle(uid_t uid, bool disabled) override;
-        void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
+        void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+                int32_t capability);
 
         void addOverrideUid(uid_t uid, bool active) { updateOverrideUid(uid, active, true); }
         void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
@@ -622,8 +625,7 @@
         virtual status_t openOutput(audio_module_handle_t module,
                                     audio_io_handle_t *output,
                                     audio_config_t *config,
-                                    audio_devices_t *devices,
-                                    const String8& address,
+                                    const sp<DeviceDescriptorBase>& device,
                                     uint32_t *latencyMs,
                                     audio_output_flags_t flags);
         // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
@@ -759,9 +761,10 @@
     public:
                 AudioClient(const audio_attributes_t attributes,
                             const audio_io_handle_t io, uid_t uid, pid_t pid,
-                            const audio_session_t session, const audio_port_handle_t deviceId) :
+                            const audio_session_t session,  audio_port_handle_t portId,
+                            const audio_port_handle_t deviceId) :
                                 attributes(attributes), io(io), uid(uid), pid(pid),
-                                session(session), deviceId(deviceId), active(false) {}
+                                session(session), portId(portId), deviceId(deviceId), active(false) {}
                 ~AudioClient() override = default;
 
 
@@ -770,6 +773,7 @@
         const uid_t uid;                     // client UID
         const pid_t pid;                     // client PID
         const audio_session_t session;       // audio session ID
+        const audio_port_handle_t portId;
         const audio_port_handle_t deviceId;  // selected input device port ID
               bool active;                   // Playback/Capture is active or inactive
     };
@@ -781,10 +785,10 @@
     public:
                 AudioRecordClient(const audio_attributes_t attributes,
                           const audio_io_handle_t io, uid_t uid, pid_t pid,
-                          const audio_session_t session, const audio_port_handle_t deviceId,
-                          const String16& opPackageName,
+                          const audio_session_t session, audio_port_handle_t portId,
+                          const audio_port_handle_t deviceId, const String16& opPackageName,
                           bool canCaptureOutput, bool canCaptureHotword) :
-                    AudioClient(attributes, io, uid, pid, session, deviceId),
+                    AudioClient(attributes, io, uid, pid, session, portId, deviceId),
                     opPackageName(opPackageName), startTimeNs(0),
                     canCaptureOutput(canCaptureOutput), canCaptureHotword(canCaptureHotword) {}
                 ~AudioRecordClient() override = default;
@@ -802,9 +806,9 @@
     public:
                 AudioPlaybackClient(const audio_attributes_t attributes,
                       const audio_io_handle_t io, uid_t uid, pid_t pid,
-                            const audio_session_t session, audio_port_handle_t deviceId,
-                            audio_stream_type_t stream) :
-                    AudioClient(attributes, io, uid, pid, session, deviceId), stream(stream) {}
+                            const audio_session_t session, audio_port_handle_t portId,
+                            audio_port_handle_t deviceId, audio_stream_type_t stream) :
+                    AudioClient(attributes, io, uid, pid, session, portId, deviceId), stream(stream) {}
                 ~AudioPlaybackClient() override = default;
 
         const audio_stream_type_t stream;
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
new file mode 100644
index 0000000..efdb241
--- /dev/null
+++ b/services/audiopolicy/tests/Android.bp
@@ -0,0 +1,71 @@
+cc_test {
+    name: "audiopolicy_tests",
+
+    include_dirs: [
+        "frameworks/av/services/audiopolicy",
+    ],
+
+    shared_libs: [
+        "libaudioclient",
+        "libaudiofoundation",
+        "libaudiopolicy",
+        "libaudiopolicymanagerdefault",
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+        "libxml2",
+    ],
+
+    static_libs: ["libaudiopolicycomponents"],
+
+    header_libs: [
+        "libaudiopolicycommon",
+        "libaudiopolicyengine_interface_headers",
+        "libaudiopolicymanager_interface_headers",
+    ],
+
+    srcs: ["audiopolicymanager_tests.cpp"],
+
+    data: [":audiopolicytest_configuration_files",],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+
+}
+
+
+cc_test {
+    name: "audio_health_tests",
+
+    shared_libs: [
+        "libaudiofoundation",
+        "libaudioclient",
+        "libaudiopolicymanagerdefault",
+        "liblog",
+        "libmedia_helper",
+        "libutils",
+    ],
+
+    static_libs: ["libaudiopolicycomponents"],
+
+    header_libs: [
+        "libaudiopolicyengine_interface_headers",
+        "libaudiopolicymanager_interface_headers",
+    ],
+
+    srcs: ["audio_health_tests.cpp"],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+
+}
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
deleted file mode 100644
index ab9f78b..0000000
--- a/services/audiopolicy/tests/Android.mk
+++ /dev/null
@@ -1,65 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
-  frameworks/av/services/audiopolicy \
-  $(call include-path-for, audio-utils) \
-
-LOCAL_SHARED_LIBRARIES := \
-  libaudiopolicymanagerdefault \
-  libbase \
-  liblog \
-  libmedia_helper \
-  libutils \
-
-LOCAL_STATIC_LIBRARIES := \
-  libaudiopolicycomponents \
-
-LOCAL_HEADER_LIBRARIES := \
-    libaudiopolicycommon \
-    libaudiopolicyengine_interface_headers \
-    libaudiopolicymanager_interface_headers
-
-LOCAL_SRC_FILES := \
-  audiopolicymanager_tests.cpp \
-
-LOCAL_MODULE := audiopolicy_tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_NATIVE_TEST)
-
-# system/audio.h utilities test
-
-include $(CLEAR_VARS)
-
-LOCAL_SHARED_LIBRARIES := \
-  libbase \
-  liblog \
-  libmedia_helper \
-  libutils
-
-LOCAL_HEADER_LIBRARIES := \
-  libmedia_headers
-
-LOCAL_SRC_FILES := \
-  systemaudio_tests.cpp \
-
-LOCAL_MODULE := systemaudio_tests
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := -Werror -Wall
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
new file mode 100644
index 0000000..c2a92d7
--- /dev/null
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "AudioPolicyTestClient.h"
+
+namespace android {
+
+class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
+public:
+    // AudioPolicyClientInterface implementation
+    audio_module_handle_t loadHwModule(const char * /*name*/) override {
+        return mNextModuleHandle++;
+    }
+
+    status_t openOutput(audio_module_handle_t module,
+                        audio_io_handle_t *output,
+                        audio_config_t * /*config*/,
+                        const sp<DeviceDescriptorBase>& /*device*/,
+                        uint32_t * /*latencyMs*/,
+                        audio_output_flags_t /*flags*/) override {
+        if (module >= mNextModuleHandle) {
+            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+                  __func__, module, mNextModuleHandle);
+            return BAD_VALUE;
+        }
+        *output = mNextIoHandle++;
+        return NO_ERROR;
+    }
+
+    audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
+                                          audio_io_handle_t /*output2*/) override {
+        audio_io_handle_t id = mNextIoHandle++;
+        return id;
+    }
+
+    status_t openInput(audio_module_handle_t module,
+                       audio_io_handle_t *input,
+                       audio_config_t * /*config*/,
+                       audio_devices_t * /*device*/,
+                       const String8 & /*address*/,
+                       audio_source_t /*source*/,
+                       audio_input_flags_t /*flags*/) override {
+        if (module >= mNextModuleHandle) {
+            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
+                  __func__, module, mNextModuleHandle);
+            return BAD_VALUE;
+        }
+        *input = mNextIoHandle++;
+        return NO_ERROR;
+    }
+
+    status_t createAudioPatch(const struct audio_patch *patch,
+                              audio_patch_handle_t *handle,
+                              int /*delayMs*/) override {
+        *handle = mNextPatchHandle++;
+        mActivePatches.insert(std::make_pair(*handle, *patch));
+        return NO_ERROR;
+    }
+
+    status_t releaseAudioPatch(audio_patch_handle_t handle,
+                               int /*delayMs*/) override {
+        if (mActivePatches.erase(handle) != 1) {
+            if (handle >= mNextPatchHandle) {
+                ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
+                      __func__, handle, mNextPatchHandle);
+            } else {
+                ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
+            }
+            return BAD_VALUE;
+        }
+        return NO_ERROR;
+    }
+
+    // Helper methods for tests
+    size_t getActivePatchesCount() const { return mActivePatches.size(); }
+
+    const struct audio_patch *getLastAddedPatch() const {
+        if (mActivePatches.empty()) {
+            return nullptr;
+        }
+        auto it = --mActivePatches.end();
+        return &it->second;
+    };
+
+private:
+    audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
+    audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
+    audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
+    std::map<audio_patch_handle_t, struct audio_patch> mActivePatches;
+};
+
+} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index e4c64e5..b92a2e6 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -31,8 +31,7 @@
     status_t openOutput(audio_module_handle_t /*module*/,
                         audio_io_handle_t* /*output*/,
                         audio_config_t* /*config*/,
-                        audio_devices_t* /*devices*/,
-                        const String8& /*address*/,
+                        const sp<DeviceDescriptorBase>& /*device*/,
                         uint32_t* /*latencyMs*/,
                         audio_output_flags_t /*flags*/) override { return NO_INIT; }
     audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index fe543a6..bafcc63 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -24,7 +24,9 @@
     explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
             : AudioPolicyManager(clientInterface, true /*forTesting*/) { }
     using AudioPolicyManager::getConfig;
+    using AudioPolicyManager::loadConfig;
     using AudioPolicyManager::initialize;
+    using AudioPolicyManager::getOutputs;
 };
 
 }  // namespace android
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
new file mode 100644
index 0000000..8736cf1
--- /dev/null
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioPolicy_Boot_Test"
+
+#include <unordered_set>
+
+#include <gtest/gtest.h>
+
+#include <media/AudioSystem.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include "AudioPolicyManagerTestClient.h"
+#include "AudioPolicyTestManager.h"
+
+using namespace android;
+
+TEST(AudioHealthTest, AttachedDeviceFound) {
+    unsigned int numPorts;
+    unsigned int generation1;
+    unsigned int generation;
+    struct audio_port *audioPorts = NULL;
+    int attempts = 10;
+    do {
+        if (attempts-- < 0) {
+            free(audioPorts);
+            GTEST_FAIL() << "Query audio ports time out";
+        }
+        numPorts = 0;
+        ASSERT_EQ(NO_ERROR, AudioSystem::listAudioPorts(
+                AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, NULL, &generation1));
+        if (numPorts == 0) {
+            free(audioPorts);
+            GTEST_FAIL() << "Number of audio ports should not be zero";
+        }
+
+        audioPorts = (struct audio_port *)realloc(audioPorts, numPorts * sizeof(struct audio_port));
+        status_t status = AudioSystem::listAudioPorts(
+                AUDIO_PORT_ROLE_NONE, AUDIO_PORT_TYPE_DEVICE, &numPorts, audioPorts, &generation);
+        if (status != NO_ERROR) {
+            free(audioPorts);
+            GTEST_FAIL() << "Query audio ports failed";
+        }
+    } while (generation1 != generation);
+    std::unordered_set<audio_devices_t> attachedDevices;
+    for (int i = 0 ; i < numPorts; i++) {
+        attachedDevices.insert(audioPorts[i].ext.device.type);
+    }
+    free(audioPorts);
+
+    AudioPolicyManagerTestClient client;
+    AudioPolicyTestManager manager(&client);
+    manager.loadConfig();
+    ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+
+    for (auto desc : manager.getConfig().getAvailableInputDevices()) {
+        ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+    }
+    for (auto desc : manager.getConfig().getAvailableOutputDevices()) {
+        ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
+    }
+}
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index e10a716..e4a19ea 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -15,16 +15,23 @@
  */
 
 #include <memory>
-#include <set>
+#include <string>
 #include <sys/wait.h>
 #include <unistd.h>
 
 #include <gtest/gtest.h>
 
 #define LOG_TAG "APM_Test"
-#include <log/log.h>
+#include <Serializer.h>
+#include <android-base/file.h>
+#include <media/AudioPolicy.h>
 #include <media/PatchBuilder.h>
+#include <media/RecordingActivityTracker.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
 
+#include "AudioPolicyInterface.h"
+#include "AudioPolicyManagerTestClient.h"
 #include "AudioPolicyTestClient.h"
 #include "AudioPolicyTestManager.h"
 
@@ -50,77 +57,6 @@
 }
 
 
-class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
-  public:
-    // AudioPolicyClientInterface implementation
-    audio_module_handle_t loadHwModule(const char* /*name*/) override {
-        return mNextModuleHandle++;
-    }
-
-    status_t openOutput(audio_module_handle_t module,
-                        audio_io_handle_t* output,
-                        audio_config_t* /*config*/,
-                        audio_devices_t* /*devices*/,
-                        const String8& /*address*/,
-                        uint32_t* /*latencyMs*/,
-                        audio_output_flags_t /*flags*/) override {
-        if (module >= mNextModuleHandle) {
-            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
-                    __func__, module, mNextModuleHandle);
-            return BAD_VALUE;
-        }
-        *output = mNextIoHandle++;
-        return NO_ERROR;
-    }
-
-    status_t openInput(audio_module_handle_t module,
-                       audio_io_handle_t* input,
-                       audio_config_t* /*config*/,
-                       audio_devices_t* /*device*/,
-                       const String8& /*address*/,
-                       audio_source_t /*source*/,
-                       audio_input_flags_t /*flags*/) override {
-        if (module >= mNextModuleHandle) {
-            ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
-                    __func__, module, mNextModuleHandle);
-            return BAD_VALUE;
-        }
-        *input = mNextIoHandle++;
-        return NO_ERROR;
-    }
-
-    status_t createAudioPatch(const struct audio_patch* /*patch*/,
-                              audio_patch_handle_t* handle,
-                              int /*delayMs*/) override {
-        *handle = mNextPatchHandle++;
-        mActivePatches.insert(*handle);
-        return NO_ERROR;
-    }
-
-    status_t releaseAudioPatch(audio_patch_handle_t handle,
-                               int /*delayMs*/) override {
-        if (mActivePatches.erase(handle) != 1) {
-            if (handle >= mNextPatchHandle) {
-                ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
-                        __func__, handle, mNextPatchHandle);
-            } else {
-                ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
-            }
-            return BAD_VALUE;
-        }
-        return NO_ERROR;
-    }
-
-    // Helper methods for tests
-    size_t getActivePatchesCount() const { return mActivePatches.size(); }
-
-  private:
-    audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
-    audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
-    audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
-    std::set<audio_patch_handle_t> mActivePatches;
-};
-
 class PatchCountCheck {
   public:
     explicit PatchCountCheck(AudioPolicyManagerTestClient *client)
@@ -143,18 +79,35 @@
   protected:
     void SetUp() override;
     void TearDown() override;
-    virtual void SetUpConfig(AudioPolicyConfig *config) { (void)config; }
+    virtual void SetUpManagerConfig();
 
     void dumpToLog();
+    // When explicit routing is needed, selectedDeviceId needs to be set as the wanted port
+    // id. Otherwise, selectedDeviceId needs to be initialized as AUDIO_PORT_HANDLE_NONE.
     void getOutputForAttr(
             audio_port_handle_t *selectedDeviceId,
             audio_format_t format,
             int channelMask,
             int sampleRate,
             audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+            audio_io_handle_t *output = nullptr,
+            audio_port_handle_t *portId = nullptr,
+            audio_attributes_t attr = {});
+    void getInputForAttr(
+            const audio_attributes_t &attr,
+            audio_unique_id_t riid,
+            audio_port_handle_t *selectedDeviceId,
+            audio_format_t format,
+            int channelMask,
+            int sampleRate,
+            audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
             audio_port_handle_t *portId = nullptr);
     PatchCountCheck snapshotPatchCount() { return PatchCountCheck(mClient.get()); }
 
+    void findDevicePort(audio_port_role_t role, audio_devices_t deviceType,
+            const std::string &address, audio_port &foundPort);
+    static audio_port_handle_t getDeviceIdFromPatch(const struct audio_patch* patch);
+
     std::unique_ptr<AudioPolicyManagerTestClient> mClient;
     std::unique_ptr<AudioPolicyTestManager> mManager;
 };
@@ -162,8 +115,7 @@
 void AudioPolicyManagerTest::SetUp() {
     mClient.reset(new AudioPolicyManagerTestClient);
     mManager.reset(new AudioPolicyTestManager(mClient.get()));
-    mManager->getConfig().setDefault();
-    SetUpConfig(&mManager->getConfig());  // Subclasses may want to customize the config.
+    SetUpManagerConfig();  // Subclasses may want to customize the config.
     ASSERT_EQ(NO_ERROR, mManager->initialize());
     ASSERT_EQ(NO_ERROR, mManager->initCheck());
 }
@@ -173,6 +125,10 @@
     mClient.reset();
 }
 
+void AudioPolicyManagerTest::SetUpManagerConfig() {
+    mManager->getConfig().setDefault();
+}
+
 void AudioPolicyManagerTest::dumpToLog() {
     int pipefd[2];
     ASSERT_NE(-1, pipe(pipefd));
@@ -209,22 +165,91 @@
         int channelMask,
         int sampleRate,
         audio_output_flags_t flags,
-        audio_port_handle_t *portId) {
-    audio_attributes_t attr = {};
-    audio_io_handle_t output = AUDIO_PORT_HANDLE_NONE;
+        audio_io_handle_t *output,
+        audio_port_handle_t *portId,
+        audio_attributes_t attr) {
+    audio_io_handle_t localOutput;
+    if (!output) output = &localOutput;
+    *output = AUDIO_IO_HANDLE_NONE;
     audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
     audio_config_t config = AUDIO_CONFIG_INITIALIZER;
     config.sample_rate = sampleRate;
     config.channel_mask = channelMask;
     config.format = format;
-    *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     audio_port_handle_t localPortId;
     if (!portId) portId = &localPortId;
     *portId = AUDIO_PORT_HANDLE_NONE;
+    AudioPolicyInterface::output_type_t outputType;
     ASSERT_EQ(OK, mManager->getOutputForAttr(
-                    &attr, &output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
-                    selectedDeviceId, portId, {}));
+                    &attr, output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
+                    selectedDeviceId, portId, {}, &outputType));
     ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+    ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
+}
+
+void AudioPolicyManagerTest::getInputForAttr(
+        const audio_attributes_t &attr,
+        audio_unique_id_t riid,
+        audio_port_handle_t *selectedDeviceId,
+        audio_format_t format,
+        int channelMask,
+        int sampleRate,
+        audio_input_flags_t flags,
+        audio_port_handle_t *portId) {
+    audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
+    audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
+    config.sample_rate = sampleRate;
+    config.channel_mask = channelMask;
+    config.format = format;
+    audio_port_handle_t localPortId;
+    if (!portId) portId = &localPortId;
+    *portId = AUDIO_PORT_HANDLE_NONE;
+    AudioPolicyInterface::input_type_t inputType;
+    ASSERT_EQ(OK, mManager->getInputForAttr(
+            &attr, &input, riid, AUDIO_SESSION_NONE, 0 /*uid*/, &config, flags,
+            selectedDeviceId, &inputType, portId));
+    ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
+}
+
+void AudioPolicyManagerTest::findDevicePort(audio_port_role_t role,
+        audio_devices_t deviceType, const std::string &address, audio_port &foundPort) {
+    uint32_t numPorts = 0;
+    uint32_t generation1;
+    status_t ret;
+
+    ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, nullptr, &generation1);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    uint32_t generation2;
+    struct audio_port ports[numPorts];
+    ret = mManager->listAudioPorts(role, AUDIO_PORT_TYPE_DEVICE, &numPorts, ports, &generation2);
+    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_EQ(generation1, generation2);
+
+    for (const auto &port : ports) {
+        if (port.role == role && port.ext.device.type == deviceType &&
+                (strncmp(port.ext.device.address, address.c_str(),
+                         AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+            foundPort = port;
+            return;
+        }
+    }
+    GTEST_FAIL() << "Device port with role " << role << " and address " << address << "not found";
+}
+
+audio_port_handle_t AudioPolicyManagerTest::getDeviceIdFromPatch(
+        const struct audio_patch* patch) {
+    // The logic here is the same as the one in AudioIoDescriptor.
+    // Note this function is aim to get routed device id for test.
+    // In that case, device to device patch is not expected here.
+    if (patch->num_sources != 0 && patch->num_sinks != 0) {
+        if (patch->sources[0].type == AUDIO_PORT_TYPE_MIX) {
+            return patch->sinks[0].id;
+        } else {
+            return patch->sources[0].id;
+        }
+    }
+    return AUDIO_PORT_HANDLE_NONE;
 }
 
 
@@ -286,15 +311,17 @@
 
 class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest {
   protected:
-    void SetUpConfig(AudioPolicyConfig *config) override;
+    void SetUpManagerConfig() override;
     void TearDown() override;
 
     sp<DeviceDescriptor> mMsdOutputDevice;
     sp<DeviceDescriptor> mMsdInputDevice;
 };
 
-void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
+void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
     // TODO: Consider using Serializer to load part of the config from a string.
+    AudioPolicyManagerTest::SetUpManagerConfig();
+    AudioPolicyConfig& config = mManager->getConfig();
     mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
     sp<AudioProfile> pcmOutputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
@@ -307,22 +334,21 @@
     sp<AudioProfile> pcmInputProfile = new AudioProfile(
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
     mMsdInputDevice->addAudioProfile(pcmInputProfile);
-    config->addAvailableDevice(mMsdOutputDevice);
-    config->addAvailableDevice(mMsdInputDevice);
+    config.addAvailableDevice(mMsdOutputDevice);
+    config.addAvailableDevice(mMsdInputDevice);
 
     sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
-    HwModuleCollection modules = config->getHwModules();
+    HwModuleCollection modules = config.getHwModules();
     modules.add(msdModule);
-    config->setHwModules(modules);
+    config.setHwModules(modules);
     mMsdOutputDevice->attach(msdModule);
     mMsdInputDevice->attach(msdModule);
 
-    sp<OutputProfile> msdOutputProfile = new OutputProfile(String8("msd input"));
+    sp<OutputProfile> msdOutputProfile = new OutputProfile("msd input");
     msdOutputProfile->addAudioProfile(pcmOutputProfile);
     msdOutputProfile->addSupportedDevice(mMsdOutputDevice);
     msdModule->addOutputProfile(msdOutputProfile);
-    sp<OutputProfile> msdCompressedOutputProfile =
-            new OutputProfile(String8("msd compressed input"));
+    sp<OutputProfile> msdCompressedOutputProfile = new OutputProfile("msd compressed input");
     msdCompressedOutputProfile->addAudioProfile(ac3OutputProfile);
     msdCompressedOutputProfile->setFlags(
             AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
@@ -330,7 +356,7 @@
     msdCompressedOutputProfile->addSupportedDevice(mMsdOutputDevice);
     msdModule->addOutputProfile(msdCompressedOutputProfile);
 
-    sp<InputProfile> msdInputProfile = new InputProfile(String8("msd output"));
+    sp<InputProfile> msdInputProfile = new InputProfile("msd output");
     msdInputProfile->addAudioProfile(pcmInputProfile);
     msdInputProfile->addSupportedDevice(mMsdInputDevice);
     msdModule->addInputProfile(msdInputProfile);
@@ -339,12 +365,12 @@
     // of streams that are not supported by MSD.
     sp<AudioProfile> dtsOutputProfile = new AudioProfile(
             AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000);
-    config->getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
-    sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile(String8("encoded"));
+    config.getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
+    sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile("encoded");
     primaryEncodedOutputProfile->addAudioProfile(dtsOutputProfile);
     primaryEncodedOutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
-    primaryEncodedOutputProfile->addSupportedDevice(config->getDefaultOutputDevice());
-    config->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
+    primaryEncodedOutputProfile->addSupportedDevice(config.getDefaultOutputDevice());
+    config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
             addOutputProfile(primaryEncodedOutputProfile);
 }
 
@@ -372,7 +398,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -381,7 +407,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -390,7 +416,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
@@ -403,7 +429,7 @@
 
 TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) {
     const PatchCountCheck patchCount = snapshotPatchCount();
-    audio_port_handle_t selectedDeviceId;
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
     getOutputForAttr(&selectedDeviceId,
             AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
     ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
@@ -414,10 +440,11 @@
     // Switch between formats that are supported and not supported by MSD.
     {
         const PatchCountCheck patchCount = snapshotPatchCount();
-        audio_port_handle_t selectedDeviceId, portId;
+        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+        audio_port_handle_t portId;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
-                &portId);
+                nullptr /*output*/, &portId);
         ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
         ASSERT_EQ(1, patchCount.deltaFromSnapshot());
         mManager->releaseOutput(portId);
@@ -425,10 +452,11 @@
     }
     {
         const PatchCountCheck patchCount = snapshotPatchCount();
-        audio_port_handle_t selectedDeviceId, portId;
+        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+        audio_port_handle_t portId;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
-                &portId);
+                nullptr /*output*/, &portId);
         ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
         ASSERT_EQ(-1, patchCount.deltaFromSnapshot());
         mManager->releaseOutput(portId);
@@ -436,10 +464,662 @@
     }
     {
         const PatchCountCheck patchCount = snapshotPatchCount();
-        audio_port_handle_t selectedDeviceId;
+        audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
         getOutputForAttr(&selectedDeviceId,
                 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
         ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
         ASSERT_EQ(0, patchCount.deltaFromSnapshot());
     }
 }
+
+class AudioPolicyManagerTestWithConfigurationFile : public AudioPolicyManagerTest {
+protected:
+    void SetUpManagerConfig() override;
+    virtual std::string getConfigFile() { return sDefaultConfig; }
+
+    static const std::string sExecutableDir;
+    static const std::string sDefaultConfig;
+};
+
+const std::string AudioPolicyManagerTestWithConfigurationFile::sExecutableDir =
+        base::GetExecutableDirectory() + "/";
+
+const std::string AudioPolicyManagerTestWithConfigurationFile::sDefaultConfig =
+        sExecutableDir + "test_audio_policy_configuration.xml";
+
+void AudioPolicyManagerTestWithConfigurationFile::SetUpManagerConfig() {
+    status_t status = deserializeAudioPolicyFile(getConfigFile().c_str(), &mManager->getConfig());
+    ASSERT_EQ(NO_ERROR, status);
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, Dump) {
+    dumpToLog();
+}
+
+using PolicyMixTuple = std::tuple<audio_usage_t, audio_source_t, uint32_t>;
+
+class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+    void TearDown() override;
+
+    status_t addPolicyMix(int mixType, int mixFlag, audio_devices_t deviceType,
+            std::string mixAddress, const audio_config_t& audioConfig,
+            const std::vector<PolicyMixTuple>& rules);
+    void clearPolicyMix();
+
+    Vector<AudioMix> mAudioMixes;
+    const std::string mMixAddress = "remote_submix_media";
+};
+
+void AudioPolicyManagerTestDynamicPolicy::TearDown() {
+    mManager->unregisterPolicyMixes(mAudioMixes);
+    AudioPolicyManagerTestWithConfigurationFile::TearDown();
+}
+
+status_t AudioPolicyManagerTestDynamicPolicy::addPolicyMix(int mixType, int mixFlag,
+        audio_devices_t deviceType, std::string mixAddress, const audio_config_t& audioConfig,
+        const std::vector<PolicyMixTuple>& rules) {
+    Vector<AudioMixMatchCriterion> myMixMatchCriteria;
+
+    for(const auto &rule: rules) {
+        myMixMatchCriteria.add(AudioMixMatchCriterion(
+                std::get<0>(rule), std::get<1>(rule), std::get<2>(rule)));
+    }
+
+    AudioMix myAudioMix(myMixMatchCriteria, mixType, audioConfig, mixFlag,
+            String8(mixAddress.c_str()), 0);
+    myAudioMix.mDeviceType = deviceType;
+    // Clear mAudioMix before add new one to make sure we don't add already exist mixes.
+    mAudioMixes.clear();
+    mAudioMixes.add(myAudioMix);
+
+    // As the policy mixes registration may fail at some case,
+    // caller need to check the returned status.
+    status_t ret = mManager->registerPolicyMixes(mAudioMixes);
+    return ret;
+}
+
+void AudioPolicyManagerTestDynamicPolicy::clearPolicyMix() {
+    if (mManager != nullptr) {
+        mManager->unregisterPolicyMixes(mAudioMixes);
+    }
+    mAudioMixes.clear();
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, InitSuccess) {
+    // SetUp must finish with no assertions
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, Dump) {
+    dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, RegisterPolicyMixes) {
+    status_t ret;
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+
+    // Only capture of playback is allowed in LOOP_BACK &RENDER mode
+    ret = addPolicyMix(MIX_TYPE_RECORDERS, MIX_ROUTE_FLAG_LOOP_BACK_AND_RENDER,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // Fail due to the device is already connected.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // The first time to register policy mixes with valid parameter should succeed.
+    clearPolicyMix();
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig,
+            std::vector<PolicyMixTuple>());
+    ASSERT_EQ(NO_ERROR, ret);
+    // Registering the same policy mixes should fail.
+    ret = mManager->registerPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // Registration should fail due to device not found.
+    // Note that earpiece is not present in the test configuration file.
+    // This will need to be updated if earpiece is added in the test configuration file.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+            AUDIO_DEVICE_OUT_EARPIECE, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // Registration should fail due to output not found.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    // The first time to register valid policy mixes should succeed.
+    clearPolicyMix();
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+            AUDIO_DEVICE_OUT_SPEAKER, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(NO_ERROR, ret);
+    // Registering the same policy mixes should fail.
+    ret = mManager->registerPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+TEST_F(AudioPolicyManagerTestDynamicPolicy, UnregisterPolicyMixes) {
+    status_t ret;
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig,
+            std::vector<PolicyMixTuple>());
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // After successfully registering policy mixes, it should be able to unregister.
+    ret = mManager->unregisterPolicyMixes(mAudioMixes);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    // After unregistering policy mixes successfully, it should fail unregistering
+    // the same policy mixes as they are not registered.
+    ret = mManager->unregisterPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+class AudioPolicyManagerTestDPNoRemoteSubmixModule : public AudioPolicyManagerTestDynamicPolicy {
+protected:
+    std::string getConfigFile() override { return sPrimaryOnlyConfig; }
+
+    static const std::string sPrimaryOnlyConfig;
+};
+
+const std::string AudioPolicyManagerTestDPNoRemoteSubmixModule::sPrimaryOnlyConfig =
+        sExecutableDir + "test_audio_policy_primary_only_configuration.xml";
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, Dump) {
+    dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTestDPNoRemoteSubmixModule, RegistrationFailure) {
+    // Registration/Unregistration should fail due to module for remote submix not found.
+    status_t ret;
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "", audioConfig, std::vector<PolicyMixTuple>());
+    ASSERT_EQ(INVALID_OPERATION, ret);
+
+    ret = mManager->unregisterPolicyMixes(mAudioMixes);
+    ASSERT_EQ(INVALID_OPERATION, ret);
+}
+
+class AudioPolicyManagerTestDPPlaybackReRouting : public AudioPolicyManagerTestDynamicPolicy,
+        public testing::WithParamInterface<audio_attributes_t> {
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    std::unique_ptr<RecordingActivityTracker> mTracker;
+
+    std::vector<PolicyMixTuple> mUsageRules = {
+            {AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT, RULE_MATCH_ATTRIBUTE_USAGE},
+            {AUDIO_USAGE_ALARM, AUDIO_SOURCE_DEFAULT, RULE_MATCH_ATTRIBUTE_USAGE}
+    };
+
+    struct audio_port mInjectionPort;
+    audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
+};
+
+void AudioPolicyManagerTestDPPlaybackReRouting::SetUp() {
+    AudioPolicyManagerTestDynamicPolicy::SetUp();
+
+    mTracker.reset(new RecordingActivityTracker());
+
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+    audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, mUsageRules);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    struct audio_port extractionPort;
+    findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+            mMixAddress, extractionPort);
+
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
+    audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, 0, ""};
+    std::string tags = "addr=" + mMixAddress;
+    strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+    getInputForAttr(attr, mTracker->getRiid(), &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
+            AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE, &mPortId);
+    ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
+    ASSERT_EQ(extractionPort.id, selectedDeviceId);
+
+    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+            mMixAddress, mInjectionPort);
+}
+
+void AudioPolicyManagerTestDPPlaybackReRouting::TearDown() {
+    mManager->stopInput(mPortId);
+    AudioPolicyManagerTestDynamicPolicy::TearDown();
+}
+
+TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, InitSuccess) {
+    // SetUp must finish with no assertions
+}
+
+TEST_F(AudioPolicyManagerTestDPPlaybackReRouting, Dump) {
+    dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDPPlaybackReRouting, PlaybackReRouting) {
+    const audio_attributes_t attr = GetParam();
+    const audio_usage_t usage = attr.usage;
+
+    audio_port_handle_t playbackRoutedPortId = AUDIO_PORT_HANDLE_NONE;
+    getOutputForAttr(&playbackRoutedPortId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE,
+            nullptr /*output*/, nullptr /*portId*/, attr);
+    if (std::find_if(begin(mUsageRules), end(mUsageRules), [&usage](const auto &usageRule) {
+            return (std::get<0>(usageRule) == usage) &&
+            (std::get<2>(usageRule) == RULE_MATCH_ATTRIBUTE_USAGE);}) != end(mUsageRules) ||
+            (strncmp(attr.tags, "addr=", strlen("addr=")) == 0 &&
+                    strncmp(attr.tags + strlen("addr="), mMixAddress.c_str(),
+                    AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0)) {
+        EXPECT_EQ(mInjectionPort.id, playbackRoutedPortId);
+    } else {
+        EXPECT_NE(mInjectionPort.id, playbackRoutedPortId);
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(
+        PlaybackReroutingUsageMatch,
+        AudioPolicyManagerTestDPPlaybackReRouting,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""}
+                )
+        );
+
+INSTANTIATE_TEST_CASE_P(
+        PlaybackReroutingAddressPriorityMatch,
+        AudioPolicyManagerTestDPPlaybackReRouting,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_MEDIA,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ALARM,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VIRTUAL_SOURCE,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, "addr=remote_submix_media"}
+                )
+        );
+
+INSTANTIATE_TEST_CASE_P(
+        PlaybackReroutingUnHandledUsages,
+        AudioPolicyManagerTestDPPlaybackReRouting,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_VOICE_COMMUNICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_NOTIFICATION_EVENT,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC,
+                                     AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_GAME,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_MUSIC, AUDIO_USAGE_ASSISTANT,
+                                     AUDIO_SOURCE_DEFAULT, 0, ""}
+                )
+        );
+
+class AudioPolicyManagerTestDPMixRecordInjection : public AudioPolicyManagerTestDynamicPolicy,
+        public testing::WithParamInterface<audio_attributes_t> {
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    std::unique_ptr<RecordingActivityTracker> mTracker;
+
+    std::vector<PolicyMixTuple> mSourceRules = {
+        {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_CAMCORDER, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET},
+        {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_MIC, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET},
+        {AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_VOICE_COMMUNICATION, RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET}
+    };
+
+    struct audio_port mExtractionPort;
+    audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
+};
+
+void AudioPolicyManagerTestDPMixRecordInjection::SetUp() {
+    AudioPolicyManagerTestDynamicPolicy::SetUp();
+
+    mTracker.reset(new RecordingActivityTracker());
+
+    audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+    audioConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+    audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+    audioConfig.sample_rate = 48000;
+    status_t ret = addPolicyMix(MIX_TYPE_RECORDERS, MIX_ROUTE_FLAG_LOOP_BACK,
+            AUDIO_DEVICE_IN_REMOTE_SUBMIX, mMixAddress, audioConfig, mSourceRules);
+    ASSERT_EQ(NO_ERROR, ret);
+
+    struct audio_port injectionPort;
+    findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+            mMixAddress, injectionPort);
+
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_usage_t usage = AUDIO_USAGE_VIRTUAL_SOURCE;
+    audio_attributes_t attr = {AUDIO_CONTENT_TYPE_UNKNOWN, usage, AUDIO_SOURCE_DEFAULT, 0, ""};
+    std::string tags = std::string("addr=") + mMixAddress;
+    strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+    getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+            48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE, nullptr /*output*/, &mPortId, attr);
+    ASSERT_EQ(NO_ERROR, mManager->startOutput(mPortId));
+    ASSERT_EQ(injectionPort.id, getDeviceIdFromPatch(mClient->getLastAddedPatch()));
+
+    findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+            mMixAddress, mExtractionPort);
+}
+
+void AudioPolicyManagerTestDPMixRecordInjection::TearDown() {
+    mManager->stopOutput(mPortId);
+    AudioPolicyManagerTestDynamicPolicy::TearDown();
+}
+
+TEST_F(AudioPolicyManagerTestDPMixRecordInjection, InitSuccess) {
+    // SetUp mush finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDPMixRecordInjection, Dump) {
+    dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDPMixRecordInjection, RecordingInjection) {
+    const audio_attributes_t attr = GetParam();
+    const audio_source_t source = attr.source;
+
+    audio_port_handle_t captureRoutedPortId = AUDIO_PORT_HANDLE_NONE;
+    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+    getInputForAttr(attr, mTracker->getRiid(), &captureRoutedPortId, AUDIO_FORMAT_PCM_16_BIT,
+            AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE, &portId);
+    if (std::find_if(begin(mSourceRules), end(mSourceRules), [&source](const auto &sourceRule) {
+            return (std::get<1>(sourceRule) == source) &&
+            (std::get<2>(sourceRule) == RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET);})
+            != end(mSourceRules)) {
+        EXPECT_EQ(mExtractionPort.id, captureRoutedPortId);
+    } else {
+        EXPECT_NE(mExtractionPort.id, captureRoutedPortId);
+    }
+}
+
+// No address priority rule for remote recording, address is a "don't care"
+INSTANTIATE_TEST_CASE_P(
+        RecordInjectionSourceMatch,
+        AudioPolicyManagerTestDPMixRecordInjection,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_CAMCORDER, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_CAMCORDER, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_MIC, 0, "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_MIC, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_COMMUNICATION, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_COMMUNICATION, 0,
+                                     "addr=remote_submix_media"}
+                )
+        );
+
+// No address priority rule for remote recording
+INSTANTIATE_TEST_CASE_P(
+        RecordInjectionSourceNotMatch,
+        AudioPolicyManagerTestDPMixRecordInjection,
+        testing::Values(
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_RECOGNITION, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_HOTWORD, 0, ""},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_VOICE_RECOGNITION, 0,
+                                     "addr=remote_submix_media"},
+                (audio_attributes_t){AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN,
+                                     AUDIO_SOURCE_HOTWORD, 0, "addr=remote_submix_media"}
+                )
+        );
+
+using DeviceConnectionTestParams =
+        std::tuple<audio_devices_t /*type*/, std::string /*name*/, std::string /*address*/>;
+
+class AudioPolicyManagerTestDeviceConnection : public AudioPolicyManagerTestWithConfigurationFile,
+        public testing::WithParamInterface<DeviceConnectionTestParams> {
+};
+
+TEST_F(AudioPolicyManagerTestDeviceConnection, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTestDeviceConnection, Dump) {
+    dumpToLog();
+}
+
+TEST_P(AudioPolicyManagerTestDeviceConnection, SetDeviceConnectionState) {
+    const audio_devices_t type = std::get<0>(GetParam());
+    const std::string name = std::get<1>(GetParam());
+    const std::string address = std::get<2>(GetParam());
+
+    if (type == AUDIO_DEVICE_OUT_HDMI) {
+        // Set device connection state failed due to no device descriptor found
+        // For HDMI case, it is easier to simulate device descriptor not found error
+        // by using a undeclared encoded format.
+        ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+                type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+                address.c_str(), name.c_str(), AUDIO_FORMAT_MAT_2_1));
+    }
+    // Connect with valid parameters should succeed
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Try to connect with the same device again should fail
+    ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Disconnect the connected device should succeed
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Disconnect device that is not connected should fail
+    ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+    // Try to set device connection state  with a invalid connection state should fail
+    ASSERT_EQ(BAD_VALUE, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_CNT,
+            "", "", AUDIO_FORMAT_DEFAULT));
+}
+
+TEST_P(AudioPolicyManagerTestDeviceConnection, ExplicitlyRoutingAfterConnection) {
+    const audio_devices_t type = std::get<0>(GetParam());
+    const std::string name = std::get<1>(GetParam());
+    const std::string address = std::get<2>(GetParam());
+
+    // Connect device to do explicitly routing test
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+
+    audio_port devicePort;
+    const audio_port_role_t role = audio_is_output_device(type)
+            ? AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
+    findDevicePort(role, type, address, devicePort);
+
+    audio_port_handle_t routedPortId = devicePort.id;
+    // Try start input or output according to the device type
+    if (audio_is_output_devices(type)) {
+        getOutputForAttr(&routedPortId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+                48000 /*sampleRate*/, AUDIO_OUTPUT_FLAG_NONE);
+    } else if (audio_is_input_device(type)) {
+        RecordingActivityTracker tracker;
+        getInputForAttr({}, tracker.getRiid(), &routedPortId, AUDIO_FORMAT_PCM_16_BIT,
+                AUDIO_CHANNEL_IN_STEREO, 48000 /*sampleRate*/, AUDIO_INPUT_FLAG_NONE);
+    }
+    ASSERT_EQ(devicePort.id, routedPortId);
+
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            type, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+            address.c_str(), name.c_str(), AUDIO_FORMAT_DEFAULT));
+}
+
+INSTANTIATE_TEST_CASE_P(
+        DeviceConnectionState,
+        AudioPolicyManagerTestDeviceConnection,
+        testing::Values(
+                DeviceConnectionTestParams({AUDIO_DEVICE_IN_HDMI, "test_in_hdmi",
+                                            "audio_policy_test_in_hdmi"}),
+                DeviceConnectionTestParams({AUDIO_DEVICE_OUT_HDMI, "test_out_hdmi",
+                                            "audio_policy_test_out_hdmi"}),
+                DeviceConnectionTestParams({AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "bt_hfp_in",
+                                            "hfp_client_in"}),
+                DeviceConnectionTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "bt_hfp_out",
+                                            "hfp_client_out"})
+                )
+        );
+
+class AudioPolicyManagerTVTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+    std::string getConfigFile() override { return sTvConfig; }
+    void testHDMIPortSelection(audio_output_flags_t flags, const char* expectedMixPortName);
+
+    static const std::string sTvConfig;
+};
+
+const std::string AudioPolicyManagerTVTest::sTvConfig =
+        AudioPolicyManagerTVTest::sExecutableDir + "test_tv_apm_configuration.xml";
+
+// SwAudioOutputDescriptor doesn't populate flags so check against the port name.
+void AudioPolicyManagerTVTest::testHDMIPortSelection(
+        audio_output_flags_t flags, const char* expectedMixPortName) {
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+            "" /*address*/, "" /*name*/, AUDIO_FORMAT_DEFAULT));
+    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+    audio_io_handle_t output;
+    audio_port_handle_t portId;
+    getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000,
+            flags, &output, &portId);
+    sp<SwAudioOutputDescriptor> outDesc = mManager->getOutputs().valueFor(output);
+    ASSERT_NE(nullptr, outDesc.get());
+    audio_port port = {};
+    outDesc->toAudioPort(&port);
+    mManager->releaseOutput(portId);
+    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+            AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+            "" /*address*/, "" /*name*/, AUDIO_FORMAT_DEFAULT));
+    ASSERT_EQ(AUDIO_PORT_TYPE_MIX, port.type);
+    ASSERT_EQ(AUDIO_PORT_ROLE_SOURCE, port.role);
+    ASSERT_STREQ(expectedMixPortName, port.name);
+}
+
+TEST_F(AudioPolicyManagerTVTest, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTVTest, Dump) {
+    dumpToLog();
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchNoFlags) {
+    testHDMIPortSelection(AUDIO_OUTPUT_FLAG_NONE, "primary output");
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchOutputDirectNoHwAvSync) {
+    // b/140447125: The selected port must not have HW AV Sync flag (see the config file).
+    testHDMIPortSelection(AUDIO_OUTPUT_FLAG_DIRECT, "direct");
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchOutputDirectHwAvSync) {
+    testHDMIPortSelection(static_cast<audio_output_flags_t>(
+                    AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
+            "tunnel");
+}
+
+TEST_F(AudioPolicyManagerTVTest, MatchOutputDirectMMapNoIrq) {
+    testHDMIPortSelection(static_cast<audio_output_flags_t>(
+                    AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+            "low latency");
+}
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
new file mode 100644
index 0000000..d9476d9
--- /dev/null
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -0,0 +1,8 @@
+filegroup {
+    name: "audiopolicytest_configuration_files",
+    srcs: [
+        "test_audio_policy_configuration.xml",
+        "test_audio_policy_primary_only_configuration.xml",
+        "test_tv_apm_configuration.xml",
+    ],
+}
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
new file mode 100644
index 0000000..87f0ab9
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <globalConfiguration speaker_drc_enabled="true"/>
+
+    <modules>
+        <!-- Primary module -->
+        <module name="primary" halVersion="2.0">
+            <attachedDevices>
+                <item>Speaker</item>
+                <item>Built-In Mic</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="primary input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000"
+                             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+                <mixPort name="mixport_bt_hfp_output" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="mixport_bt_hfp_input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="8000,11025,16000,44100,48000"
+                             channelMasks="AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_MONO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+                </devicePort>
+                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+                </devicePort>
+                <devicePort tagName="Hdmi" type="AUDIO_DEVICE_OUT_HDMI" role="sink">
+                </devicePort>
+                <devicePort tagName="Hdmi-In Mic" type="AUDIO_DEVICE_IN_HDMI" role="source">
+                </devicePort>
+                <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"
+                            role="sink" address="hfp_client_out">
+                </devicePort>
+                <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"
+                            role="source" address="hfp_client_in">
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="Speaker"
+                       sources="primary output"/>
+                <route type="mix" sink="primary input"
+                       sources="Built-In Mic,Hdmi-In Mic"/>
+                <route type="mix" sink="Hdmi"
+                       sources="primary output"/>
+                <route type="mix" sink="BT SCO"
+                       sources="mixport_bt_hfp_output"/>
+                <route type="mix" sink="mixport_bt_hfp_input"
+                       sources="BT SCO Headset Mic"/>
+            </routes>
+        </module>
+
+        <!-- Remote Submix module -->
+        <module name="r_submix" halVersion="2.0">
+            <attachedDevices>
+                <item>Remote Submix In</item>
+            </attachedDevices>
+            <mixPorts>
+                <mixPort name="r_submix output" role="source">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="r_submix input" role="sink">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+           </mixPorts>
+           <devicePorts>
+               <devicePort tagName="Remote Submix Out" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"  role="sink">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+               </devicePort>
+               <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX"  role="source">
+                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="Remote Submix Out"
+                       sources="r_submix output"/>
+                <route type="mix" sink="r_submix input"
+                       sources="Remote Submix In"/>
+            </routes>
+        </module>
+    </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml
new file mode 100644
index 0000000..edc0adb
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_audio_policy_primary_only_configuration.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <globalConfiguration speaker_drc_enabled="true"/>
+
+    <modules>
+        <!-- Primary module -->
+        <module name="primary" halVersion="2.0">
+            <attachedDevices>
+                <item>Speaker</item>
+                <item>Built-In Mic</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="primary input" role="sink">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000"
+                             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+                </mixPort>
+            </mixPorts>
+            <devicePorts>
+                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+                </devicePort>
+                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+                </devicePort>
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="Speaker"
+                       sources="primary output"/>
+                <route type="mix" sink="primary input"
+                       sources="Built-In Mic"/>
+            </routes>
+        </module>
+    </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/resources/test_tv_apm_configuration.xml b/services/audiopolicy/tests/resources/test_tv_apm_configuration.xml
new file mode 100644
index 0000000..f1638f3
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_tv_apm_configuration.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <globalConfiguration speaker_drc_enabled="false"/>
+    <modules>
+        <module name="primary" halVersion="2.0">
+            <attachedDevices>
+                <item>Speaker</item>
+            </attachedDevices>
+            <defaultOutputDevice>Speaker</defaultOutputDevice>
+            <mixPorts>
+                <!-- Profiles on the HDMI port are explicit for simplicity. In reality they are dynamic -->
+                <!-- Note: ports are intentionally arranged from more specific to less
+                     specific in order to test b/140447125 for HW AV Sync, and similar "explicit matches" -->
+                <mixPort name="tunnel" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="low latency" role="source"
+                         flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="direct" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
+                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+                             samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+                </mixPort>
+           </mixPorts>
+           <devicePorts>
+                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink" />
+                <devicePort tagName="Out Aux Digital" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink" />
+            </devicePorts>
+            <routes>
+                <route type="mix" sink="Speaker" sources="primary output"/>
+                <route type="mix" sink="Out Aux Digital" sources="primary output,tunnel,direct,low latency"/>
+            </routes>
+        </module>
+    </modules>
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/systemaudio_tests.cpp b/services/audiopolicy/tests/systemaudio_tests.cpp
deleted file mode 100644
index abaae52..0000000
--- a/services/audiopolicy/tests/systemaudio_tests.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gtest/gtest.h>
-
-#define LOG_TAG "SysAudio_Test"
-#include <log/log.h>
-#include <media/PatchBuilder.h>
-#include <system/audio.h>
-
-using namespace android;
-
-TEST(SystemAudioTest, PatchInvalid) {
-    audio_patch patch{};
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-    patch.num_sources = AUDIO_PATCH_PORTS_MAX + 1;
-    patch.num_sinks = 1;
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-    patch.num_sources = 1;
-    patch.num_sinks = AUDIO_PATCH_PORTS_MAX + 1;
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-    patch.num_sources = 0;
-    patch.num_sinks = 1;
-    ASSERT_FALSE(audio_patch_is_valid(&patch));
-}
-
-TEST(SystemAudioTest, PatchValid) {
-    const audio_port_config src = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
-    // It's OK not to have sinks.
-    ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).patch()));
-    const audio_port_config sink = {
-        .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_TRUE(audio_patch_is_valid((PatchBuilder{}).addSource(src).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patch_is_valid(
-                    (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patch_is_valid(
-                    (PatchBuilder{}).addSource(src).addSink(sink).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patch_is_valid(
-                    (PatchBuilder{}).addSource(src).addSource(src).
-                    addSink(sink).addSink(sink).patch()));
-}
-
-TEST(SystemAudioTest, PatchHwAvSync) {
-    audio_port_config device_src_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-    device_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-    device_src_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_src_cfg));
-
-    audio_port_config device_sink_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-    device_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-    device_sink_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&device_sink_cfg));
-
-    audio_port_config mix_sink_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_MIX };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-    mix_sink_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-    mix_sink_cfg.flags.input = AUDIO_INPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_sink_cfg));
-
-    audio_port_config mix_src_cfg = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_MIX };
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-    mix_src_cfg.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    ASSERT_FALSE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-    mix_src_cfg.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
-    ASSERT_TRUE(audio_port_config_has_hw_av_sync(&mix_src_cfg));
-}
-
-TEST(SystemAudioTest, PatchEqual) {
-    const audio_patch patch1{}, patch2{};
-    // Invalid patches are not equal.
-    ASSERT_FALSE(audio_patches_are_equal(&patch1, &patch2));
-    const audio_port_config src = {
-        .id = 1, .role = AUDIO_PORT_ROLE_SOURCE, .type = AUDIO_PORT_TYPE_DEVICE };
-    const audio_port_config sink = {
-        .id = 2, .role = AUDIO_PORT_ROLE_SINK, .type = AUDIO_PORT_TYPE_DEVICE };
-    ASSERT_FALSE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch()));
-    ASSERT_TRUE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch()));
-    ASSERT_FALSE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
-                    (PatchBuilder{}).addSource(src).addSource(src).addSink(sink).patch()));
-    audio_port_config sink_hw_av_sync = sink;
-    sink_hw_av_sync.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
-    sink_hw_av_sync.flags.output = AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
-    ASSERT_FALSE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
-    ASSERT_TRUE(audio_patches_are_equal(
-                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch(),
-                    (PatchBuilder{}).addSource(src).addSink(sink_hw_av_sync).patch()));
-}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 06c6996..b704573 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -117,7 +117,12 @@
 
 // ----------------------------------------------------------------------------
 
+static const String16 sDumpPermission("android.permission.DUMP");
 static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");
+static const String16 sCameraPermission("android.permission.CAMERA");
+static const String16 sSystemCameraPermission("android.permission.SYSTEM_CAMERA");
+static const String16
+        sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
 
 // Matches with PERCEPTIBLE_APP_ADJ in ProcessList.java
 static constexpr int32_t kVendorClientScore = 200;
@@ -130,7 +135,9 @@
 CameraService::CameraService() :
         mEventLog(DEFAULT_EVENT_LOG_LENGTH),
         mNumberOfCameras(0),
-        mSoundRef(0), mInitialized(false) {
+        mNumberOfCamerasWithoutSystemCamera(0),
+        mSoundRef(0), mInitialized(false),
+        mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE) {
     ALOGI("CameraService started (pid=%d)", getpid());
     mServiceLockWrapper = std::make_shared<WaitableMutexWrapper>(&mServiceLock);
 }
@@ -157,6 +164,7 @@
     mUidPolicy->registerSelf();
     mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
     mSensorPrivacyPolicy->registerSelf();
+    mAppOps.setCameraAudioRestriction(mAudioRestriction);
     sp<HidlCameraService> hcs = HidlCameraService::getInstance(this);
     if (hcs->registerAsService() != android::OK) {
         ALOGE("%s: Failed to register default android.frameworks.cameraservice.service@1.0",
@@ -242,7 +250,7 @@
     Mutex::Autolock lock(mStatusListenerLock);
 
     for (auto& i : mListenerList) {
-        i.second->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
+        i->getListener()->onTorchStatusChanged(mapToInterface(status), String16{cameraId});
     }
 }
 
@@ -256,32 +264,62 @@
     enumerateProviders();
 }
 
-bool CameraService::isPublicallyHiddenSecureCamera(const String8& cameraId) {
+void CameraService::filterAPI1SystemCameraLocked(
+        const std::vector<std::string> &normalDeviceIds) {
+    mNormalDeviceIdsWithoutSystemCamera.clear();
+    for (auto &deviceId : normalDeviceIds) {
+        SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+        if (getSystemCameraKind(String8(deviceId.c_str()), &deviceKind) != OK) {
+            ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, deviceId.c_str());
+            continue;
+        }
+        if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
+            // All system camera ids will necessarily come after public camera
+            // device ids as per the HAL interface contract.
+            break;
+        }
+        mNormalDeviceIdsWithoutSystemCamera.push_back(deviceId);
+    }
+    ALOGV("%s: number of API1 compatible public cameras is %zu", __FUNCTION__,
+              mNormalDeviceIdsWithoutSystemCamera.size());
+}
+
+status_t CameraService::getSystemCameraKind(const String8& cameraId, SystemCameraKind *kind) const {
     auto state = getCameraState(cameraId);
     if (state != nullptr) {
-        return state->isPublicallyHiddenSecureCamera();
+        *kind = state->getSystemCameraKind();
+        return OK;
     }
     // Hidden physical camera ids won't have CameraState
-    return mCameraProviderManager->isPublicallyHiddenSecureCamera(cameraId.c_str());
+    return mCameraProviderManager->getSystemCameraKind(cameraId.c_str(), kind);
 }
 
 void CameraService::updateCameraNumAndIds() {
     Mutex::Autolock l(mServiceLock);
-    mNumberOfCameras = mCameraProviderManager->getCameraCount();
+    std::pair<int, int> systemAndNonSystemCameras = mCameraProviderManager->getCameraCount();
+    // Excludes hidden secure cameras
+    mNumberOfCameras =
+            systemAndNonSystemCameras.first + systemAndNonSystemCameras.second;
+    mNumberOfCamerasWithoutSystemCamera = systemAndNonSystemCameras.second;
     mNormalDeviceIds =
             mCameraProviderManager->getAPI1CompatibleCameraDeviceIds();
+    filterAPI1SystemCameraLocked(mNormalDeviceIds);
 }
 
 void CameraService::addStates(const String8 id) {
     std::string cameraId(id.c_str());
     hardware::camera::common::V1_0::CameraResourceCost cost;
     status_t res = mCameraProviderManager->getResourceCost(cameraId, &cost);
+    SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
     if (res != OK) {
         ALOGE("Failed to query device resource cost: %s (%d)", strerror(-res), res);
         return;
     }
-    bool isPublicallyHiddenSecureCamera =
-            mCameraProviderManager->isPublicallyHiddenSecureCamera(id.string());
+    res = mCameraProviderManager->getSystemCameraKind(cameraId, &deviceKind);
+    if (res != OK) {
+        ALOGE("Failed to query device kind: %s (%d)", strerror(-res), res);
+        return;
+    }
     std::set<String8> conflicting;
     for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
         conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
@@ -290,8 +328,7 @@
     {
         Mutex::Autolock lock(mCameraStatesLock);
         mCameraStates.emplace(id, std::make_shared<CameraState>(id, cost.resourceCost,
-                                                                conflicting,
-                                                                isPublicallyHiddenSecureCamera));
+                                                                conflicting, deviceKind));
     }
 
     if (mFlashlight->hasFlashUnit(id)) {
@@ -454,15 +491,31 @@
     broadcastTorchModeStatus(cameraId, newStatus);
 }
 
+static bool hasPermissionsForSystemCamera(int callingPid, int callingUid) {
+    return checkPermission(sSystemCameraPermission, callingPid, callingUid) &&
+            checkPermission(sCameraPermission, callingPid, callingUid);
+}
+
 Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
     ATRACE_CALL();
     Mutex::Autolock l(mServiceLock);
+    bool hasSystemCameraPermissions =
+            hasPermissionsForSystemCamera(CameraThreadState::getCallingPid(),
+                    CameraThreadState::getCallingUid());
     switch (type) {
         case CAMERA_TYPE_BACKWARD_COMPATIBLE:
-            *numCameras = static_cast<int>(mNormalDeviceIds.size());
+            if (hasSystemCameraPermissions) {
+                *numCameras = static_cast<int>(mNormalDeviceIds.size());
+            } else {
+                *numCameras = static_cast<int>(mNormalDeviceIdsWithoutSystemCamera.size());
+            }
             break;
         case CAMERA_TYPE_ALL:
-            *numCameras = mNumberOfCameras;
+            if (hasSystemCameraPermissions) {
+                *numCameras = mNumberOfCameras;
+            } else {
+                *numCameras = mNumberOfCamerasWithoutSystemCamera;
+            }
             break;
         default:
             ALOGW("%s: Unknown camera type %d",
@@ -477,20 +530,31 @@
         CameraInfo* cameraInfo) {
     ATRACE_CALL();
     Mutex::Autolock l(mServiceLock);
+    std::string cameraIdStr = cameraIdIntToStrLocked(cameraId);
+    if (shouldRejectSystemCameraConnection(String8(cameraIdStr.c_str()))) {
+        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
+                "characteristics for system only device %s: ", cameraIdStr.c_str());
+    }
 
     if (!mInitialized) {
         return STATUS_ERROR(ERROR_DISCONNECTED,
                 "Camera subsystem is not available");
     }
-
-    if (cameraId < 0 || cameraId >= mNumberOfCameras) {
+    bool hasSystemCameraPermissions =
+            hasPermissionsForSystemCamera(CameraThreadState::getCallingPid(),
+                    CameraThreadState::getCallingUid());
+    int cameraIdBound = mNumberOfCamerasWithoutSystemCamera;
+    if (hasSystemCameraPermissions) {
+        cameraIdBound = mNumberOfCameras;
+    }
+    if (cameraId < 0 || cameraId >= cameraIdBound) {
         return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT,
                 "CameraId is not valid");
     }
 
     Status ret = Status::ok();
     status_t err = mCameraProviderManager->getCameraInfo(
-            cameraIdIntToStrLocked(cameraId), cameraInfo);
+            cameraIdStr.c_str(), cameraInfo);
     if (err != OK) {
         ret = STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                 "Error retrieving camera info from device %d: %s (%d)", cameraId,
@@ -501,13 +565,20 @@
 }
 
 std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt) {
-    if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(mNormalDeviceIds.size())) {
+    const std::vector<std::string> *deviceIds = &mNormalDeviceIdsWithoutSystemCamera;
+    auto callingPid = CameraThreadState::getCallingPid();
+    auto callingUid = CameraThreadState::getCallingUid();
+    if (checkPermission(sSystemCameraPermission, callingPid, callingUid) ||
+            getpid() == callingPid) {
+        deviceIds = &mNormalDeviceIds;
+    }
+    if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(deviceIds->size())) {
         ALOGE("%s: input id %d invalid: valid range  (0, %zu)",
-                __FUNCTION__, cameraIdInt, mNormalDeviceIds.size());
+                __FUNCTION__, cameraIdInt, deviceIds->size());
         return std::string{};
     }
 
-    return mNormalDeviceIds[cameraIdInt];
+    return (*deviceIds)[cameraIdInt];
 }
 
 String8 CameraService::cameraIdIntToStr(int cameraIdInt) {
@@ -529,16 +600,13 @@
                 "Camera subsystem is not available");;
     }
 
-    if (shouldRejectHiddenCameraConnection(String8(cameraId))) {
-        ALOGW("Attempting to retrieve characteristics for system-only camera id %s, rejected",
-              String8(cameraId).string());
-        return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
-                                "No camera device with ID \"%s\" currently available",
-                                String8(cameraId).string());
-
+    if (shouldRejectSystemCameraConnection(String8(cameraId))) {
+        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera"
+                "characteristics for system only device %s: ", String8(cameraId).string());
     }
 
     Status ret{};
+
     status_t res = mCameraProviderManager->getCameraCharacteristics(
             String8(cameraId).string(), cameraInfo);
     if (res != OK) {
@@ -546,13 +614,21 @@
                 "characteristics for device %s: %s (%d)", String8(cameraId).string(),
                 strerror(-res), res);
     }
-
+    SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+    if (getSystemCameraKind(String8(cameraId), &deviceKind) != OK) {
+        ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, String8(cameraId).string());
+        return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Unable to retrieve camera kind "
+                "for device %s", String8(cameraId).string());
+    }
     int callingPid = CameraThreadState::getCallingPid();
     int callingUid = CameraThreadState::getCallingUid();
     std::vector<int32_t> tagsRemoved;
-    // If it's not calling from cameraserver, check the permission.
+    // If it's not calling from cameraserver, check the permission only if
+    // android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
+    // it would've already been checked in shouldRejectSystemCameraConnection.
     if ((callingPid != getpid()) &&
-            !checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) {
+            (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
+            !checkPermission(sCameraPermission, callingPid, callingUid)) {
         res = cameraInfo->removePermissionEntries(
                 mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
                 &tagsRemoved);
@@ -656,9 +732,10 @@
 }
 
 Status CameraService::makeClient(const sp<CameraService>& cameraService,
-        const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
-        int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
-        int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+        const sp<IInterface>& cameraCb, const String16& packageName,
+        const std::unique_ptr<String16>& featureId, const String8& cameraId, int api1CameraId,
+        int facing, int clientPid, uid_t clientUid, int servicePid, int halVersion,
+        int deviceVersion, apiLevel effectiveApiLevel,
         /*out*/sp<BasicClient>* client) {
 
     if (halVersion < 0 || halVersion == deviceVersion) {
@@ -668,7 +745,7 @@
           case CAMERA_DEVICE_API_VERSION_1_0:
             if (effectiveApiLevel == API_1) {  // Camera1 API route
                 sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
-                *client = new CameraClient(cameraService, tmp, packageName,
+                *client = new CameraClient(cameraService, tmp, packageName, featureId,
                         api1CameraId, facing, clientPid, clientUid,
                         getpid());
             } else { // Camera2 API route
@@ -686,15 +763,15 @@
           case CAMERA_DEVICE_API_VERSION_3_5:
             if (effectiveApiLevel == API_1) { // Camera1 API route
                 sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
-                *client = new Camera2Client(cameraService, tmp, packageName,
+                *client = new Camera2Client(cameraService, tmp, packageName, featureId,
                         cameraId, api1CameraId,
                         facing, clientPid, clientUid,
                         servicePid);
             } else { // Camera2 API route
                 sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                         static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
-                *client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
-                        facing, clientPid, clientUid, servicePid);
+                *client = new CameraDeviceClient(cameraService, tmp, packageName, featureId,
+                        cameraId, facing, clientPid, clientUid, servicePid);
             }
             break;
           default:
@@ -711,7 +788,7 @@
             halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
             // Only support higher HAL version device opened as HAL1.0 device.
             sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
-            *client = new CameraClient(cameraService, tmp, packageName,
+            *client = new CameraClient(cameraService, tmp, packageName, featureId,
                     api1CameraId, facing, clientPid, clientUid,
                     servicePid);
         } else {
@@ -811,7 +888,7 @@
     if (!(ret = connectHelper<ICameraClient,Client>(
             sp<ICameraClient>{nullptr}, id, cameraId,
             static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
-            internalPackageName, uid, USE_CALLING_PID,
+            internalPackageName, std::unique_ptr<String16>(), uid, USE_CALLING_PID,
             API_1, /*shimUpdateOnly*/ true, /*out*/ tmp)
             ).isOk()) {
         ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
@@ -992,9 +1069,26 @@
                 clientName8.string(), clientUid, clientPid);
     }
 
-    // If it's not calling from cameraserver, check the permission.
+    if (shouldRejectSystemCameraConnection(cameraId)) {
+        ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
+                cameraId.c_str());
+        return STATUS_ERROR_FMT(ERROR_DISCONNECTED, "No camera device with ID \"%s\" is"
+                                "available", cameraId.string());
+    }
+    SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+    if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+        ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
+        return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT, "No camera device with ID \"%s\""
+                "found while trying to query device kind", cameraId.string());
+
+    }
+
+    // If it's not calling from cameraserver, check the permission if the
+    // device isn't a system only camera (shouldRejectSystemCameraConnection already checks for
+    // android.permission.SYSTEM_CAMERA for system only camera devices).
     if (callingPid != getpid() &&
-            !checkPermission(String16("android.permission.CAMERA"), clientPid, clientUid)) {
+                (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
+                !checkPermission(sCameraPermission, clientPid, clientUid)) {
         ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
         return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
                 "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" without camera permission",
@@ -1307,8 +1401,8 @@
     String8 id = cameraIdIntToStr(api1CameraId);
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
-            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
-            /*shimUpdateOnly*/ false, /*out*/client);
+            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, std::unique_ptr<String16>(),
+            clientUid, clientPid, API_1, /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
         logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
@@ -1334,8 +1428,8 @@
     Status ret = Status::ok();
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
-            clientPackageName, clientUid, USE_CALLING_PID, API_1, /*shimUpdateOnly*/ false,
-            /*out*/client);
+            clientPackageName, std::unique_ptr<String16>(), clientUid, USE_CALLING_PID, API_1,
+            /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
         logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
@@ -1347,22 +1441,69 @@
     return ret;
 }
 
-bool CameraService::shouldRejectHiddenCameraConnection(const String8 & cameraId) {
-    // If the thread serving this call is not a hwbinder thread and the caller
-    // isn't the cameraserver itself, and the camera id being requested is to be
-    // publically hidden, we should reject the connection.
-    if (!hardware::IPCThreadState::self()->isServingCall() &&
-            CameraThreadState::getCallingPid() != getpid() &&
-            isPublicallyHiddenSecureCamera(cameraId)) {
+bool CameraService::shouldSkipStatusUpdates(SystemCameraKind systemCameraKind,
+        bool isVendorListener, int clientPid, int clientUid) {
+    // If the client is not a vendor client, don't add listener if
+    //   a) the camera is a publicly hidden secure camera OR
+    //   b) the camera is a system only camera and the client doesn't
+    //      have android.permission.SYSTEM_CAMERA permissions.
+    if (!isVendorListener && (systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA ||
+            (systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
+            !hasPermissionsForSystemCamera(clientPid, clientUid)))) {
         return true;
     }
     return false;
 }
 
+bool CameraService::shouldRejectSystemCameraConnection(const String8& cameraId) const {
+    // Rules for rejection:
+    // 1) If cameraserver tries to access this camera device, accept the
+    //    connection.
+    // 2) The camera device is a publicly hidden secure camera device AND some
+    //    component is trying to access it on a non-hwbinder thread (generally a non HAL client),
+    //    reject it.
+    // 3) if the camera device is advertised by the camera HAL as SYSTEM_ONLY
+    //    and the serving thread is a non hwbinder thread, the client must have
+    //    android.permission.SYSTEM_CAMERA permissions to connect.
+
+    int cPid = CameraThreadState::getCallingPid();
+    int cUid = CameraThreadState::getCallingUid();
+    SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+    if (getSystemCameraKind(cameraId, &systemCameraKind) != OK) {
+        ALOGE("%s: Invalid camera id %s, ", __FUNCTION__, cameraId.c_str());
+        return true;
+    }
+
+    // (1) Cameraserver trying to connect, accept.
+    if (CameraThreadState::getCallingPid() == getpid()) {
+        return false;
+    }
+    // (2)
+    if (!hardware::IPCThreadState::self()->isServingCall() &&
+            systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA) {
+        ALOGW("Rejecting access to secure hidden camera %s", cameraId.c_str());
+        return true;
+    }
+    // (3) Here we only check for permissions if it is a system only camera device. This is since
+    //     getCameraCharacteristics() allows for calls to succeed (albeit after hiding some
+    //     characteristics) even if clients don't have android.permission.CAMERA. We do not want the
+    //     same behavior for system camera devices.
+    if (!hardware::IPCThreadState::self()->isServingCall() &&
+            systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
+            !hasPermissionsForSystemCamera(cPid, cUid)) {
+        ALOGW("Rejecting access to system only camera %s, inadequete permissions",
+                cameraId.c_str());
+        return true;
+    }
+
+    return false;
+}
+
 Status CameraService::connectDevice(
         const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
         const String16& cameraId,
         const String16& clientPackageName,
+        const std::unique_ptr<String16>& clientFeatureId,
         int clientUid,
         /*out*/
         sp<hardware::camera2::ICameraDeviceUser>* device) {
@@ -1372,6 +1513,7 @@
     String8 id = String8(cameraId);
     sp<CameraDeviceClient> client = nullptr;
     String16 clientPackageNameAdj = clientPackageName;
+
     if (hardware::IPCThreadState::self()->isServingCall()) {
         std::string vendorClient =
                 StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
@@ -1379,7 +1521,7 @@
     }
     ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
             /*api1CameraId*/-1,
-            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj,
+            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj, clientFeatureId,
             clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
@@ -1394,8 +1536,9 @@
 
 template<class CALLBACK, class CLIENT>
 Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
-        int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
-        int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
+        int api1CameraId, int halVersion, const String16& clientPackageName,
+        const std::unique_ptr<String16>& clientFeatureId, int clientUid, int clientPid,
+        apiLevel effectiveApiLevel, bool shimUpdateOnly,
         /*out*/sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
 
@@ -1408,14 +1551,6 @@
             (halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),
             static_cast<int>(effectiveApiLevel));
 
-    if (shouldRejectHiddenCameraConnection(cameraId)) {
-        ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
-              cameraId.c_str());
-        return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
-                                "No camera device with ID \"%s\" currently available",
-                                cameraId.string());
-
-    }
     sp<CLIENT> client = nullptr;
     {
         // Acquire mServiceLock and prevent other clients from connecting
@@ -1486,7 +1621,7 @@
         }
 
         sp<BasicClient> tmp = nullptr;
-        if(!(ret = makeClient(this, cameraCb, clientPackageName,
+        if(!(ret = makeClient(this, cameraCb, clientPackageName, clientFeatureId,
                 cameraId, api1CameraId, facing,
                 clientPid, clientUid, getpid(),
                 halVersion, deviceVersion, effectiveApiLevel,
@@ -1691,8 +1826,7 @@
     if (pid != selfPid) {
         // Ensure we're being called by system_server, or similar process with
         // permissions to notify the camera service about system events
-        if (!checkCallingPermission(
-                String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+        if (!checkCallingPermission(sCameraSendSystemEventsPermission)) {
             const int uid = CameraThreadState::getCallingUid();
             ALOGE("Permission Denial: cannot send updates to camera service about system"
                     " events from pid=%d, uid=%d", pid, uid);
@@ -1727,7 +1861,7 @@
     Mutex::Autolock lock(mStatusListenerLock);
 
     for (const auto& it : mListenerList) {
-        auto ret = it.second->getListener()->onCameraAccessPrioritiesChanged();
+        auto ret = it->getListener()->onCameraAccessPrioritiesChanged();
         if (!ret.isOk()) {
             ALOGE("%s: Failed to trigger permission callback: %d", __FUNCTION__,
                     ret.exceptionCode());
@@ -1743,8 +1877,7 @@
     if (pid != selfPid) {
         // Ensure we're being called by system_server, or similar process with
         // permissions to notify the camera service about system events
-        if (!checkCallingPermission(
-                String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
+        if (!checkCallingPermission(sCameraSendSystemEventsPermission)) {
             const int uid = CameraThreadState::getCallingUid();
             ALOGE("Permission Denial: cannot send updates to camera service about device"
                     " state changes from pid=%d, uid=%d", pid, uid);
@@ -1798,20 +1931,23 @@
         return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, "Null listener given to addListener");
     }
 
+    auto clientUid = CameraThreadState::getCallingUid();
+    auto clientPid = CameraThreadState::getCallingPid();
+
     Mutex::Autolock lock(mServiceLock);
 
     {
         Mutex::Autolock lock(mStatusListenerLock);
         for (const auto &it : mListenerList) {
-            if (IInterface::asBinder(it.second->getListener()) == IInterface::asBinder(listener)) {
+            if (IInterface::asBinder(it->getListener()) == IInterface::asBinder(listener)) {
                 ALOGW("%s: Tried to add listener %p which was already subscribed",
                       __FUNCTION__, listener.get());
                 return STATUS_ERROR(ERROR_ALREADY_EXISTS, "Listener already registered");
             }
         }
 
-        auto clientUid = CameraThreadState::getCallingUid();
-        sp<ServiceListener> serviceListener = new ServiceListener(this, listener, clientUid);
+        sp<ServiceListener> serviceListener =
+                new ServiceListener(this, listener, clientUid, clientPid, isVendorListener);
         auto ret = serviceListener->initialize();
         if (ret != NO_ERROR) {
             String8 msg = String8::format("Failed to initialize service listener: %s (%d)",
@@ -1819,7 +1955,10 @@
             ALOGE("%s: %s", __FUNCTION__, msg.string());
             return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
         }
-        mListenerList.emplace_back(isVendorListener, serviceListener);
+        // The listener still needs to be added to the list of listeners, regardless of what
+        // permissions the listener process has / whether it is a vendor listener. Since it might be
+        // eligible to listen to other camera ids.
+        mListenerList.emplace_back(serviceListener);
         mUidPolicy->registerMonitorUid(clientUid);
     }
 
@@ -1830,21 +1969,21 @@
             cameraStatuses->emplace_back(i.first, mapToInterface(i.second->getStatus()));
         }
     }
-
     // Remove the camera statuses that should be hidden from the client, we do
     // this after collecting the states in order to avoid holding
-    // mCameraStatesLock and mInterfaceLock (held in
-    // isPublicallyHiddenSecureCamera()) at the same time.
+    // mCameraStatesLock and mInterfaceLock (held in getSystemCameraKind()) at
+    // the same time.
     cameraStatuses->erase(std::remove_if(cameraStatuses->begin(), cameraStatuses->end(),
-                [this, &isVendorListener](const hardware::CameraStatus& s) {
-                    bool ret = !isVendorListener && isPublicallyHiddenSecureCamera(s.cameraId);
-                    if (ret) {
-                        ALOGV("Cannot add public listener for hidden system-only %s for pid %d",
-                                s.cameraId.c_str(), CameraThreadState::getCallingPid());
+                [this, &isVendorListener, &clientPid, &clientUid](const hardware::CameraStatus& s) {
+                    SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+                    if (getSystemCameraKind(s.cameraId, &deviceKind) != OK) {
+                        ALOGE("%s: Invalid camera id %s, skipping status update",
+                                __FUNCTION__, s.cameraId.c_str());
+                        return true;
                     }
-                    return ret;
-                }),
-                cameraStatuses->end());
+                    return shouldSkipStatusUpdates(deviceKind, isVendorListener, clientPid,
+                            clientUid);}), cameraStatuses->end());
+
 
     /*
      * Immediately signal current torch status to this listener only
@@ -1876,9 +2015,9 @@
     {
         Mutex::Autolock lock(mStatusListenerLock);
         for (auto it = mListenerList.begin(); it != mListenerList.end(); it++) {
-            if (IInterface::asBinder(it->second->getListener()) == IInterface::asBinder(listener)) {
-                mUidPolicy->unregisterMonitorUid(it->second->getListenerUid());
-                IInterface::asBinder(listener)->unlinkToDeath(it->second);
+            if (IInterface::asBinder((*it)->getListener()) == IInterface::asBinder(listener)) {
+                mUidPolicy->unregisterMonitorUid((*it)->getListenerUid());
+                IInterface::asBinder(listener)->unlinkToDeath(*it);
                 mListenerList.erase(it);
                 return Status::ok();
             }
@@ -1994,6 +2133,7 @@
             mActiveClientManager.remove(i);
         }
     }
+    updateAudioRestrictionLocked();
 }
 
 bool CameraService::evictClientIdByRemote(const wp<IBinder>& remote) {
@@ -2323,13 +2463,14 @@
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
         const String16& clientPackageName,
+        const std::unique_ptr<String16>& clientFeatureId,
         const String8& cameraIdStr,
         int api1CameraId, int cameraFacing,
         int clientPid, uid_t clientUid,
         int servicePid) :
         CameraService::BasicClient(cameraService,
                 IInterface::asBinder(cameraClient),
-                clientPackageName,
+                clientPackageName, clientFeatureId,
                 cameraIdStr, cameraFacing,
                 clientPid, clientUid,
                 servicePid),
@@ -2359,16 +2500,24 @@
 
 CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
         const sp<IBinder>& remoteCallback,
-        const String16& clientPackageName,
+        const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
         const String8& cameraIdStr, int cameraFacing,
         int clientPid, uid_t clientUid,
         int servicePid):
         mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing),
-        mClientPackageName(clientPackageName), mClientPid(clientPid), mClientUid(clientUid),
+        mClientPackageName(clientPackageName),
+        mClientPid(clientPid), mClientUid(clientUid),
         mServicePid(servicePid),
         mDisconnected(false),
+        mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE),
         mRemoteBinder(remoteCallback)
 {
+    if (clientFeatureId) {
+        mClientFeatureId = std::unique_ptr<String16>(new String16(*clientFeatureId));
+    } else {
+        mClientFeatureId = std::unique_ptr<String16>();
+    }
+
     if (sCameraService == nullptr) {
         sCameraService = cameraService;
     }
@@ -2470,6 +2619,35 @@
     return level == API_2;
 }
 
+status_t CameraService::BasicClient::setAudioRestriction(int32_t mode) {
+    {
+        Mutex::Autolock l(mAudioRestrictionLock);
+        mAudioRestriction = mode;
+    }
+    sCameraService->updateAudioRestriction();
+    return OK;
+}
+
+int32_t CameraService::BasicClient::getServiceAudioRestriction() const {
+    return sCameraService->updateAudioRestriction();
+}
+
+int32_t CameraService::BasicClient::getAudioRestriction() const {
+    Mutex::Autolock l(mAudioRestrictionLock);
+    return mAudioRestriction;
+}
+
+bool CameraService::BasicClient::isValidAudioRestriction(int32_t mode) {
+    switch (mode) {
+        case hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE:
+        case hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_VIBRATION:
+        case hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_VIBRATION_SOUND:
+            return true;
+        default:
+            return false;
+    }
+}
+
 status_t CameraService::BasicClient::startCameraOps() {
     ATRACE_CALL();
 
@@ -2483,8 +2661,9 @@
         int32_t res;
         mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
                 mClientPackageName, mOpsCallback);
-        res = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA,
-                mClientUid, mClientPackageName, /*startIfModeDefault*/ false);
+        res = mAppOpsManager->startOpNoThrow(AppOpsManager::OP_CAMERA, mClientUid,
+                mClientPackageName, /*startIfModeDefault*/ false, mClientFeatureId,
+                String16("start camera ") + String16(mCameraIdStr));
 
         if (res == AppOpsManager::MODE_ERRORED) {
             ALOGI("Camera %s: Access for \"%s\" has been revoked",
@@ -2526,7 +2705,7 @@
         // Notify app ops that the camera is available again
         if (mAppOpsManager != nullptr) {
             mAppOpsManager->finishOp(AppOpsManager::OP_CAMERA, mClientUid,
-                    mClientPackageName);
+                    mClientPackageName, mClientFeatureId);
             mOpsActive = false;
         }
         // This function is called when a client disconnects. This should
@@ -2689,7 +2868,7 @@
 }
 
 void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState,
-        int64_t /*procStateSeq*/) {
+        int64_t procStateSeq __unused, int32_t capability __unused) {
     bool procStateChange = false;
     {
         Mutex::Autolock _l(mUidLock);
@@ -2903,9 +3082,9 @@
 // ----------------------------------------------------------------------------
 
 CameraService::CameraState::CameraState(const String8& id, int cost,
-        const std::set<String8>& conflicting, bool isHidden) : mId(id),
+        const std::set<String8>& conflicting, SystemCameraKind systemCameraKind) : mId(id),
         mStatus(StatusInternal::NOT_PRESENT), mCost(cost), mConflicting(conflicting),
-        mIsPublicallyHiddenSecureCamera(isHidden) {}
+        mSystemCameraKind(systemCameraKind) {}
 
 CameraService::CameraState::~CameraState() {}
 
@@ -2934,8 +3113,8 @@
     return mId;
 }
 
-bool CameraService::CameraState::isPublicallyHiddenSecureCamera() const {
-    return mIsPublicallyHiddenSecureCamera;
+SystemCameraKind CameraService::CameraState::getSystemCameraKind() const {
+    return mSystemCameraKind;
 }
 
 // ----------------------------------------------------------------------------
@@ -3066,7 +3245,7 @@
 status_t CameraService::dump(int fd, const Vector<String16>& args) {
     ATRACE_CALL();
 
-    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+    if (checkCallingPermission(sDumpPermission) == false) {
         dprintf(fd, "Permission Denial: can't dump CameraService from pid=%d, uid=%d\n",
                 CameraThreadState::getCallingPid(),
                 CameraThreadState::getCallingUid());
@@ -3090,6 +3269,8 @@
     dprintf(fd, "\n== Service global info: ==\n\n");
     dprintf(fd, "Number of camera devices: %d\n", mNumberOfCameras);
     dprintf(fd, "Number of normal camera devices: %zu\n", mNormalDeviceIds.size());
+    dprintf(fd, "Number of public camera devices visible to API1: %zu\n",
+            mNormalDeviceIdsWithoutSystemCamera.size());
     for (size_t i = 0; i < mNormalDeviceIds.size(); i++) {
         dprintf(fd, "    Device %zu maps to \"%s\"\n", i, mNormalDeviceIds[i].c_str());
     }
@@ -3273,10 +3454,28 @@
                 cameraId.string());
         return;
     }
-    bool isHidden = isPublicallyHiddenSecureCamera(cameraId);
+
+    // Avoid calling getSystemCameraKind() with mStatusListenerLock held (b/141756275)
+    SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+    if (getSystemCameraKind(cameraId, &deviceKind) != OK) {
+        ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
+        return;
+    }
+    bool supportsHAL3 = false;
+    // supportsCameraApi also holds mInterfaceMutex, we can't call it in the
+    // HIDL onStatusChanged wrapper call (we'll hold mStatusListenerLock and
+    // mInterfaceMutex together, which can lead to deadlocks)
+    binder::Status sRet =
+            supportsCameraApi(String16(cameraId), hardware::ICameraService::API_VERSION_2,
+                    &supportsHAL3);
+    if (!sRet.isOk()) {
+        ALOGW("%s: Failed to determine if device supports HAL3 %s, supportsCameraApi call failed",
+                __FUNCTION__, cameraId.string());
+        return;
+    }
     // Update the status for this camera state, then send the onStatusChangedCallbacks to each
     // of the listeners with both the mStatusStatus and mStatusListenerLock held
-    state->updateStatus(status, cameraId, rejectSourceStates, [this,&isHidden]
+    state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3]
             (const String8& cameraId, StatusInternal status) {
 
             if (status != StatusInternal::ENUMERATING) {
@@ -3298,12 +3497,15 @@
             Mutex::Autolock lock(mStatusListenerLock);
 
             for (auto& listener : mListenerList) {
-                if (!listener.first &&  isHidden) {
-                    ALOGV("Skipping camera discovery callback for system-only camera %s",
-                          cameraId.c_str());
+                bool isVendorListener = listener->isVendorListener();
+                if (shouldSkipStatusUpdates(deviceKind, isVendorListener,
+                        listener->getListenerPid(), listener->getListenerUid()) ||
+                    (isVendorListener && !supportsHAL3)) {
+                    ALOGV("Skipping discovery callback for system-only camera/HAL1 device %s",
+                            cameraId.c_str());
                     continue;
                 }
-                listener.second->getListener()->onStatusChanged(mapToInterface(status),
+                listener->getListener()->onStatusChanged(mapToInterface(status),
                         String16(cameraId));
             }
         });
@@ -3503,4 +3705,25 @@
         "  help print this message\n");
 }
 
+int32_t CameraService::updateAudioRestriction() {
+    Mutex::Autolock lock(mServiceLock);
+    return updateAudioRestrictionLocked();
+}
+
+int32_t CameraService::updateAudioRestrictionLocked() {
+    int32_t mode = 0;
+    // iterate through all active client
+    for (const auto& i : mActiveClientManager.getAll()) {
+        const auto clientSp = i->getValue();
+        mode |= clientSp->getAudioRestriction();
+    }
+
+    bool modeChanged = (mAudioRestriction != mode);
+    mAudioRestriction = mode;
+    if (modeChanged) {
+        mAppOps.setCameraAudioRestriction(mode);
+    }
+    return mode;
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8bb78cd..1f40fc3 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -134,7 +134,8 @@
 
     virtual binder::Status     connectDevice(
             const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId,
-            const String16& clientPackageName, int32_t clientUid,
+            const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
+            int32_t clientUid,
             /*out*/
             sp<hardware::camera2::ICameraDeviceUser>* device);
 
@@ -258,10 +259,24 @@
 
         // Block the client form using the camera
         virtual void block();
+
+        // set audio restriction from client
+        // Will call into camera service and hold mServiceLock
+        virtual status_t setAudioRestriction(int32_t mode);
+
+        // Get current global audio restriction setting
+        // Will call into camera service and hold mServiceLock
+        virtual int32_t getServiceAudioRestriction() const;
+
+        // Get current audio restriction setting for this client
+        virtual int32_t getAudioRestriction() const;
+
+        static bool isValidAudioRestriction(int32_t mode);
     protected:
         BasicClient(const sp<CameraService>& cameraService,
                 const sp<IBinder>& remoteCallback,
                 const String16& clientPackageName,
+                const std::unique_ptr<String16>& clientFeatureId,
                 const String8& cameraIdStr,
                 int cameraFacing,
                 int clientPid,
@@ -281,11 +296,15 @@
         const String8                   mCameraIdStr;
         const int                       mCameraFacing;
         String16                        mClientPackageName;
+        std::unique_ptr<String16>       mClientFeatureId;
         pid_t                           mClientPid;
         const uid_t                     mClientUid;
         const pid_t                     mServicePid;
         bool                            mDisconnected;
 
+        mutable Mutex                   mAudioRestrictionLock;
+        int32_t                         mAudioRestriction;
+
         // - The app-side Binder interface to receive callbacks from us
         sp<IBinder>                     mRemoteBinder;   // immutable after constructor
 
@@ -349,6 +368,7 @@
         Client(const sp<CameraService>& cameraService,
                 const sp<hardware::ICameraClient>& cameraClient,
                 const String16& clientPackageName,
+                const std::unique_ptr<String16>& clientFeatureId,
                 const String8& cameraIdStr,
                 int api1CameraId,
                 int cameraFacing,
@@ -439,6 +459,9 @@
 
     }; // class CameraClientManager
 
+    int32_t updateAudioRestriction();
+    int32_t updateAudioRestrictionLocked();
+
 private:
 
     typedef hardware::camera::common::V1_0::CameraDeviceStatus CameraDeviceStatus;
@@ -472,7 +495,7 @@
          * returned in the HAL's camera_info struct for each device.
          */
         CameraState(const String8& id, int cost, const std::set<String8>& conflicting,
-                bool isHidden);
+                SystemCameraKind deviceKind);
         virtual ~CameraState();
 
         /**
@@ -525,9 +548,9 @@
         String8 getId() const;
 
         /**
-         * Return if the camera device is a publically hidden secure camera
+         * Return the kind (SystemCameraKind) of this camera device.
          */
-        bool isPublicallyHiddenSecureCamera() const;
+        SystemCameraKind getSystemCameraKind() const;
 
     private:
         const String8 mId;
@@ -536,7 +559,7 @@
         std::set<String8> mConflicting;
         mutable Mutex mStatusLock;
         CameraParameters mShimParams;
-        const bool mIsPublicallyHiddenSecureCamera;
+        const SystemCameraKind mSystemCameraKind;
     }; // class CameraState
 
     // Observer for UID lifecycle enforcing that UIDs in idle
@@ -555,7 +578,8 @@
         void onUidGone(uid_t uid, bool disabled);
         void onUidActive(uid_t uid);
         void onUidIdle(uid_t uid, bool disabled);
-        void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
+        void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+                int32_t capability);
 
         void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
         void removeOverrideUid(uid_t uid, String16 callingPackage);
@@ -640,18 +664,36 @@
         sp<BasicClient>* client,
         std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>>* partial);
 
-    // Should an operation attempt on a cameraId be rejected, if the camera id is
-    // advertised as a publically hidden secure camera, by the camera HAL ?
-    bool shouldRejectHiddenCameraConnection(const String8& cameraId);
+    // Should an operation attempt on a cameraId be rejected ? (this can happen
+    // under various conditions. For example if a camera device is advertised as
+    // system only or hidden secure camera, amongst possible others.
+    bool shouldRejectSystemCameraConnection(const String8 & cameraId) const;
 
-    bool isPublicallyHiddenSecureCamera(const String8& cameraId);
+    // Should a device status update be skipped for a particular camera device ? (this can happen
+    // under various conditions. For example if a camera device is advertised as
+    // system only or hidden secure camera, amongst possible others.
+    static bool shouldSkipStatusUpdates(SystemCameraKind systemCameraKind, bool isVendorListener,
+            int clientPid, int clientUid);
+
+    // Gets the kind of camera device (i.e public, hidden secure or system only)
+    // getSystemCameraKind() needs mInterfaceMutex which might lead to deadlocks
+    // if held along with mStatusListenerLock (depending on lock ordering, b/141756275), it is
+    // recommended that we don't call this function with mStatusListenerLock held.
+    status_t getSystemCameraKind(const String8& cameraId, SystemCameraKind *kind) const;
+
+    // Update the set of API1Compatible camera devices without including system
+    // cameras and secure cameras. This is used for hiding system only cameras
+    // from clients using camera1 api and not having android.permission.SYSTEM_CAMERA.
+    // This function expects @param normalDeviceIds, to have normalDeviceIds
+    // sorted in alpha-numeric order.
+    void filterAPI1SystemCameraLocked(const std::vector<std::string> &normalDeviceIds);
 
     // Single implementation shared between the various connect calls
     template<class CALLBACK, class CLIENT>
     binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
             int api1CameraId, int halVersion, const String16& clientPackageName,
-            int clientUid, int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
-            /*out*/sp<CLIENT>& device);
+            const std::unique_ptr<String16>& clientFeatureId, int clientUid, int clientPid,
+            apiLevel effectiveApiLevel, bool shimUpdateOnly, /*out*/sp<CLIENT>& device);
 
     // Lock guarding camera service state
     Mutex               mServiceLock;
@@ -800,9 +842,14 @@
      */
     void updateCameraNumAndIds();
 
+    // Number of camera devices (excluding hidden secure cameras)
     int                 mNumberOfCameras;
+    // Number of camera devices (excluding hidden secure cameras and
+    // system cameras)
+    int                 mNumberOfCamerasWithoutSystemCamera;
 
     std::vector<std::string> mNormalDeviceIds;
+    std::vector<std::string> mNormalDeviceIdsWithoutSystemCamera;
 
     // sounds
     sp<MediaPlayer>     newMediaPlayer(const char *file);
@@ -819,7 +866,9 @@
     class ServiceListener : public virtual IBinder::DeathRecipient {
         public:
             ServiceListener(sp<CameraService> parent, sp<hardware::ICameraServiceListener> listener,
-                    int uid) : mParent(parent), mListener(listener), mListenerUid(uid) {}
+                    int uid, int pid, bool isVendorClient)
+                    : mParent(parent), mListener(listener), mListenerUid(uid), mListenerPid(pid),
+                      mIsVendorListener(isVendorClient) { }
 
             status_t initialize() {
                 return IInterface::asBinder(mListener)->linkToDeath(this);
@@ -833,16 +882,20 @@
             }
 
             int getListenerUid() { return mListenerUid; }
+            int getListenerPid() { return mListenerPid; }
             sp<hardware::ICameraServiceListener> getListener() { return mListener; }
+            bool isVendorListener() { return mIsVendorListener; }
 
         private:
             wp<CameraService> mParent;
             sp<hardware::ICameraServiceListener> mListener;
-            int mListenerUid;
+            int mListenerUid = -1;
+            int mListenerPid = -1;
+            bool mIsVendorListener = false;
     };
 
     // Guarded by mStatusListenerMutex
-    std::vector<std::pair<bool, sp<ServiceListener>>> mListenerList;
+    std::vector<sp<ServiceListener>> mListenerList;
 
     Mutex       mStatusListenerLock;
 
@@ -936,9 +989,10 @@
     static String8 getFormattedCurrentTime();
 
     static binder::Status makeClient(const sp<CameraService>& cameraService,
-            const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
-            int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
-            int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+            const sp<IInterface>& cameraCb, const String16& packageName,
+            const std::unique_ptr<String16>& featureId, const String8& cameraId, int api1CameraId,
+            int facing, int clientPid, uid_t clientUid, int servicePid, int halVersion,
+            int deviceVersion, apiLevel effectiveApiLevel,
             /*out*/sp<BasicClient>* client);
 
     status_t checkCameraAccess(const String16& opPackageName);
@@ -958,6 +1012,13 @@
 
     void broadcastTorchModeStatus(const String8& cameraId,
             hardware::camera::common::V1_0::TorchModeStatus status);
+
+    // TODO: right now each BasicClient holds one AppOpsManager instance.
+    // We can refactor the code so all of clients share this instance
+    AppOpsManager mAppOps;
+
+    // Aggreated audio restriction mode for all camera clients
+    int32_t mAudioRestriction;
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 162b50f..5dbbc0b 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -50,13 +50,14 @@
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
         const sp<hardware::ICameraClient>& cameraClient,
         const String16& clientPackageName,
+        const std::unique_ptr<String16>& clientFeatureId,
         const String8& cameraDeviceId,
         int api1CameraId,
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
         int servicePid):
-        Camera2ClientBase(cameraService, cameraClient, clientPackageName,
+        Camera2ClientBase(cameraService, cameraClient, clientPackageName, clientFeatureId,
                 cameraDeviceId, api1CameraId, cameraFacing,
                 clientPid, clientUid, servicePid),
         mParameters(api1CameraId, cameraFacing)
@@ -959,6 +960,11 @@
         case Parameters::RECORD:
         case Parameters::PREVIEW:
             syncWithDevice();
+            // Due to flush a camera device sync is not a sufficient
+            // guarantee that the current client parameters are
+            // correctly applied. To resolve this wait for the current
+            // request id to return in the results.
+            waitUntilCurrentRequestIdLocked();
             res = stopStream();
             if (res != OK) {
                 ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
@@ -2253,6 +2259,58 @@
     return OK;
 }
 
+status_t Camera2Client::setAudioRestriction(int /*mode*/) {
+    // Empty implementation. setAudioRestriction is hidden interface and not
+    // supported by android.hardware.Camera API
+    return INVALID_OPERATION;
+}
+
+int32_t Camera2Client::getGlobalAudioRestriction() {
+    // Empty implementation. getAudioRestriction is hidden interface and not
+    // supported by android.hardware.Camera API
+    return INVALID_OPERATION;
+}
+
+status_t Camera2Client::waitUntilCurrentRequestIdLocked() {
+    int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
+    if (activeRequestId != 0) {
+        auto res = waitUntilRequestIdApplied(activeRequestId,
+                mDevice->getExpectedInFlightDuration());
+        if (res == TIMED_OUT) {
+            ALOGE("%s: Camera %d: Timed out waiting for current request id to return in results!",
+                    __FUNCTION__, mCameraId);
+            return res;
+        } else if (res != OK) {
+            ALOGE("%s: Camera %d: Error while waiting for current request id to return in results!",
+                    __FUNCTION__, mCameraId);
+            return res;
+        }
+    }
+
+    return OK;
+}
+
+status_t Camera2Client::waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout) {
+    Mutex::Autolock l(mLatestRequestMutex);
+    while (mLatestRequestId != requestId) {
+        nsecs_t startTime = systemTime();
+
+        auto res = mLatestRequestSignal.waitRelative(mLatestRequestMutex, timeout);
+        if (res != OK) return res;
+
+        timeout -= (systemTime() - startTime);
+    }
+
+    return OK;
+}
+
+void Camera2Client::notifyRequestId(int32_t requestId) {
+    Mutex::Autolock al(mLatestRequestMutex);
+
+    mLatestRequestId = requestId;
+    mLatestRequestSignal.signal();
+}
+
 const char* Camera2Client::kAutofocusLabel = "autofocus";
 const char* Camera2Client::kTakepictureLabel = "take_picture";
 
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index a9ea271..8034ab4 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -83,6 +83,8 @@
     virtual void            notifyError(int32_t errorCode,
                                         const CaptureResultExtras& resultExtras);
     virtual status_t        setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
+    virtual status_t        setAudioRestriction(int mode);
+    virtual int32_t         getGlobalAudioRestriction();
 
     /**
      * Interface used by CameraService
@@ -91,6 +93,7 @@
     Camera2Client(const sp<CameraService>& cameraService,
             const sp<hardware::ICameraClient>& cameraClient,
             const String16& clientPackageName,
+            const std::unique_ptr<String16>& clientFeatureId,
             const String8& cameraDeviceId,
             int api1CameraId,
             int cameraFacing,
@@ -122,6 +125,8 @@
 
     camera2::SharedParameters& getParameters();
 
+    void notifyRequestId(int32_t requestId);
+
     int getPreviewStreamId() const;
     int getCaptureStreamId() const;
     int getCallbackStreamId() const;
@@ -227,6 +232,12 @@
     status_t initializeImpl(TProviderPtr providerPtr, const String8& monitorTags);
 
     bool isZslEnabledInStillTemplate();
+
+    mutable Mutex mLatestRequestMutex;
+    Condition mLatestRequestSignal;
+    int32_t mLatestRequestId = -1;
+    status_t waitUntilRequestIdApplied(int32_t requestId, nsecs_t timeout);
+    status_t waitUntilCurrentRequestIdLocked();
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index d65ac7b..83da880 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -34,11 +34,11 @@
 
 CameraClient::CameraClient(const sp<CameraService>& cameraService,
         const sp<hardware::ICameraClient>& cameraClient,
-        const String16& clientPackageName,
+        const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
         int cameraId, int cameraFacing,
         int clientPid, int clientUid,
         int servicePid):
-        Client(cameraService, cameraClient, clientPackageName,
+        Client(cameraService, cameraClient, clientPackageName, clientFeatureId,
                 String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
                 clientUid, servicePid)
 {
@@ -534,7 +534,7 @@
     }
 
     if (mHardware != nullptr) {
-        VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->pointer());
+        VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->unsecurePointer());
         metadata->eType = kMetadataBufferTypeNativeHandleSource;
         metadata->pHandle = handle;
         mHardware->releaseRecordingFrame(dataPtr);
@@ -573,7 +573,7 @@
         }
 
         if (!disconnected) {
-            VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->pointer());
+            VideoNativeHandleMetadata *metadata = (VideoNativeHandleMetadata*)(dataPtr->unsecurePointer());
             metadata->eType = kMetadataBufferTypeNativeHandleSource;
             metadata->pHandle = handle;
             frames.push_back(dataPtr);
@@ -916,8 +916,12 @@
                 ALOGE("%s: dataPtr does not contain VideoNativeHandleMetadata!", __FUNCTION__);
                 return;
             }
+            // TODO: Using unsecurePointer() has some associated security pitfalls
+            //       (see declaration for details).
+            //       Either document why it is safe in this case or address the
+            //       issue (e.g. by copying).
             VideoNativeHandleMetadata *metadata =
-                (VideoNativeHandleMetadata*)(msg.dataPtr->pointer());
+                (VideoNativeHandleMetadata*)(msg.dataPtr->unsecurePointer());
             if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
                 handle = metadata->pHandle;
             }
@@ -1073,8 +1077,12 @@
 
         // Check if dataPtr contains a VideoNativeHandleMetadata.
         if (dataPtr->size() == sizeof(VideoNativeHandleMetadata)) {
+            // TODO: Using unsecurePointer() has some associated security pitfalls
+            //       (see declaration for details).
+            //       Either document why it is safe in this case or address the
+            //       issue (e.g. by copying).
             VideoNativeHandleMetadata *metadata =
-                (VideoNativeHandleMetadata*)(dataPtr->pointer());
+                (VideoNativeHandleMetadata*)(dataPtr->unsecurePointer());
             if (metadata->eType == kMetadataBufferTypeNativeHandleSource) {
                 handle = metadata->pHandle;
             }
@@ -1171,4 +1179,25 @@
     return INVALID_OPERATION;
 }
 
+status_t CameraClient::setAudioRestriction(int mode) {
+    if (!isValidAudioRestriction(mode)) {
+        ALOGE("%s: invalid audio restriction mode %d", __FUNCTION__, mode);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) {
+        return INVALID_OPERATION;
+    }
+    return BasicClient::setAudioRestriction(mode);
+}
+
+int32_t CameraClient::getGlobalAudioRestriction() {
+    Mutex::Autolock lock(mLock);
+    if (checkPidAndHardware() != NO_ERROR) {
+        return INVALID_OPERATION;
+    }
+    return BasicClient::getServiceAudioRestriction();
+}
+
 }; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 9530b6c..501ad18 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -59,11 +59,14 @@
     virtual String8         getParameters() const;
     virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
     virtual status_t        setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
+    virtual status_t        setAudioRestriction(int mode);
+    virtual int32_t         getGlobalAudioRestriction();
 
     // Interface used by CameraService
     CameraClient(const sp<CameraService>& cameraService,
             const sp<hardware::ICameraClient>& cameraClient,
             const String16& clientPackageName,
+            const std::unique_ptr<String16>& clientFeatureId,
             int cameraId,
             int cameraFacing,
             int clientPid,
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 88799f9..0c01a91 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -265,7 +265,7 @@
     Mutex::Autolock l(mInputMutex);
     while (!mStartCapture) {
         res = mStartCaptureSignal.waitRelative(mInputMutex,
-                kWaitDuration);
+                kIdleWaitDuration);
         if (res == TIMED_OUT) break;
     }
     if (mStartCapture) {
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 727dd53..9475a39 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -111,6 +111,7 @@
      * Internal to CaptureSequencer
      */
     static const nsecs_t kWaitDuration = 100000000; // 100 ms
+    static const nsecs_t kIdleWaitDuration = 10000000; // 10 ms
     static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
     static const int kMaxTimeoutsForPrecaptureEnd = 20;  // 2 sec
     static const int kMaxTimeoutsForCaptureEnd    = 40;  // 4 sec
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 683e84d..63e293a 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -86,6 +86,12 @@
         process3aState(frame, client);
     }
 
+    if (mCurrentRequestId != frame.mResultExtras.requestId) {
+        mCurrentRequestId = frame.mResultExtras.requestId;
+
+        client->notifyRequestId(mCurrentRequestId);
+    }
+
     return FrameProcessorBase::processSingleFrame(frame, device);
 }
 
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
index 8183c12..142b8cd 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
@@ -94,6 +94,7 @@
     };
 
     AlgState m3aState;
+    int32_t mCurrentRequestId = -1;
 
     // frame number -> pending 3A states that not all data are received yet.
     KeyedVector<int32_t, AlgState> mPending3AStates;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 3587db3..27bebde 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -54,6 +54,7 @@
         const sp<CameraService>& cameraService,
         const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
         const String16& clientPackageName,
+        const std::unique_ptr<String16>& clientFeatureId,
         const String8& cameraId,
         int api1CameraId,
         int cameraFacing,
@@ -63,6 +64,7 @@
     BasicClient(cameraService,
             IInterface::asBinder(remoteCallback),
             clientPackageName,
+            clientFeatureId,
             cameraId,
             cameraFacing,
             clientPid,
@@ -78,12 +80,13 @@
 CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
         const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
         const String16& clientPackageName,
+        const std::unique_ptr<String16>& clientFeatureId,
         const String8& cameraId,
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
         int servicePid) :
-    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
+    Camera2ClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
                 cameraId, /*API1 camera ID*/ -1,
                 cameraFacing, clientPid, clientUid, servicePid),
     mInputStream(),
@@ -1870,6 +1873,34 @@
     return res;
 }
 
+binder::Status CameraDeviceClient::setCameraAudioRestriction(int32_t mode) {
+    ATRACE_CALL();
+    binder::Status res;
+    if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+    if (!isValidAudioRestriction(mode)) {
+        String8 msg = String8::format("Camera %s: invalid audio restriction mode %d",
+                mCameraIdStr.string(), mode);
+        ALOGW("%s: %s", __FUNCTION__, msg.string());
+        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+    }
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+    BasicClient::setAudioRestriction(mode);
+    return binder::Status::ok();
+}
+
+binder::Status CameraDeviceClient::getGlobalAudioRestriction(/*out*/ int32_t* outMode) {
+    ATRACE_CALL();
+    binder::Status res;
+    if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+    Mutex::Autolock icl(mBinderSerializationLock);
+    if (outMode != nullptr) {
+        *outMode = BasicClient::getServiceAudioRestriction();
+    }
+    return binder::Status::ok();
+}
+
 status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
     return BasicClient::dump(fd, args);
 }
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 1c5abb0..7efc5ab 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -47,6 +47,7 @@
     CameraDeviceClientBase(const sp<CameraService>& cameraService,
             const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
             const String16& clientPackageName,
+            const std::unique_ptr<String16>& clientFeatureId,
             const String8& cameraId,
             int api1CameraId,
             int cameraFacing,
@@ -152,6 +153,10 @@
     virtual binder::Status finalizeOutputConfigurations(int32_t streamId,
             const hardware::camera2::params::OutputConfiguration &outputConfiguration) override;
 
+    virtual binder::Status setCameraAudioRestriction(int32_t mode) override;
+
+    virtual binder::Status getGlobalAudioRestriction(/*out*/int32_t* outMode) override;
+
     /**
      * Interface used by CameraService
      */
@@ -159,6 +164,7 @@
     CameraDeviceClient(const sp<CameraService>& cameraService,
             const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
             const String16& clientPackageName,
+            const std::unique_ptr<String16>& clientFeatureId,
             const String8& cameraId,
             int cameraFacing,
             int clientPid,
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 9790e32..bf4d1c8 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -1260,7 +1260,7 @@
     outputFormat->setInt32(KEY_I_FRAME_INTERVAL, 0);
     outputFormat->setInt32(KEY_COLOR_FORMAT,
             useGrid ? COLOR_FormatYUV420Flexible : COLOR_FormatSurface);
-    outputFormat->setInt32(KEY_FRAME_RATE, gridRows * gridCols);
+    outputFormat->setInt32(KEY_FRAME_RATE, useGrid ? gridRows * gridCols : kNoGridOpRate);
     // This only serves as a hint to encoder when encoding is not real-time.
     outputFormat->setInt32(KEY_OPERATING_RATE, useGrid ? kGridOpRate : kNoGridOpRate);
 
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 78feb3e..8792f9a 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -44,13 +44,14 @@
         const sp<CameraService>& cameraService,
         const sp<TCamCallbacks>& remoteCallback,
         const String16& clientPackageName,
+        const std::unique_ptr<String16>& clientFeatureId,
         const String8& cameraId,
         int api1CameraId,
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
         int servicePid):
-        TClientBase(cameraService, remoteCallback, clientPackageName,
+        TClientBase(cameraService, remoteCallback, clientPackageName, clientFeatureId,
                 cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
         mSharedCameraCallbacks(remoteCallback),
         mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 6693847..12cba0b 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -48,6 +48,7 @@
     Camera2ClientBase(const sp<CameraService>& cameraService,
                       const sp<TCamCallbacks>& remoteCallback,
                       const String16& clientPackageName,
+                      const std::unique_ptr<String16>& clientFeatureId,
                       const String8& cameraId,
                       int api1CameraId,
                       int cameraFacing,
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 98c1b5e..935bc37 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -383,6 +383,12 @@
      * drop buffers for stream of streamId.
      */
     virtual status_t dropStreamBuffers(bool /*dropping*/, int /*streamId*/) = 0;
+
+    /**
+     * Returns the maximum expected time it'll take for all currently in-flight
+     * requests to complete, based on their settings
+     */
+    virtual nsecs_t getExpectedInFlightDuration() = 0;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index fdb5657..7ed4c3d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -104,19 +104,30 @@
     return OK;
 }
 
-int CameraProviderManager::getCameraCount() const {
+std::pair<int, int> CameraProviderManager::getCameraCount() const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
-    int count = 0;
+    int systemCameraCount = 0;
+    int publicCameraCount = 0;
     for (auto& provider : mProviders) {
-        for (auto& id : provider->mUniqueCameraIds) {
-            // Hidden secure camera ids are not to be exposed to camera1 api.
-            if (isPublicallyHiddenSecureCameraLocked(id)) {
+        for (auto &id : provider->mUniqueCameraIds) {
+            SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+            if (getSystemCameraKindLocked(id, &deviceKind) != OK) {
+                ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, id.c_str());
                 continue;
             }
-            count++;
+            switch(deviceKind) {
+                case SystemCameraKind::PUBLIC:
+                    publicCameraCount++;
+                    break;
+                case SystemCameraKind::SYSTEM_ONLY_CAMERA:
+                    systemCameraCount++;
+                    break;
+                default:
+                    break;
+            }
         }
     }
-    return count;
+    return std::make_pair(systemCameraCount, publicCameraCount);
 }
 
 std::vector<std::string> CameraProviderManager::getCameraDeviceIds() const {
@@ -130,25 +141,47 @@
     return deviceIds;
 }
 
+void CameraProviderManager::collectDeviceIdsLocked(const std::vector<std::string> deviceIds,
+        std::vector<std::string>& publicDeviceIds,
+        std::vector<std::string>& systemDeviceIds) const {
+    for (auto &deviceId : deviceIds) {
+        SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+        if (getSystemCameraKindLocked(deviceId, &deviceKind) != OK) {
+            ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, deviceId.c_str());
+            continue;
+        }
+        if (deviceKind == SystemCameraKind::SYSTEM_ONLY_CAMERA) {
+            systemDeviceIds.push_back(deviceId);
+        } else {
+            publicDeviceIds.push_back(deviceId);
+        }
+    }
+}
+
 std::vector<std::string> CameraProviderManager::getAPI1CompatibleCameraDeviceIds() const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    std::vector<std::string> publicDeviceIds;
+    std::vector<std::string> systemDeviceIds;
     std::vector<std::string> deviceIds;
     for (auto& provider : mProviders) {
         std::vector<std::string> providerDeviceIds = provider->mUniqueAPI1CompatibleCameraIds;
-
+        // Secure cameras should not be exposed through camera 1 api
+        providerDeviceIds.erase(std::remove_if(providerDeviceIds.begin(), providerDeviceIds.end(),
+                [this](const std::string& s) {
+                SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
+                if (getSystemCameraKindLocked(s, &deviceKind) != OK) {
+                    ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, s.c_str());
+                    return true;
+                }
+                return deviceKind == SystemCameraKind::HIDDEN_SECURE_CAMERA;}),
+                providerDeviceIds.end());
         // API1 app doesn't handle logical and physical camera devices well. So
         // for each camera facing, only take the first id advertised by HAL in
         // all [logical, physical1, physical2, ...] id combos, and filter out the rest.
         filterLogicalCameraIdsLocked(providerDeviceIds);
-        // Hidden secure camera ids are not to be exposed to camera1 api.
-        providerDeviceIds.erase(std::remove_if(providerDeviceIds.begin(), providerDeviceIds.end(),
-                [this](const std::string& s) {
-                    return this->isPublicallyHiddenSecureCameraLocked(s);}),
-                providerDeviceIds.end());
-        deviceIds.insert(deviceIds.end(), providerDeviceIds.begin(), providerDeviceIds.end());
+        collectDeviceIdsLocked(providerDeviceIds, publicDeviceIds, systemDeviceIds);
     }
-
-    std::sort(deviceIds.begin(), deviceIds.end(),
+    auto sortFunc =
             [](const std::string& a, const std::string& b) -> bool {
                 uint32_t aUint = 0, bUint = 0;
                 bool aIsUint = base::ParseUint(a, &aUint);
@@ -164,7 +197,13 @@
                 }
                 // Simple string compare if both id are not uint
                 return a < b;
-            });
+            };
+    // We put device ids for system cameras at the end since they will be pared
+    // off for processes not having system camera permissions.
+    std::sort(publicDeviceIds.begin(), publicDeviceIds.end(), sortFunc);
+    std::sort(systemDeviceIds.begin(), systemDeviceIds.end(), sortFunc);
+    deviceIds.insert(deviceIds.end(), publicDeviceIds.begin(), publicDeviceIds.end());
+    deviceIds.insert(deviceIds.end(), systemDeviceIds.begin(), systemDeviceIds.end());
     return deviceIds;
 }
 
@@ -544,15 +583,23 @@
     }
 }
 
-bool CameraProviderManager::ProviderInfo::DeviceInfo3::isPublicallyHiddenSecureCamera() {
+SystemCameraKind CameraProviderManager::ProviderInfo::DeviceInfo3::getSystemCameraKind() {
     camera_metadata_entry_t entryCap;
     entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
-    if (entryCap.count != 1) {
-        // Do NOT hide this camera device if the capabilities specify anything more
-        // than ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA.
-        return false;
+    if (entryCap.count == 1 &&
+            entryCap.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) {
+        return SystemCameraKind::HIDDEN_SECURE_CAMERA;
     }
-    return entryCap.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA;
+
+    // Go through the capabilities and check if it has
+    // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA
+    for (size_t i = 0; i < entryCap.count; ++i) {
+        uint8_t capability = entryCap.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA) {
+            return SystemCameraKind::SYSTEM_ONLY_CAMERA;
+        }
+    }
+    return SystemCameraKind::PUBLIC;
 }
 
 void CameraProviderManager::ProviderInfo::DeviceInfo3::getSupportedSizes(
@@ -1056,15 +1103,18 @@
     return deviceInfo->mIsLogicalCamera;
 }
 
-bool CameraProviderManager::isPublicallyHiddenSecureCamera(const std::string& id) const {
+status_t CameraProviderManager::getSystemCameraKind(const std::string& id,
+        SystemCameraKind *kind) const {
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
-    return isPublicallyHiddenSecureCameraLocked(id);
+    return getSystemCameraKindLocked(id, kind);
 }
 
-bool CameraProviderManager::isPublicallyHiddenSecureCameraLocked(const std::string& id) const {
+status_t CameraProviderManager::getSystemCameraKindLocked(const std::string& id,
+        SystemCameraKind *kind) const {
     auto deviceInfo = findDeviceInfoLocked(id);
     if (deviceInfo != nullptr) {
-        return deviceInfo->mIsPublicallyHiddenSecureCamera;
+        *kind = deviceInfo->mSystemCameraKind;
+        return OK;
     }
     // If this is a hidden physical camera, we should return what kind of
     // camera the enclosing logical camera is.
@@ -1073,10 +1123,10 @@
         LOG_ALWAYS_FATAL_IF(id == isHiddenAndParent.second->mId,
                 "%s: hidden physical camera id %s and enclosing logical camera id %s are the same",
                 __FUNCTION__, id.c_str(), isHiddenAndParent.second->mId.c_str());
-        return isPublicallyHiddenSecureCameraLocked(isHiddenAndParent.second->mId);
+        return getSystemCameraKindLocked(isHiddenAndParent.second->mId, kind);
     }
-    // Invalid camera id
-    return true;
+    // Neither a hidden physical camera nor a logical camera
+    return NAME_NOT_FOUND;
 }
 
 bool CameraProviderManager::isHiddenPhysicalCamera(const std::string& cameraId) const {
@@ -1137,7 +1187,7 @@
     }
 
     sp<provider::V2_4::ICameraProvider> interface;
-    interface = mServiceProxy->getService(newProvider);
+    interface = mServiceProxy->tryGetService(newProvider);
 
     if (interface == nullptr) {
         ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
@@ -1966,7 +2016,7 @@
         return;
     }
 
-    mIsPublicallyHiddenSecureCamera = isPublicallyHiddenSecureCamera();
+    mSystemCameraKind = getSystemCameraKind();
 
     status_t res = fixupMonochromeTags();
     if (OK != res) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 954c0d9..2ef1f6f 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -54,6 +54,26 @@
             sp<VendorTagDescriptor>& descriptor);
 };
 
+enum SystemCameraKind {
+   /**
+    * These camera devices are visible to all apps and system components alike
+    */
+   PUBLIC = 0,
+
+   /**
+    * These camera devices are visible only to processes having the
+    * android.permission.SYSTEM_CAMERA permission. They are not exposed to 3P
+    * apps.
+    */
+   SYSTEM_ONLY_CAMERA,
+
+   /**
+    * These camera devices are visible only to HAL clients (that try to connect
+    * on a hwbinder thread).
+    */
+   HIDDEN_SECURE_CAMERA
+};
+
 /**
  * A manager for all camera providers available on an Android device.
  *
@@ -76,6 +96,10 @@
                 const std::string &serviceName,
                 const sp<hidl::manager::V1_0::IServiceNotification>
                 &notification) = 0;
+        // Will not wait for service to start if it's not already running
+        virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+                const std::string &serviceName) = 0;
+        // Will block for service if it exists but isn't running
         virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
                 const std::string &serviceName) = 0;
         virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
@@ -92,6 +116,10 @@
             return hardware::camera::provider::V2_4::ICameraProvider::registerForNotifications(
                     serviceName, notification);
         }
+        virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+                const std::string &serviceName) override {
+            return hardware::camera::provider::V2_4::ICameraProvider::tryGetService(serviceName);
+        }
         virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
                 const std::string &serviceName) override {
             return hardware::camera::provider::V2_4::ICameraProvider::getService(serviceName);
@@ -132,10 +160,10 @@
             ServiceInteractionProxy *proxy = &sHardwareServiceInteractionProxy);
 
     /**
-     * Retrieve the total number of available cameras. This value may change dynamically as cameras
-     * are added or removed.
+     * Retrieve the total number of available cameras.
+     * This value may change dynamically as cameras are added or removed.
      */
-    int getCameraCount() const;
+    std::pair<int, int> getCameraCount() const;
 
     std::vector<std::string> getCameraDeviceIds() const;
 
@@ -272,8 +300,7 @@
      */
     bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
 
-    bool isPublicallyHiddenSecureCamera(const std::string& id) const;
-
+    status_t getSystemCameraKind(const std::string& id, SystemCameraKind *kind) const;
     bool isHiddenPhysicalCamera(const std::string& cameraId) const;
 
     static const float kDepthARTolerance;
@@ -380,7 +407,7 @@
             std::vector<std::string> mPhysicalIds;
             hardware::CameraInfo mInfo;
             sp<IBase> mSavedInterface;
-            bool mIsPublicallyHiddenSecureCamera = false;
+            SystemCameraKind mSystemCameraKind = SystemCameraKind::PUBLIC;
 
             const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
 
@@ -498,7 +525,7 @@
             CameraMetadata mCameraCharacteristics;
             std::unordered_map<std::string, CameraMetadata> mPhysicalCameraCharacteristics;
             void queryPhysicalCameraIds();
-            bool isPublicallyHiddenSecureCamera();
+            SystemCameraKind getSystemCameraKind();
             status_t fixupMonochromeTags();
             status_t addDynamicDepthTags();
             static void getSupportedSizes(const CameraMetadata& ch, uint32_t tag,
@@ -595,15 +622,14 @@
 
     status_t getCameraCharacteristicsLocked(const std::string &id,
             CameraMetadata* characteristics) const;
-
-    bool isPublicallyHiddenSecureCameraLocked(const std::string& id) const;
-
     void filterLogicalCameraIdsLocked(std::vector<std::string>& deviceIds) const;
 
-    bool isPublicallyHiddenSecureCameraLocked(const std::string& id);
+    status_t getSystemCameraKindLocked(const std::string& id, SystemCameraKind *kind) const;
+    std::pair<bool, ProviderInfo::DeviceInfo *> isHiddenPhysicalCameraInternal(const std::string& cameraId) const;
 
-    std::pair<bool, CameraProviderManager::ProviderInfo::DeviceInfo *>
-            isHiddenPhysicalCameraInternal(const std::string& cameraId) const;
+    void collectDeviceIdsLocked(const std::vector<std::string> deviceIds,
+            std::vector<std::string>& normalDeviceIds,
+            std::vector<std::string>& systemCameraDeviceIds) const;
 };
 
 } // namespace android
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
index 522d521..62ef681 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp
@@ -165,8 +165,12 @@
         mem = mHidlMemPoolMap.at(data);
     }
     sp<CameraHeapMemory> heapMem(static_cast<CameraHeapMemory *>(mem->handle));
+    // TODO: Using unsecurePointer() has some associated security pitfalls
+    //       (see declaration for details).
+    //       Either document why it is safe in this case or address the
+    //       issue (e.g. by copying).
     VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
-            heapMem->mBuffers[bufferIndex]->pointer();
+            heapMem->mBuffers[bufferIndex]->unsecurePointer();
     md->pHandle = const_cast<native_handle_t*>(frameData.getNativeHandle());
     sDataCbTimestamp(timestamp, (int32_t) msgType, mem, bufferIndex, this);
     return hardware::Void();
@@ -192,8 +196,12 @@
                      hidl_msg.bufferIndex, mem->mNumBufs);
                 return hardware::Void();
             }
+            // TODO: Using unsecurePointer() has some associated security pitfalls
+            //       (see declaration for details).
+            //       Either document why it is safe in this case or address the
+            //       issue (e.g. by copying).
             VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*)
-                    mem->mBuffers[hidl_msg.bufferIndex]->pointer();
+                    mem->mBuffers[hidl_msg.bufferIndex]->unsecurePointer();
             md->pHandle = const_cast<native_handle_t*>(hidl_msg.frameData.getNativeHandle());
 
             msgs.push_back({hidl_msg.timestamp, mem->mBuffers[hidl_msg.bufferIndex]});
@@ -578,7 +586,11 @@
     int bufferIndex = offset / size;
     if (CC_LIKELY(mHidlDevice != nullptr)) {
         if (size == sizeof(VideoNativeHandleMetadata)) {
-            VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->pointer();
+            // TODO: Using unsecurePointer() has some associated security pitfalls
+            //       (see declaration for details).
+            //       Either document why it is safe in this case or address the
+            //       issue (e.g. by copying).
+            VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->unsecurePointer();
             // Caching the handle here because md->pHandle will be subject to HAL's edit
             native_handle_t* nh = md->pHandle;
             hidl_handle frame = nh;
@@ -605,7 +617,11 @@
             if (size == sizeof(VideoNativeHandleMetadata)) {
                 uint32_t heapId = heap->getHeapID();
                 uint32_t bufferIndex = offset / size;
-                VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->pointer();
+                // TODO: Using unsecurePointer() has some associated security pitfalls
+                //       (see declaration for details).
+                //       Either document why it is safe in this case or address the
+                //       issue (e.g. by copying).
+                VideoNativeHandleMetadata* md = (VideoNativeHandleMetadata*) mem->unsecurePointer();
                 // Caching the handle here because md->pHandle will be subject to HAL's edit
                 native_handle_t* nh = md->pHandle;
                 VideoFrameMessage msg;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4227a3b..3188892 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2802,6 +2802,27 @@
         mOperatingMode = operatingMode;
     }
 
+    // In case called from configureStreams, abort queued input buffers not belonging to
+    // any pending requests.
+    if (mInputStream != NULL && notifyRequestThread) {
+        while (true) {
+            camera3_stream_buffer_t inputBuffer;
+            status_t res = mInputStream->getInputBuffer(&inputBuffer,
+                    /*respectHalLimit*/ false);
+            if (res != OK) {
+                // Exhausted acquiring all input buffers.
+                break;
+            }
+
+            inputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+            res = mInputStream->returnInputBuffer(inputBuffer);
+            if (res != OK) {
+                ALOGE("%s: %d: couldn't return input buffer while clearing input queue: "
+                        "%s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
+            }
+        }
+    }
+
     if (!mNeedConfig) {
         ALOGV("%s: Skipping config, no stream changes", __FUNCTION__);
         return OK;
@@ -3679,7 +3700,7 @@
         // Did we get the (final) result metadata for this capture?
         if (result->result != NULL && !isPartialResult) {
             if (request.physicalCameraIds.size() != result->num_physcam_metadata) {
-                SET_ERR("Requested physical Camera Ids %d not equal to number of metadata %d",
+                SET_ERR("Expected physical Camera metadata count %d not equal to actual count %d",
                         request.physicalCameraIds.size(), result->num_physcam_metadata);
                 return;
             }
@@ -3873,12 +3894,14 @@
                             errorCode) {
                         if (physicalCameraId.size() > 0) {
                             String8 cameraId(physicalCameraId);
-                            if (r.physicalCameraIds.find(cameraId) == r.physicalCameraIds.end()) {
+                            auto iter = r.physicalCameraIds.find(cameraId);
+                            if (iter == r.physicalCameraIds.end()) {
                                 ALOGE("%s: Reported result failure for physical camera device: %s "
                                         " which is not part of the respective request!",
                                         __FUNCTION__, cameraId.string());
                                 break;
                             }
+                            r.physicalCameraIds.erase(iter);
                             resultExtras.errorPhysicalCameraId = physicalCameraId;
                         } else {
                             logicalDeviceResultError = true;
@@ -5082,6 +5105,7 @@
                     ALOGW("%s: %d: couldn't get input buffer while clearing the request "
                             "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
                 } else {
+                    inputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
                     res = (*it)->mInputStream->returnInputBuffer(inputBuffer);
                     if (res != OK) {
                         ALOGE("%s: %d: couldn't return input buffer while clearing the request "
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index cae34ce..2573b48 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -194,6 +194,8 @@
      */
     status_t dropStreamBuffers(bool dropping, int streamId) override;
 
+    nsecs_t getExpectedInFlightDuration() override;
+
     /**
      * Helper functions to map between framework and HIDL values
      */
@@ -1111,12 +1113,6 @@
             const SurfaceMap& outputSurfaces);
 
     /**
-     * Returns the maximum expected time it'll take for all currently in-flight
-     * requests to complete, based on their settings
-     */
-    nsecs_t getExpectedInFlightDuration();
-
-    /**
      * Tracking for idle detection
      */
     sp<camera3::StatusTracker> mStatusTracker;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index fc83684..cb59a76 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -71,7 +71,8 @@
 
     res = mConsumer->acquireBuffer(&bufferItem, /*waitForFence*/false);
     if (res != OK) {
-        ALOGE("%s: Stream %d: Can't acquire next output buffer: %s (%d)",
+        // This may or may not be an error condition depending on caller.
+        ALOGV("%s: Stream %d: Can't acquire next output buffer: %s (%d)",
                 __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index acb8b3c..e1d35e8 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -54,9 +54,8 @@
         mState = STATE_ERROR;
     }
 
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 }
 
 Camera3OutputStream::Camera3OutputStream(int id,
@@ -87,9 +86,8 @@
         mState = STATE_ERROR;
     }
 
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 }
 
 Camera3OutputStream::Camera3OutputStream(int id,
@@ -124,10 +122,8 @@
     }
 
     mConsumerName = String8("Deferred");
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
-
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 }
 
 Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
@@ -151,9 +147,8 @@
         mDropBuffers(false),
         mDequeueBufferLatency(kDequeueLatencyBinSize) {
 
-    if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
-        mBufferReleasedListener = new BufferReleasedListener(this);
-    }
+    bool needsReleaseNotify = setId > CAMERA3_STREAM_SET_ID_INVALID;
+    mBufferProducerListener = new BufferProducerListener(this, needsReleaseNotify);
 
     // Subclasses expected to initialize mConsumer themselves
 }
@@ -261,7 +256,7 @@
         notifyBufferReleased(anwBuffer);
         if (mUseBufferManager) {
             // Return this buffer back to buffer manager.
-            mBufferReleasedListener->onBufferReleased();
+            mBufferProducerListener->onBufferReleased();
         }
     } else {
         if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
@@ -387,8 +382,8 @@
     // Configure consumer-side ANativeWindow interface. The listener may be used
     // to notify buffer manager (if it is used) of the returned buffers.
     res = mConsumer->connect(NATIVE_WINDOW_API_CAMERA,
-            /*listener*/mBufferReleasedListener,
-            /*reportBufferRemoval*/true);
+            /*reportBufferRemoval*/true,
+            /*listener*/mBufferProducerListener);
     if (res != OK) {
         ALOGE("%s: Unable to connect to native window for stream %d",
                 __FUNCTION__, mId);
@@ -790,7 +785,7 @@
     return INVALID_OPERATION;
 }
 
-void Camera3OutputStream::BufferReleasedListener::onBufferReleased() {
+void Camera3OutputStream::BufferProducerListener::onBufferReleased() {
     sp<Camera3OutputStream> stream = mParent.promote();
     if (stream == nullptr) {
         ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
@@ -823,6 +818,25 @@
     }
 }
 
+void Camera3OutputStream::BufferProducerListener::onBuffersDiscarded(
+        const std::vector<sp<GraphicBuffer>>& buffers) {
+    sp<Camera3OutputStream> stream = mParent.promote();
+    if (stream == nullptr) {
+        ALOGV("%s: Parent camera3 output stream was destroyed", __FUNCTION__);
+        return;
+    }
+
+    if (buffers.size() > 0) {
+        Mutex::Autolock l(stream->mLock);
+        stream->onBuffersRemovedLocked(buffers);
+        if (stream->mUseBufferManager) {
+            stream->mBufferManager->onBuffersRemoved(stream->getId(),
+                    stream->getStreamSetId(), buffers.size());
+        }
+        ALOGV("Stream %d: %zu Buffers discarded.", stream->getId(), buffers.size());
+    }
+}
+
 void Camera3OutputStream::onBuffersRemovedLocked(
         const std::vector<sp<GraphicBuffer>>& removedBuffers) {
     sp<Camera3StreamBufferFreedListener> callback = mBufferFreedListener.promote();
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 729c655..b4e49f9 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -146,18 +146,22 @@
      */
     virtual status_t setConsumers(const std::vector<sp<Surface>>& consumers);
 
-    class BufferReleasedListener : public BnProducerListener {
+    class BufferProducerListener : public SurfaceListener {
         public:
-          BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {}
+            BufferProducerListener(wp<Camera3OutputStream> parent, bool needsReleaseNotify)
+                    : mParent(parent), mNeedsReleaseNotify(needsReleaseNotify) {}
 
-          /**
-          * Implementation of IProducerListener, used to notify this stream that the consumer
-          * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
-          */
-          virtual void onBufferReleased();
+            /**
+            * Implementation of IProducerListener, used to notify this stream that the consumer
+            * has returned a buffer and it is ready to return to Camera3BufferManager for reuse.
+            */
+            virtual void onBufferReleased();
+            virtual bool needsReleaseNotify() { return mNeedsReleaseNotify; }
+            virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers);
 
         private:
-          wp<Camera3OutputStream> mParent;
+            wp<Camera3OutputStream> mParent;
+            bool mNeedsReleaseNotify;
     };
 
     virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd);
@@ -262,10 +266,10 @@
     sp<Camera3BufferManager> mBufferManager;
 
     /**
-     * Buffer released listener, used to notify the buffer manager that a buffer is released
-     * from consumer side.
+     * Buffer producer listener, used to handle notification when a buffer is released
+     * from consumer side, or a set of buffers are discarded by the consumer.
      */
-    sp<BufferReleasedListener> mBufferReleasedListener;
+    sp<BufferProducerListener> mBufferProducerListener;
 
     /**
      * Flag indicating if the buffer manager is used to allocate the stream buffers
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index fd9b4b0..f707ef8 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -70,7 +70,7 @@
     mFormatOverridden(false),
     mOriginalFormat(format),
     mDataSpaceOverridden(false),
-    mOriginalDataSpace(HAL_DATASPACE_UNKNOWN),
+    mOriginalDataSpace(dataSpace),
     mPhysicalCameraId(physicalCameraId),
     mLastTimestamp(0) {
 
@@ -137,9 +137,6 @@
 
 void Camera3Stream::setDataSpaceOverride(bool dataSpaceOverridden) {
     mDataSpaceOverridden = dataSpaceOverridden;
-    if (dataSpaceOverridden && mOriginalDataSpace == HAL_DATASPACE_UNKNOWN) {
-        mOriginalDataSpace = camera3_stream::data_space;
-    }
 }
 
 bool Camera3Stream::isDataSpaceOverridden() const {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 67afd0f..805df82 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -588,7 +588,7 @@
 
     //Keep track of original dataSpace in case it gets overridden
     bool mDataSpaceOverridden;
-    android_dataspace mOriginalDataSpace;
+    const android_dataspace mOriginalDataSpace;
 
     String8 mPhysicalCameraId;
     nsecs_t mLastTimestamp;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 3089181..5c6c518 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -498,7 +498,7 @@
         mInputSlots[bufferItem.mSlot].mFrameNumber = bufferItem.mFrameNumber;
     } else {
         SP_LOGE("%s: Invalid input graphic buffer!", __FUNCTION__);
-        res = BAD_VALUE;
+        mOnFrameAvailableRes.store(BAD_VALUE);
         return;
     }
     bufferId = bufferItem.mGraphicBuffer->getId();
@@ -543,6 +543,11 @@
     mOnFrameAvailableRes.store(res);
 }
 
+void Camera3StreamSplitter::onFrameReplaced(const BufferItem& item) {
+    ATRACE_CALL();
+    onFrameAvailable(item);
+}
+
 void Camera3StreamSplitter::decrementBufRefCountLocked(uint64_t id, size_t surfaceId) {
     ATRACE_CALL();
 
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 960f7aa..4eb455a 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -102,6 +102,13 @@
     void onFrameAvailable(const BufferItem& item) override;
 
     // From IConsumerListener
+    //
+    // Similar to onFrameAvailable, but buffer item is indeed replacing a buffer
+    // in the buffer queue. This can happen when buffer queue is in droppable
+    // mode.
+    void onFrameReplaced(const BufferItem& item) override;
+
+    // From IConsumerListener
     // We don't care about released buffers because we detach each buffer as
     // soon as we acquire it. See the comment for onBufferReleased below for
     // some clarifying notes about the name.
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 74cfe42..97ba9c4 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -103,7 +103,7 @@
     }
     sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = hybridCallbacks;
     binder::Status serviceRet = mAidlICameraService->connectDevice(
-            callbacks, String16(cameraId.c_str()), String16(""),
+            callbacks, String16(cameraId.c_str()), String16(""), std::unique_ptr<String16>(),
             hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
     HStatus status = HStatus::NO_ERROR;
     if (!serviceRet.isOk()) {
@@ -191,6 +191,14 @@
       _hidl_cb(status, {});
       return Void();
     }
+    cameraStatusAndIds.erase(std::remove_if(cameraStatusAndIds.begin(), cameraStatusAndIds.end(),
+            [this](const hardware::CameraStatus& s) {
+              bool supportsHAL3 = false;
+              binder::Status sRet =
+                            mAidlICameraService->supportsCameraApi(String16(s.cameraId),
+                                    hardware::ICameraService::API_VERSION_2, &supportsHAL3);
+              return !sRet.isOk() || !supportsHAL3;
+            }), cameraStatusAndIds.end());
     hidl_vec<HCameraStatusAndId> hCameraStatusAndIds;
     //Convert cameraStatusAndIds to HIDL and call callback
     convertToHidl(cameraStatusAndIds, &hCameraStatusAndIds);
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 78d737d..084dc62 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -183,6 +183,7 @@
     sp<TestICameraProvider> mTestCameraProvider;
 
     TestInteractionProxy() {}
+
     void setProvider(sp<TestICameraProvider> provider) {
         mTestCameraProvider = provider;
     }
@@ -199,13 +200,31 @@
         return true;
     }
 
+    virtual sp<hardware::camera::provider::V2_4::ICameraProvider> tryGetService(
+            const std::string &serviceName) override {
+        // If no provider has been given, act like the HAL isn't available and return null.
+        if (mTestCameraProvider == nullptr) return nullptr;
+        return getService(serviceName);
+    }
+
     virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
             const std::string &serviceName) override {
+        // If no provider has been given, fail; in reality, getService would
+        // block for HALs that don't start correctly, so we should never use
+        // getService when we don't have a valid HAL running
+        if (mTestCameraProvider == nullptr) {
+            ADD_FAILURE() << "getService called with no valid provider; would block indefinitely";
+            // Real getService would block, but that's bad in unit tests. So
+            // just record an error and return nullptr
+            return nullptr;
+        }
         mLastRequestedServiceNames.push_back(serviceName);
         return mTestCameraProvider;
     }
 
     virtual hardware::hidl_vec<hardware::hidl_string> listServices() override {
+        // Always provide a list even if there's no actual provider yet, to
+        // simulate stuck HAL situations as well
         hardware::hidl_vec<hardware::hidl_string> ret = {"test/0"};
         return ret;
     }
@@ -438,3 +457,52 @@
             << "Unable to change device state";
 
 }
+
+// Test that CameraProviderManager doesn't get stuck when the camera HAL isn't really working
+TEST(CameraProviderManagerTest, BadHalStartupTest) {
+
+    std::vector<hardware::hidl_string> deviceNames;
+    deviceNames.push_back("device@3.2/test/0");
+    deviceNames.push_back("device@1.0/test/0");
+    deviceNames.push_back("device@3.2/test/1");
+    hardware::hidl_vec<common::V1_0::VendorTagSection> vendorSection;
+    status_t res;
+
+    sp<CameraProviderManager> providerManager = new CameraProviderManager();
+    sp<TestStatusListener> statusListener = new TestStatusListener();
+    TestInteractionProxy serviceProxy;
+    sp<TestICameraProvider> provider =  new TestICameraProvider(deviceNames,
+            vendorSection);
+
+    // Not setting up provider in the service proxy yet, to test cases where a
+    // HAL isn't starting right
+    res = providerManager->initialize(statusListener, &serviceProxy);
+    ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
+
+    // Now set up provider and trigger a registration
+    serviceProxy.setProvider(provider);
+    int numProviders = static_cast<int>(serviceProxy.listServices().size());
+
+    hardware::hidl_string testProviderFqInterfaceName =
+            "android.hardware.camera.provider@2.4::ICameraProvider";
+    hardware::hidl_string testProviderInstanceName = "test/0";
+    serviceProxy.mManagerNotificationInterface->onRegistration(
+            testProviderFqInterfaceName,
+            testProviderInstanceName, false);
+
+    // Check that new provider is called once for all the init methods
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], numProviders) <<
+            "Only one call to setCallback per provider expected during register";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], numProviders) <<
+            "Only one call to getVendorTags per provider expected during register";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED],
+            numProviders) <<
+            "Only one call to isSetTorchModeSupported per provider expected during init";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], numProviders) <<
+            "Only one call to getCameraIdList per provider expected during init";
+    EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], numProviders) <<
+            "Only one call to notifyDeviceState per provider expected during init";
+
+    ASSERT_EQ(serviceProxy.mLastRequestedServiceNames.back(), testProviderInstanceName) <<
+            "Incorrect instance requested from service manager";
+}
diff --git a/services/mediaanalytics/Android.bp b/services/mediaanalytics/Android.bp
index c27aced..dc72064 100644
--- a/services/mediaanalytics/Android.bp
+++ b/services/mediaanalytics/Android.bp
@@ -6,8 +6,32 @@
 
     srcs: [
         "main_mediametrics.cpp",
-        "MediaAnalyticsService.cpp",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libmediaanalyticsservice",
+        "libutils",
+    ],
+
+    init_rc: [
+        "mediametrics.rc",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
+
+cc_library_shared {
+    name: "libmediaanalyticsservice",
+
+    srcs: [
         "iface_statsd.cpp",
+        "MediaAnalyticsService.cpp",
         "statsd_audiopolicy.cpp",
         "statsd_audiorecord.cpp",
         "statsd_audiothread.cpp",
@@ -24,45 +48,25 @@
     },
 
     shared_libs: [
-        "libcutils",
-        "liblog",
-        "libmedia",
-        "libutils",
         "libbinder",
-        "libdl",
-        "libgui",
-        "libmedia",
-        "libmediautils",
+        "liblog",
         "libmediametrics",
-        "libstagefright_foundation",
+        "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
-        "libprotobuf-cpp-lite",
     ],
 
     static_libs: [
         "libplatformprotos",
-        "libregistermsext",
     ],
 
     include_dirs: [
-        "frameworks/av/media/libstagefright/include",
-        "frameworks/av/media/libstagefright/rtsp",
-        "frameworks/av/media/libstagefright/webm",
-        "frameworks/av/include/media",
-        "frameworks/av/camera/include/camera",
-        "frameworks/native/include/media/openmax",
-        "frameworks/native/include/media/hardware",
-        "external/tremolo/Tremolo",
+        "system/media/audio_utils/include",
     ],
 
-    init_rc: ["mediametrics.rc"],
-
     cflags: [
-        "-Werror",
         "-Wall",
-        "-Wno-error=deprecated-declarations",
+        "-Werror",
+        "-Wextra",
     ],
-    clang: true,
-
 }
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 0e7edfd..1ed8b74 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -14,66 +14,20 @@
  * limitations under the License.
  */
 
-// Proxy for media player implementations
-
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaAnalyticsService"
 #include <utils/Log.h>
 
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include <string.h>
-#include <pwd.h>
-
-#include <cutils/atomic.h>
-#include <cutils/properties.h> // for property_get
-
-#include <utils/misc.h>
-
-#include <android/content/pm/IPackageManagerNative.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
-#include <gui/Surface.h>
-#include <utils/Errors.h>  // for status_t
-#include <utils/List.h>
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <media/IMediaHTTPService.h>
-#include <media/IRemoteDisplay.h>
-#include <media/IRemoteDisplayClient.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/mediarecorder.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-#include <media/Metadata.h>
-#include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/stagefright/MediaCodecList.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <mediautils/BatteryNotifier.h>
-
-//#include <memunreachable/memunreachable.h>
-#include <system/audio.h>
-
-#include <private/android_filesystem_config.h>
-
 #include "MediaAnalyticsService.h"
 
+#include <pwd.h> //getpwuid
+
+#include <audio_utils/clock.h>                 // clock conversions
+#include <android/content/pm/IPackageManagerNative.h>  // package info
+#include <binder/IPCThreadState.h>             // get calling uid
+#include <cutils/properties.h>                 // for property_get
+#include <private/android_filesystem_config.h> // UID
+
 namespace android {
 
 // individual records kept in memory: age or count
@@ -81,192 +35,143 @@
 // count: hard limit of # records
 // (0 for either of these disables that threshold)
 //
-static constexpr nsecs_t kMaxRecordAgeNs =  28 * 3600 * (1000*1000*1000ll);
+static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * NANOS_PER_SECOND;
 // 2019/6: average daily per device is currently 375-ish;
 // setting this to 2000 is large enough to catch most devices
 // we'll lose some data on very very media-active devices, but only for
 // the gms collection; statsd will have already covered those for us.
 // This also retains enough information to help with bugreports
-static constexpr int kMaxRecords    = 2000;
+static constexpr size_t kMaxRecords = 2000;
 
 // max we expire in a single call, to constrain how long we hold the
 // mutex, which also constrains how long a client might wait.
-static constexpr int kMaxExpiredAtOnce = 50;
+static constexpr size_t kMaxExpiredAtOnce = 50;
 
 // TODO: need to look at tuning kMaxRecords and friends for low-memory devices
 
-static const char *kServiceName = "media.metrics";
-
-void MediaAnalyticsService::instantiate() {
-    defaultServiceManager()->addService(
-            String16(kServiceName), new MediaAnalyticsService());
-}
-
 MediaAnalyticsService::MediaAnalyticsService()
         : mMaxRecords(kMaxRecords),
           mMaxRecordAgeNs(kMaxRecordAgeNs),
           mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
-          mDumpProto(MediaAnalyticsItem::PROTO_V1),
-          mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
-
-    ALOGD("MediaAnalyticsService created");
-
-    mItemsSubmitted = 0;
-    mItemsFinalized = 0;
-    mItemsDiscarded = 0;
-    mItemsDiscardedExpire = 0;
-    mItemsDiscardedCount = 0;
-
-    mLastSessionID = 0;
-    // recover any persistency we set up
-    // etc
-}
-
-MediaAnalyticsService::~MediaAnalyticsService() {
-        ALOGD("MediaAnalyticsService destroyed");
-
-    while (mItems.size() > 0) {
-        MediaAnalyticsItem * oitem = *(mItems.begin());
-        mItems.erase(mItems.begin());
-        delete oitem;
-        mItemsDiscarded++;
-        mItemsDiscardedCount++;
-    }
-}
-
-
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
-    // generate a new sessionid
-
-    Mutex::Autolock _l(mLock_ids);
-    return (++mLastSessionID);
-}
-
-// caller surrenders ownership of 'item'
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
+          mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1)
 {
-    UNUSED(forcenew);
+    ALOGD("%s", __func__);
+}
 
-    // fill in a sessionID if we do not yet have one
-    if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
-        item->setSessionID(generateUniqueSessionID());
-    }
+MediaAnalyticsService::~MediaAnalyticsService()
+{
+    ALOGD("%s", __func__);
+    // the class destructor clears anyhow, but we enforce clearing items first.
+    mItemsDiscarded += mItems.size();
+    mItems.clear();
+}
 
+status_t MediaAnalyticsService::submitInternal(MediaAnalyticsItem *item, bool release)
+{
     // we control these, generally not trusting user input
     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
     // round nsecs to seconds
-    now = ((now + 500000000) / 1000000000) * 1000000000;
+    now = (now + NANOS_PER_SECOND / 2) / NANOS_PER_SECOND * NANOS_PER_SECOND;
+    // TODO: if we convert to boot time, do we need to round timestamp?
     item->setTimestamp(now);
-    int pid = IPCThreadState::self()->getCallingPid();
-    int uid = IPCThreadState::self()->getCallingUid();
 
-    int uid_given = item->getUid();
-    int pid_given = item->getPid();
+    const int pid = IPCThreadState::self()->getCallingPid();
+    const int uid = IPCThreadState::self()->getCallingUid();
+    const int uid_given = item->getUid();
+    const int pid_given = item->getPid();
 
-    // although we do make exceptions for some trusted client uids
-    bool isTrusted = false;
-
-    ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
-
-    switch (uid)  {
-        case AID_MEDIA:
-        case AID_MEDIA_CODEC:
-        case AID_MEDIA_EX:
-        case AID_MEDIA_DRM:
-            // trusted source, only override default values
-            isTrusted = true;
-            if (uid_given == (-1)) {
-                item->setUid(uid);
-            }
-            if (pid_given == (-1)) {
-                item->setPid(pid);
-            }
-            break;
-        default:
-            isTrusted = false;
-            item->setPid(pid);
+    ALOGV("%s: caller has uid=%d, embedded uid=%d", __func__, uid, uid_given);
+    bool isTrusted;
+    switch (uid) {
+    case AID_DRM:
+    case AID_MEDIA:
+    case AID_MEDIA_CODEC:
+    case AID_MEDIA_EX:
+    case AID_MEDIA_DRM:
+        // trusted source, only override default values
+        isTrusted = true;
+        if (uid_given == -1) {
             item->setUid(uid);
-            break;
+        }
+        if (pid_given == -1) {
+            item->setPid(pid);
+        }
+        break;
+    default:
+        isTrusted = false;
+        item->setPid(pid);
+        item->setUid(uid);
+        break;
     }
 
     // Overwrite package name and version if the caller was untrusted.
     if (!isTrusted) {
-      setPkgInfo(item, item->getUid(), true, true);
+        mUidInfo.setPkgInfo(item, item->getUid(), true, true);
     } else if (item->getPkgName().empty()) {
-      // empty, so fill out both parts
-      setPkgInfo(item, item->getUid(), true, true);
+        // empty, so fill out both parts
+        mUidInfo.setPkgInfo(item, item->getUid(), true, true);
     } else {
-      // trusted, provided a package, do nothing
+        // trusted, provided a package, do nothing
     }
 
-    ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
-          "sanitized pkg version: %"  PRId64,
+    ALOGV("%s: given uid %d; sanitized uid: %d sanitized pkg: %s "
+          "sanitized pkg version: %lld",
+          __func__,
           uid_given, item->getUid(),
           item->getPkgName().c_str(),
-          item->getPkgVersionCode());
+          (long long)item->getPkgVersionCode());
 
     mItemsSubmitted++;
 
     // validate the record; we discard if we don't like it
-    if (contentValid(item, isTrusted) == false) {
-        delete item;
-        return MediaAnalyticsItem::SessionIDInvalid;
+    if (isContentValid(item, isTrusted) == false) {
+        if (release) delete item;
+        return PERMISSION_DENIED;
     }
 
     // XXX: if we have a sessionid in the new record, look to make
     // sure it doesn't appear in the finalized list.
 
     if (item->count() == 0) {
-        ALOGV("dropping empty record...");
-        delete item;
-        item = NULL;
-        return MediaAnalyticsItem::SessionIDInvalid;
+        ALOGV("%s: dropping empty record...", __func__);
+        if (release) delete item;
+        return BAD_VALUE;
     }
 
-    // save the new record
-    //
-    // send a copy to statsd
-    dump2Statsd(item);
+    // send to statsd
+    extern bool dump2Statsd(MediaAnalyticsItem *item);  // extern hook
+    (void)dump2Statsd(item);  // failure should be logged in function.
 
-    // and keep our copy for dumpsys
-    MediaAnalyticsItem::SessionID_t id = item->getSessionID();
+    if (!release) item = item->dup();
     saveItem(item);
-    mItemsFinalized++;
-
-    return id;
+    return NO_ERROR;
 }
 
-
 status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
 {
-    const size_t SIZE = 512;
-    char buffer[SIZE];
     String8 result;
 
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: "
+        result.appendFormat("Permission Denial: "
                 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
-        result.append(buffer);
         write(fd, result.string(), result.size());
         return NO_ERROR;
     }
 
     // crack any parameters
-    String16 protoOption("-proto");
+    const String16 protoOption("-proto");
     int chosenProto = mDumpProtoDefault;
-    String16 clearOption("-clear");
+    const String16 clearOption("-clear");
     bool clear = false;
-    String16 sinceOption("-since");
+    const String16 sinceOption("-since");
     nsecs_t ts_since = 0;
-    String16 helpOption("-help");
-    String16 onlyOption("-only");
+    const String16 helpOption("-help");
+    const String16 onlyOption("-only");
     std::string only;
-    int n = args.size();
-
+    const int n = args.size();
     for (int i = 0; i < n; i++) {
-        String8 myarg(args[i]);
         if (args[i] == clearOption) {
             clear = true;
         } else if (args[i] == protoOption) {
@@ -304,7 +209,7 @@
                 ts_since = 0;
             }
             // command line is milliseconds; internal units are nano-seconds
-            ts_since *= 1000*1000;
+            ts_since *= NANOS_PER_MILLISECOND;
         } else if (args[i] == onlyOption) {
             i++;
             if (i < n) {
@@ -312,6 +217,10 @@
                 only = value.string();
             }
         } 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 #");
@@ -324,31 +233,18 @@
         }
     }
 
-    Mutex::Autolock _l(mLock);
-    // mutex between insertion and dumping the contents
+    {
+        std::lock_guard _l(mLock);
 
-    mDumpProto = chosenProto;
+        result.appendFormat("Dump of the %s process:\n", kServiceName);
+        dumpHeaders_l(result, chosenProto, ts_since);
+        dumpRecent_l(result, chosenProto, ts_since, only.c_str());
 
-    // we ALWAYS dump this piece
-    snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
-    result.append(buffer);
-
-    dumpHeaders(result, ts_since);
-
-    dumpRecent(result, ts_since, only.c_str());
-
-
-    if (clear) {
-        // remove everything from the finalized queue
-        while (mItems.size() > 0) {
-            MediaAnalyticsItem * oitem = *(mItems.begin());
-            mItems.erase(mItems.begin());
-            delete oitem;
-            mItemsDiscarded++;
+        if (clear) {
+            mItemsDiscarded += mItems.size();
+            mItems.clear();
+            // shall we clear the summary data too?
         }
-
-        // shall we clear the summary data too?
-
     }
 
     write(fd, result.string(), result.size());
@@ -356,275 +252,207 @@
 }
 
 // dump headers
-void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
+void MediaAnalyticsService::dumpHeaders_l(String8 &result, int dumpProto, nsecs_t ts_since)
 {
-    const size_t SIZE = 512;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
-    result.append(buffer);
-
-    int enabled = MediaAnalyticsItem::isEnabled();
-    if (enabled) {
-        snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
+    result.appendFormat("Protocol Version: %d\n", dumpProto);
+    if (MediaAnalyticsItem::isEnabled()) {
+        result.append("Metrics gathering: enabled\n");
     } else {
-        snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
+        result.append("Metrics gathering: DISABLED via property\n");
     }
-    result.append(buffer);
-
-    snprintf(buffer, SIZE,
-        "Since Boot: Submissions: %8" PRId64
-            " Accepted: %8" PRId64 "\n",
-        mItemsSubmitted, mItemsFinalized);
-    result.append(buffer);
-    snprintf(buffer, SIZE,
-        "Records Discarded: %8" PRId64
-            " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
-         mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
-    result.append(buffer);
+    result.appendFormat(
+            "Since Boot: Submissions: %lld Accepted: %lld\n",
+            (long long)mItemsSubmitted.load(), (long long)mItemsFinalized);
+    result.appendFormat(
+            "Records Discarded: %lld (by Count: %lld by Expiration: %lld)\n",
+            (long long)mItemsDiscarded, (long long)mItemsDiscardedCount,
+            (long long)mItemsDiscardedExpire);
     if (ts_since != 0) {
-        snprintf(buffer, SIZE,
-            "Emitting Queue entries more recent than: %" PRId64 "\n",
-            (int64_t) ts_since);
-        result.append(buffer);
+        result.appendFormat(
+            "Emitting Queue entries more recent than: %lld\n",
+            (long long)ts_since);
     }
 }
 
-// the recent, detailed queues
-void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
+void MediaAnalyticsService::dumpRecent_l(
+        String8 &result, int dumpProto, nsecs_t ts_since, const char * only)
 {
-    const size_t SIZE = 512;
-    char buffer[SIZE];
-
-    if (only != NULL && *only == '\0') {
-        only = NULL;
+    if (only != nullptr && *only == '\0') {
+        only = nullptr;
     }
-
-    // show the recently recorded records
-    snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
-    result.append(buffer);
-    result.append(this->dumpQueue(ts_since, only));
+    result.append("\nFinalized Metrics (oldest first):\n");
+    dumpQueue_l(result, dumpProto, 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
 }
 
-// caller has locked mLock...
-String8 MediaAnalyticsService::dumpQueue() {
-    return dumpQueue((nsecs_t) 0, NULL);
+void MediaAnalyticsService::dumpQueue_l(String8 &result, int dumpProto) {
+    dumpQueue_l(result, dumpProto, (nsecs_t) 0, nullptr /* only */);
 }
 
-String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
-    String8 result;
+void MediaAnalyticsService::dumpQueue_l(
+        String8 &result, int dumpProto, nsecs_t ts_since, const char * only) {
     int slot = 0;
 
     if (mItems.empty()) {
-            result.append("empty\n");
+        result.append("empty\n");
     } else {
-        List<MediaAnalyticsItem *>::iterator it = mItems.begin();
-        for (; it != mItems.end(); it++) {
-            nsecs_t when = (*it)->getTimestamp();
+        for (const auto &item : mItems) {
+            nsecs_t when = item->getTimestamp();
             if (when < ts_since) {
                 continue;
             }
-            if (only != NULL &&
-                strcmp(only, (*it)->getKey().c_str()) != 0) {
-                ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
+            // 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;
             }
-            std::string entry = (*it)->toString(mDumpProto);
-            result.appendFormat("%5d: %s\n", slot, entry.c_str());
+            result.appendFormat("%5d: %s\n",
+                   slot, item->toString(dumpProto).c_str());
             slot++;
         }
     }
-
-    return result;
 }
 
 //
 // Our Cheap in-core, non-persistent records management.
 
-
-// we hold mLock when we get here
 // if item != NULL, it's the item we just inserted
 // true == more items eligible to be recovered
 bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
 {
     bool more = false;
-    int handled = 0;
 
-    // keep removing old records the front until we're in-bounds (count)
-    // since we invoke this with each insertion, it should be 0/1 iterations.
-    if (mMaxRecords > 0) {
-        while (mItems.size() > (size_t) mMaxRecords) {
-            MediaAnalyticsItem * oitem = *(mItems.begin());
-            if (oitem == item) {
-                break;
-            }
-            if (handled >= mMaxRecordsExpiredAtOnce) {
-                // unlikely in this loop
-                more = true;
-                break;
-            }
-            handled++;
-            mItems.erase(mItems.begin());
-            delete oitem;
-            mItemsDiscarded++;
-            mItemsDiscardedCount++;
+    // check queue size
+    size_t overlimit = 0;
+    if (mMaxRecords > 0 && mItems.size() > mMaxRecords) {
+        overlimit = mItems.size() - mMaxRecords;
+        if (overlimit > mMaxRecordsExpiredAtOnce) {
+            more = true;
+            overlimit = mMaxRecordsExpiredAtOnce;
         }
     }
 
-    // keep removing old records the front until we're in-bounds (age)
-    // limited to mMaxRecordsExpiredAtOnce items per invocation.
-    if (mMaxRecordAgeNs > 0) {
-        nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
-        while (mItems.size() > 0) {
-            MediaAnalyticsItem * oitem = *(mItems.begin());
+    // check queue times
+    size_t expired = 0;
+    if (!more && mMaxRecordAgeNs > 0) {
+        const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+        // we check one at a time, skip search would be more efficient.
+        size_t i = overlimit;
+        for (; i < mItems.size(); ++i) {
+            auto &oitem = mItems[i];
             nsecs_t when = oitem->getTimestamp();
-            if (oitem == item) {
+            if (oitem.get() == item) {
                 break;
             }
-            // careful about timejumps too
-            if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
-                // this (and the rest) are recent enough to keep
-                break;
+            if (now > when && (now - when) <= mMaxRecordAgeNs) {
+                break;  // TODO: if we use BOOTTIME, should be monotonic.
             }
-            if (handled >= mMaxRecordsExpiredAtOnce) {
+            if (i >= mMaxRecordsExpiredAtOnce) {
                 // this represents "one too many"; tell caller there are
                 // more to be reclaimed.
                 more = true;
                 break;
             }
-            handled++;
-            mItems.erase(mItems.begin());
-            delete oitem;
-            mItemsDiscarded++;
-            mItemsDiscardedExpire++;
         }
+        expired = i - overlimit;
     }
 
-    // we only indicate whether there's more to clean;
-    // caller chooses whether to schedule further cleanup.
+    if (const size_t toErase = overlimit + expired;
+            toErase > 0) {
+        mItemsDiscardedCount += overlimit;
+        mItemsDiscardedExpire += expired;
+        mItemsDiscarded += toErase;
+        mItems.erase(mItems.begin(), mItems.begin() + toErase); // erase from front
+    }
     return more;
 }
 
-// process expirations in bite sized chunks, allowing new insertions through
-// runs in a pthread specifically started for this (which then exits)
-bool MediaAnalyticsService::processExpirations()
+void MediaAnalyticsService::processExpirations()
 {
     bool more;
     do {
         sleep(1);
-        {
-            Mutex::Autolock _l(mLock);
-            more = expirations_l(NULL);
-            if (!more) {
-                break;
-            }
-        }
+        std::lock_guard _l(mLock);
+        more = expirations_l(nullptr);
     } while (more);
-    return true;        // value is for std::future thread synchronization
 }
 
-// insert appropriately into queue
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+void MediaAnalyticsService::saveItem(MediaAnalyticsItem *item)
 {
-
-    Mutex::Autolock _l(mLock);
-    // mutex between insertion and dumping the contents
-
-    // we want to dump 'in FIFO order', so insert at the end
-    mItems.push_back(item);
-
-    // clean old stuff from the queue
-    bool more = expirations_l(item);
-
-    // consider scheduling some asynchronous cleaning, if not running
-    if (more) {
-        if (!mExpireFuture.valid()
-            || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
-
-            mExpireFuture = std::async(std::launch::async, [this]()
-                                       {return this->processExpirations();});
-        }
+    std::lock_guard _l(mLock);
+    // we assume the items are roughly in time order.
+    mItems.emplace_back(item);
+    ++mItemsFinalized;
+    if (expirations_l(item)
+            && (!mExpireFuture.valid()
+               || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)) {
+        mExpireFuture = std::async(std::launch::async, [this] { processExpirations(); });
     }
 }
 
-static std::string allowedKeys[] =
+/* static */
+bool MediaAnalyticsService::isContentValid(const MediaAnalyticsItem *item, bool isTrusted)
 {
-    "audiopolicy",
-    "audiorecord",
-    "audiothread",
-    "audiotrack",
-    "codec",
-    "extractor",
-    "nuplayer",
-};
-
-static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
-
-// are the contents good
-bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
-
+    if (isTrusted) return true;
     // untrusted uids can only send us a limited set of keys
-    if (isTrusted == false) {
-        // restrict to a specific set of keys
-        std::string key = item->getKey();
-
-        size_t i;
-        for(i = 0; i < nAllowedKeys; i++) {
-            if (key == allowedKeys[i]) {
-                break;
-            }
-        }
-        if (i == nAllowedKeys) {
-            ALOGD("Ignoring (key): %s", item->toString().c_str());
-            return false;
+    const std::string &key = item->getKey();
+    for (const char *allowedKey : {
+                                     "audiopolicy",
+                                     "audiorecord",
+                                     "audiothread",
+                                     "audiotrack",
+                                     "codec",
+                                     "extractor",
+                                     "nuplayer",
+                                 }) {
+        if (key == allowedKey) {
+            return true;
         }
     }
-
-    // internal consistency
-
-    return true;
-}
-
-// are we rate limited, normally false
-bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
-
+    ALOGD("%s: invalid key: %s", __func__, item->toString().c_str());
     return false;
 }
 
-// how long we hold package info before we re-fetch it
-#define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
+// are we rate limited, normally false
+bool MediaAnalyticsService::isRateLimited(MediaAnalyticsItem *) const
+{
+    return false;
+}
+
+// How long we hold package info before we re-fetch it
+constexpr nsecs_t PKG_EXPIRATION_NS = 30 * 60 * NANOS_PER_SECOND; // 30 minutes
 
 // give me the package name, perhaps going to find it
 // manages its own mutex operations internally
-void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
+void MediaAnalyticsService::UidInfo::setPkgInfo(
+        MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
 {
-    ALOGV("asking for packagename to go with uid=%d", uid);
+    ALOGV("%s: uid=%d", __func__, uid);
 
     if (!setName && !setVersion) {
-        // setting nothing? strange
-        return;
+        return;  // setting nothing? strange
     }
 
-    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
-    struct UidToPkgMap mapping;
-    mapping.uid = (uid_t)(-1);
-
+    const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    struct UidToPkgInfo mapping;
     {
-        Mutex::Autolock _l(mLock_mappings);
-        int i = mPkgMappings.indexOfKey(uid);
-        if (i >= 0) {
-            mapping = mPkgMappings.valueAt(i);
-            ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
-                  uid, mapping.expiration, now);
+        std::lock_guard _l(mUidInfoLock);
+        auto it = mPkgMappings.find(uid);
+        if (it != mPkgMappings.end()) {
+            mapping = it->second;
+            ALOGV("%s: uid %d expiration %lld now %lld",
+                    __func__, uid, (long long)mapping.expiration, (long long)now);
             if (mapping.expiration <= now) {
                 // purge the stale entry and fall into re-fetching
-                ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
-                mPkgMappings.removeItemsAt(i);
-                mapping.uid = (uid_t)(-1);
+                ALOGV("%s: entry for uid %d expired, now %lld",
+                        __func__, uid, (long long)now);
+                mPkgMappings.erase(it);
+                mapping.uid = (uid_t)-1;  // this is always fully overwritten
             }
         }
     }
@@ -632,115 +460,103 @@
     // if we did not find it
     if (mapping.uid == (uid_t)(-1)) {
         std::string pkg;
-        std::string installer = "";
+        std::string installer;
         int64_t versionCode = 0;
 
-        struct passwd *pw = getpwuid(uid);
+        const struct passwd *pw = getpwuid(uid);
         if (pw) {
             pkg = pw->pw_name;
         }
 
-        // find the proper value
-
-        sp<IBinder> binder = NULL;
         sp<IServiceManager> sm = defaultServiceManager();
-        if (sm == NULL) {
-            ALOGE("defaultServiceManager failed");
+        sp<content::pm::IPackageManagerNative> package_mgr;
+        if (sm.get() == nullptr) {
+            ALOGE("%s: Cannot find service manager", __func__);
         } else {
-            binder = sm->getService(String16("package_native"));
-            if (binder == NULL) {
-                ALOGE("getService package_native failed");
+            sp<IBinder> binder = sm->getService(String16("package_native"));
+            if (binder.get() == nullptr) {
+                ALOGE("%s: Cannot find package_native", __func__);
+            } else {
+                package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder);
             }
         }
 
-        if (binder != NULL) {
-            sp<content::pm::IPackageManagerNative> package_mgr =
-                            interface_cast<content::pm::IPackageManagerNative>(binder);
-            binder::Status status;
-
+        if (package_mgr != nullptr) {
             std::vector<int> uids;
             std::vector<std::string> names;
-
             uids.push_back(uid);
-
-            status = package_mgr->getNamesForUids(uids, &names);
+            binder::Status status = package_mgr->getNamesForUids(uids, &names);
             if (!status.isOk()) {
-                ALOGE("package_native::getNamesForUids failed: %s",
-                      status.exceptionMessage().c_str());
-            } else {
-                if (!names[0].empty()) {
-                    pkg = names[0].c_str();
-                }
+                ALOGE("%s: getNamesForUids failed: %s",
+                        __func__, status.exceptionMessage().c_str());
+            }
+            if (!names[0].empty()) {
+                pkg = names[0].c_str();
+            }
+        }
+
+        // strip any leading "shared:" strings that came back
+        if (pkg.compare(0, 7, "shared:") == 0) {
+            pkg.erase(0, 7);
+        }
+        // determine how pkg was installed and the versionCode
+        if (pkg.empty()) {
+            pkg = std::to_string(uid); // no name for us to manage
+        } else if (strchr(pkg.c_str(), '.') == NULL) {
+            // not of form 'com.whatever...'; assume internal and ok
+        } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
+            // android.* packages are assumed fine
+        } else if (package_mgr.get() != nullptr) {
+            String16 pkgName16(pkg.c_str());
+            binder::Status status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+            if (!status.isOk()) {
+                ALOGE("%s: getInstallerForPackage failed: %s",
+                        __func__, status.exceptionMessage().c_str());
             }
 
-            // strip any leading "shared:" strings that came back
-            if (pkg.compare(0, 7, "shared:") == 0) {
-                pkg.erase(0, 7);
-            }
-
-            // determine how pkg was installed and the versionCode
-            //
-            if (pkg.empty()) {
-                // no name for us to manage
-            } else if (strchr(pkg.c_str(), '.') == NULL) {
-                // not of form 'com.whatever...'; assume internal and ok
-            } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
-                // android.* packages are assumed fine
-            } else {
-                String16 pkgName16(pkg.c_str());
-                status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+            // skip if we didn't get an installer
+            if (status.isOk()) {
+                status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
                 if (!status.isOk()) {
-                    ALOGE("package_native::getInstallerForPackage failed: %s",
-                          status.exceptionMessage().c_str());
-                }
-
-                // skip if we didn't get an installer
-                if (status.isOk()) {
-                    status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
-                    if (!status.isOk()) {
-                        ALOGE("package_native::getVersionCodeForPackage failed: %s",
-                          status.exceptionMessage().c_str());
-                    }
-                }
-
-
-                ALOGV("package '%s' installed by '%s' versioncode %"  PRId64 " / %" PRIx64,
-                      pkg.c_str(), installer.c_str(), versionCode, versionCode);
-
-                if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
-                        // from play store, we keep info
-                } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
-                        // some google source, we keep info
-                } else if (strcmp(installer.c_str(), "preload") == 0) {
-                        // preloads, we keep the info
-                } else if (installer.c_str()[0] == '\0') {
-                        // sideload (no installer); do not report
-                        pkg = "";
-                        versionCode = 0;
-                } else {
-                        // unknown installer; do not report
-                        pkg = "";
-                        versionCode = 0;
+                    ALOGE("%s: getVersionCodeForPackage failed: %s",
+                            __func__, status.exceptionMessage().c_str());
                 }
             }
+
+            ALOGV("%s: package '%s' installed by '%s' versioncode %lld",
+                    __func__, pkg.c_str(), installer.c_str(), (long long)versionCode);
+
+            if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+                // from play store, we keep info
+            } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+                // some google source, we keep info
+            } else if (strcmp(installer.c_str(), "preload") == 0) {
+                // preloads, we keep the info
+            } else if (installer.c_str()[0] == '\0') {
+                // sideload (no installer); report UID only
+                pkg = std::to_string(uid);
+                versionCode = 0;
+            } else {
+                // unknown installer; report UID only
+                pkg = std::to_string(uid);
+                versionCode = 0;
+            }
+        } else {
+            // unvalidated by package_mgr just send uid.
+            pkg = std::to_string(uid);
         }
 
         // add it to the map, to save a subsequent lookup
-        if (!pkg.empty()) {
-            Mutex::Autolock _l(mLock_mappings);
-            ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
-            ssize_t i = mPkgMappings.indexOfKey(uid);
-            if (i < 0) {
-                mapping.uid = uid;
-                mapping.pkg = pkg;
-                mapping.installer = installer.c_str();
-                mapping.versionCode = versionCode;
-                mapping.expiration = now + PKG_EXPIRATION_NS;
-                ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
-
-                mPkgMappings.add(uid, mapping);
-            }
-        }
+        std::lock_guard _l(mUidInfoLock);
+        // always overwrite
+        mapping.uid = uid;
+        mapping.pkg = std::move(pkg);
+        mapping.installer = std::move(installer);
+        mapping.versionCode = versionCode;
+        mapping.expiration = now + PKG_EXPIRATION_NS;
+        ALOGV("%s: adding uid %d pkg '%s' expiration: %lld",
+                __func__, uid, mapping.pkg.c_str(), (long long)mapping.expiration);
+        mPkgMappings[uid] = mapping;
     }
 
     if (mapping.uid != (uid_t)(-1)) {
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 6c9cbaa..eb7d725 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -14,109 +14,110 @@
  * limitations under the License.
  */
 
+#pragma once
 
-#ifndef ANDROID_MEDIAANALYTICSSERVICE_H
-#define ANDROID_MEDIAANALYTICSSERVICE_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/List.h>
-
+#include <atomic>
+#include <deque>
 #include <future>
+#include <mutex>
+#include <unordered_map>
 
+// IMediaAnalyticsService must include Vector, String16, Errors
 #include <media/IMediaAnalyticsService.h>
+#include <utils/String8.h>
 
 namespace android {
 
 class MediaAnalyticsService : public BnMediaAnalyticsService
 {
+public:
+    MediaAnalyticsService();
+    ~MediaAnalyticsService() override;
 
- public:
+    /**
+     * Submits the indicated record to the mediaanalytics service.
+     *
+     * \param item the item to submit.
+     * \return status failure, which is negative on binder transaction failure.
+     *         As the transaction is one-way, remote failures will not be reported.
+     */
+    status_t submit(MediaAnalyticsItem *item) override {
+        return submitInternal(item, false /* release */);
+    }
 
-    // on this side, caller surrenders ownership
-    virtual int64_t submit(MediaAnalyticsItem *item, bool forcenew);
+    status_t dump(int fd, const Vector<String16>& args) override;
 
-    static  void            instantiate();
-    virtual status_t        dump(int fd, const Vector<String16>& args);
+    static constexpr const char * const kServiceName = "media.metrics";
 
-                            MediaAnalyticsService();
-    virtual                 ~MediaAnalyticsService();
+protected:
 
-    bool processExpirations();
+    // Internal call where release is true if ownership of item is transferred
+    // to the service (that is, the service will eventually delete the item).
+    status_t submitInternal(MediaAnalyticsItem *item, bool release) override;
 
- private:
-    MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
+private:
+    void processExpirations();
+    // input validation after arrival from client
+    static bool isContentValid(const MediaAnalyticsItem *item, bool isTrusted);
+    bool isRateLimited(MediaAnalyticsItem *) const;
+    void saveItem(MediaAnalyticsItem *);
 
-    // statistics about our analytics
-    int64_t mItemsSubmitted;
-    int64_t mItemsFinalized;
-    int64_t mItemsDiscarded;
-    int64_t mItemsDiscardedExpire;
-    int64_t mItemsDiscardedCount;
-    MediaAnalyticsItem::SessionID_t mLastSessionID;
+    // The following methods are GUARDED_BY(mLock)
+    bool expirations_l(MediaAnalyticsItem *);
 
-    // partitioned a bit so we don't over serialize
-    mutable Mutex           mLock;
-    mutable Mutex           mLock_ids;
-    mutable Mutex           mLock_mappings;
+    // support for generating output
+    void dumpQueue_l(String8 &result, int dumpProto);
+    void dumpQueue_l(String8 &result, int dumpProto, nsecs_t, const char *only);
+    void dumpHeaders_l(String8 &result, int dumpProto, nsecs_t ts_since);
+    void dumpSummaries_l(String8 &result, int dumpProto, nsecs_t ts_since, const char * only);
+    void dumpRecent_l(String8 &result, int dumpProto, nsecs_t ts_since, const char * only);
+
+    // The following variables accessed without mLock
 
     // limit how many records we'll retain
     // by count (in each queue (open, finalized))
-    int32_t mMaxRecords;
-    // by time (none older than this long agan
-    nsecs_t mMaxRecordAgeNs;
+    const size_t mMaxRecords;
+    // by time (none older than this)
+    const nsecs_t mMaxRecordAgeNs;
     // max to expire per expirations_l() invocation
-    int32_t mMaxRecordsExpiredAtOnce;
-    //
-    // # of sets of summaries
-    int32_t mMaxRecordSets;
-    // nsecs until we start a new record set
-    nsecs_t mNewSetInterval;
+    const size_t mMaxRecordsExpiredAtOnce;
+    const int mDumpProtoDefault;
 
-    // input validation after arrival from client
-    bool contentValid(MediaAnalyticsItem *item, bool isTrusted);
-    bool rateLimited(MediaAnalyticsItem *);
+    class UidInfo {
+    public:
+        void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
 
-    // (oldest at front) so it prints nicely for dumpsys
-    List<MediaAnalyticsItem *> mItems;
-    void saveItem(MediaAnalyticsItem *);
+    private:
+        std::mutex mUidInfoLock;
 
-    bool expirations_l(MediaAnalyticsItem *);
-    std::future<bool> mExpireFuture;
+        struct UidToPkgInfo {
+            uid_t uid = -1;
+            std::string pkg;
+            std::string installer;
+            int64_t versionCode = 0;
+            nsecs_t expiration = 0;  // TODO: remove expiration.
+        };
 
-    // support for generating output
-    int mDumpProto;
-    int mDumpProtoDefault;
-    String8 dumpQueue();
-    String8 dumpQueue(nsecs_t, const char *only);
+        // TODO: use concurrent hashmap with striped lock.
+        std::unordered_map<uid_t, struct UidToPkgInfo> mPkgMappings; // GUARDED_BY(mUidInfoLock)
+    } mUidInfo;  // mUidInfo can be accessed without lock (locked internally)
 
-    void dumpHeaders(String8 &result, nsecs_t ts_since);
-    void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
-    void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);
+    std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
 
-    // mapping uids to package names
-    struct UidToPkgMap {
-        uid_t uid;
-        std::string pkg;
-        std::string installer;
-        int64_t versionCode;
-        nsecs_t expiration;
-    };
+    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)
 
-    KeyedVector<uid_t,struct UidToPkgMap>  mPkgMappings;
-    void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
+    // If we have a worker thread to garbage collect
+    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 MediaAnalyticsItem>> mItems; // GUARDED_BY(mLock)
 };
 
-// hook to send things off to the statsd subsystem
-extern bool dump2Statsd(MediaAnalyticsItem *item);
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAANALYTICSSERVICE_H
+} // namespace android
diff --git a/services/mediaanalytics/OWNERS b/services/mediaanalytics/OWNERS
index 9af258b..e37a1f8 100644
--- a/services/mediaanalytics/OWNERS
+++ b/services/mediaanalytics/OWNERS
@@ -1 +1,2 @@
 essick@google.com
+hunga@google.com
diff --git a/services/mediaanalytics/TEST_MAPPING b/services/mediaanalytics/TEST_MAPPING
new file mode 100644
index 0000000..01e9e46
--- /dev/null
+++ b/services/mediaanalytics/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+       "name": "mediametrics_tests"
+    },
+    {
+       "name": "CtsNativeMediaMetricsTestCases"
+    }
+  ]
+}
diff --git a/services/mediaanalytics/iface_statsd.cpp b/services/mediaanalytics/iface_statsd.cpp
index 6845f06..e02c9cf 100644
--- a/services/mediaanalytics/iface_statsd.cpp
+++ b/services/mediaanalytics/iface_statsd.cpp
@@ -52,7 +52,7 @@
 };
 
 // keep this sorted, so we can do binary searches
-struct statsd_hooks  statsd_handlers[] =
+static constexpr struct statsd_hooks statsd_handlers[] =
 {
     { "audiopolicy", statsd_audiopolicy },
     { "audiorecord", statsd_audiorecord },
@@ -60,6 +60,7 @@
     { "audiotrack", statsd_audiotrack },
     { "codec", statsd_codec},
     { "drm.vendor.Google.WidevineCDM", statsd_widevineCDM },
+    { "drmmanager", statsd_drmmanager },
     { "extractor", statsd_extractor },
     { "mediadrm", statsd_mediadrm },
     { "nuplayer", statsd_nuplayer },
@@ -67,7 +68,6 @@
     { "recorder", statsd_recorder },
 };
 
-
 // give me a record, i'll look at the type and upload appropriately
 bool dump2Statsd(MediaAnalyticsItem *item) {
     if (item == NULL) return false;
@@ -80,10 +80,9 @@
         return false;
     }
 
-    int i;
-    for(i = 0;i < sizeof(statsd_handlers) / sizeof(statsd_handlers[0]) ; i++) {
-        if (key == statsd_handlers[i].key) {
-            return (*statsd_handlers[i].handler)(item);
+    for (const auto &statsd_handler : statsd_handlers) {
+        if (key == statsd_handler.key) {
+            return statsd_handler.handler(item);
         }
     }
     return false;
diff --git a/services/mediaanalytics/iface_statsd.h b/services/mediaanalytics/iface_statsd.h
index f85d303..014929b 100644
--- a/services/mediaanalytics/iface_statsd.h
+++ b/services/mediaanalytics/iface_statsd.h
@@ -30,5 +30,6 @@
 
 extern bool statsd_mediadrm(MediaAnalyticsItem *);
 extern bool statsd_widevineCDM(MediaAnalyticsItem *);
+extern bool statsd_drmmanager(MediaAnalyticsItem *);
 
 } // namespace android
diff --git a/services/mediaanalytics/main_mediametrics.cpp b/services/mediaanalytics/main_mediametrics.cpp
index 8020a03..6833fe2 100644
--- a/services/mediaanalytics/main_mediametrics.cpp
+++ b/services/mediaanalytics/main_mediametrics.cpp
@@ -16,33 +16,33 @@
 
 #define LOG_TAG "mediametrics"
 //#define LOG_NDEBUG 0
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
 #include <utils/Log.h>
-//#include "RegisterExtensions.h"
 
-// from LOCAL_C_INCLUDES
 #include "MediaAnalyticsService.h"
 
-using namespace android;
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
 
 int main(int argc __unused, char **argv __unused)
 {
+    using namespace android;
+
     signal(SIGPIPE, SIG_IGN);
 
     // to match the service name
     // we're replacing "/system/bin/mediametrics" with "media.metrics"
     // we add a ".", but discard the path components: we finish with a shorter string
-    strcpy(argv[0], "media.metrics");
+    strcpy(argv[0], MediaAnalyticsService::kServiceName);
 
-    sp<ProcessState> proc(ProcessState::self());
-    sp<IServiceManager> sm(defaultServiceManager());
-    ALOGI("ServiceManager: %p", sm.get());
+    defaultServiceManager()->addService(
+            String16(MediaAnalyticsService::kServiceName), new MediaAnalyticsService());
 
-    MediaAnalyticsService::instantiate();
-
-    ProcessState::self()->startThreadPool();
+    sp<ProcessState> processState(ProcessState::self());
+    // processState->setThreadPoolMaxThreadCount(8);
+    processState->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
+
+    return EXIT_SUCCESS;
 }
diff --git a/services/mediaanalytics/statsd_drm.cpp b/services/mediaanalytics/statsd_drm.cpp
index 902483a..845383d 100644
--- a/services/mediaanalytics/statsd_drm.cpp
+++ b/services/mediaanalytics/statsd_drm.cpp
@@ -104,4 +104,38 @@
     return true;
 }
 
+// drmmanager
+bool statsd_drmmanager(MediaAnalyticsItem *item)
+{
+    if (item == NULL) return false;
+
+    nsecs_t timestamp = item->getTimestamp();
+    std::string pkgName = item->getPkgName();
+    int64_t pkgVersionCode = item->getPkgVersionCode();
+    int64_t mediaApexVersion = 0;
+
+    char *plugin_id = NULL;
+    (void) item->getCString("plugin_id", &plugin_id);
+    char *description = NULL;
+    (void) item->getCString("description", &description);
+    int32_t method_id = -1;
+    (void) item->getInt32("method_id", &method_id);
+    char *mime_types = NULL;
+    (void) item->getCString("mime_types", &mime_types);
+
+    if (enabled_statsd) {
+        android::util::stats_write(android::util::MEDIAMETRICS_DRMMANAGER_REPORTED,
+                                   timestamp, pkgName.c_str(), pkgVersionCode,
+                                   mediaApexVersion,
+                                   plugin_id, description,
+                                   method_id, mime_types);
+    } else {
+        ALOGV("NOT sending: drmmanager data");
+    }
+
+    free(plugin_id);
+    free(description);
+    free(mime_types);
+    return true;
+}
 } // namespace android
diff --git a/services/mediaanalytics/tests/Android.bp b/services/mediaanalytics/tests/Android.bp
new file mode 100644
index 0000000..a8a330c
--- /dev/null
+++ b/services/mediaanalytics/tests/Android.bp
@@ -0,0 +1,26 @@
+cc_test {
+    name: "mediametrics_tests",
+    test_suites: ["device-tests"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+
+    include_dirs: [
+        "frameworks/av/services/mediaanalytics",
+    ],
+
+    shared_libs: [
+        "libbinder",
+        "liblog",
+        "libmediaanalyticsservice",
+        "libmediametrics",
+        "libutils",
+    ],
+
+    srcs: [
+        "mediametrics_tests.cpp",
+    ],
+}
diff --git a/services/mediaanalytics/tests/build_and_run_all_unit_tests.sh b/services/mediaanalytics/tests/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..2511c30
--- /dev/null
+++ b/services/mediaanalytics/tests/build_and_run_all_unit_tests.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    echo "Android build environment not set"
+    exit -1
+fi
+
+# ensure we have mm
+. $ANDROID_BUILD_TOP/build/envsetup.sh
+
+mm
+
+echo "waiting for device"
+
+adb root && adb wait-for-device remount
+
+echo "========================================"
+
+echo "testing mediametrics"
+adb push $OUT/data/nativetest/mediametrics_tests/mediametrics_tests /system/bin
+adb shell /system/bin/mediametrics_tests
diff --git a/services/mediaanalytics/tests/mediametrics_tests.cpp b/services/mediaanalytics/tests/mediametrics_tests.cpp
new file mode 100644
index 0000000..09ca114
--- /dev/null
+++ b/services/mediaanalytics/tests/mediametrics_tests.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "mediametrics_tests"
+#include <utils/Log.h>
+
+#include "MediaAnalyticsService.h"
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+#include <media/MediaAnalyticsItem.h>
+
+using namespace android;
+
+TEST(mediametrics_tests, instantiate) {
+  sp mediaMetrics = new MediaAnalyticsService();
+  status_t status;
+
+  // random keys ignored when empty
+  std::unique_ptr<MediaAnalyticsItem> random_key(MediaAnalyticsItem::create("random_key"));
+  status = mediaMetrics->submit(random_key.get());
+  ASSERT_EQ(PERMISSION_DENIED, status);
+
+  // random keys ignored with data
+  random_key->setInt32("foo", 10);
+  status = mediaMetrics->submit(random_key.get());
+  ASSERT_EQ(PERMISSION_DENIED, status);
+
+  // known keys ignored if empty
+  std::unique_ptr<MediaAnalyticsItem> audiotrack_key(MediaAnalyticsItem::create("audiotrack"));
+  status = mediaMetrics->submit(audiotrack_key.get());
+  ASSERT_EQ(BAD_VALUE, status);
+
+  // known keys not ignored if not empty
+  audiotrack_key->addInt32("foo", 10);
+  status = mediaMetrics->submit(audiotrack_key.get());
+  ASSERT_EQ(NO_ERROR, status);
+
+
+  /*
+  // fluent style that goes directly to mediametrics
+  ASSERT_EQ(true, MediaAnalyticsItem("audiorecord")
+                     .setInt32("value", 2)
+                     .addInt32("bar", 1)
+                     .addInt32("value", 3)
+                     .selfrecord());
+  */
+
+  mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+
+TEST(mediametrics_tests, item_manipulation) {
+  MediaAnalyticsItem item("audiorecord");
+
+  item.setInt32("value", 2).addInt32("bar", 3).addInt32("value", 4);
+
+  int32_t i32;
+  ASSERT_TRUE(item.getInt32("value", &i32));
+  ASSERT_EQ(6, i32);
+
+  ASSERT_TRUE(item.getInt32("bar", &i32));
+  ASSERT_EQ(3, i32);
+
+  item.setInt64("big", INT64_MAX).setInt64("smaller", INT64_MAX - 1).addInt64("smaller", -2);
+
+  int64_t i64;
+  ASSERT_TRUE(item.getInt64("big", &i64));
+  ASSERT_EQ(INT64_MAX, i64);
+
+  ASSERT_TRUE(item.getInt64("smaller", &i64));
+  ASSERT_EQ(INT64_MAX - 3, i64);
+
+  item.setDouble("precise", 10.5).setDouble("small", 0.125).addDouble("precise", 0.25);
+
+  double d;
+  ASSERT_TRUE(item.getDouble("precise", &d));
+  ASSERT_EQ(10.75, d);
+
+  ASSERT_TRUE(item.getDouble("small", &d));
+  ASSERT_EQ(0.125, d);
+
+  char *s;
+  item.setCString("name", "Frank").setCString("mother", "June").setCString("mother", "July");
+  ASSERT_TRUE(item.getCString("name", &s));
+  ASSERT_EQ(0, strcmp(s, "Frank"));
+  free(s);
+
+  ASSERT_TRUE(item.getCString("mother", &s));
+  ASSERT_EQ(0, strcmp(s, "July"));  // "July" overwrites "June"
+  free(s);
+
+  item.setRate("burgersPerHour", 5, 2);
+  int64_t b, h;
+  ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
+  ASSERT_EQ(5, b);
+  ASSERT_EQ(2, h);
+  ASSERT_EQ(2.5, d);
+
+  item.addRate("burgersPerHour", 4, 2);
+  ASSERT_TRUE(item.getRate("burgersPerHour", &b, &h, &d));
+  ASSERT_EQ(9, b);
+  ASSERT_EQ(4, h);
+  ASSERT_EQ(2.25, d);
+
+  printf("item: %s\n", item.toString().c_str());
+  fflush(stdout);
+
+  sp mediaMetrics = new MediaAnalyticsService();
+  status_t status = mediaMetrics->submit(&item);
+  ASSERT_EQ(NO_ERROR, status);
+  mediaMetrics->dump(fileno(stdout), {} /* args */);
+}
+
+TEST(mediametrics_tests, superbig_item) {
+  MediaAnalyticsItem item("TheBigOne");
+  constexpr size_t count = 10000;
+
+  for (size_t i = 0; i < count; ++i) {
+    item.setInt32(std::to_string(i).c_str(), i);
+  }
+  for (size_t i = 0; i < count; ++i) {
+    int32_t i32;
+    ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+    ASSERT_EQ((int32_t)i, i32);
+  }
+}
+
+TEST(mediametrics_tests, superbig_item_removal) {
+  MediaAnalyticsItem item("TheOddBigOne");
+  constexpr size_t count = 10000;
+
+  for (size_t i = 0; i < count; ++i) {
+    item.setInt32(std::to_string(i).c_str(), i);
+  }
+  for (size_t i = 0; i < count; i += 2) {
+    item.filter(std::to_string(i).c_str()); // filter out all the evens.
+  }
+  for (size_t i = 0; i < count; ++i) {
+    int32_t i32;
+    if (i & 1) { // check to see that only the odds are left.
+        ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+        ASSERT_EQ((int32_t)i, i32);
+    } else {
+        ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
+    }
+  }
+}
+
+TEST(mediametrics_tests, superbig_item_removal2) {
+  MediaAnalyticsItem item("TheOne");
+  constexpr size_t count = 10000;
+
+  for (size_t i = 0; i < count; ++i) {
+    item.setInt32(std::to_string(i).c_str(), i);
+  }
+  static const char *attrs[] = { "1", };
+  item.filterNot(1, attrs);
+
+  for (size_t i = 0; i < count; ++i) {
+    int32_t i32;
+    if (i == 1) { // check to see that there is only one
+        ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+        ASSERT_EQ((int32_t)i, i32);
+    } else {
+        ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
+    }
+  }
+}
+
+TEST(mediametrics_tests, item_transmutation) {
+  MediaAnalyticsItem item("Alchemist's Stone");
+
+  item.setInt64("convert", 123);
+  int64_t i64;
+  ASSERT_TRUE(item.getInt64("convert", &i64));
+  ASSERT_EQ(123, i64);
+
+  item.addInt32("convert", 2);     // changes type of 'convert' from i64 to i32 (and re-init).
+  ASSERT_FALSE(item.getInt64("convert", &i64));  // should be false, no value in i64.
+
+  int32_t i32;
+  ASSERT_TRUE(item.getInt32("convert", &i32));   // check it is i32 and 2 (123 is discarded).
+  ASSERT_EQ(2, i32);
+}
+
+TEST(mediametrics_tests, item_binderization) {
+  MediaAnalyticsItem item;
+  item.setInt32("i32", 1)
+      .setInt64("i64", 2)
+      .setDouble("double", 3.1)
+      .setCString("string", "abc")
+      .setRate("rate", 11, 12);
+
+  Parcel p;
+  item.writeToParcel(&p);
+
+  p.setDataPosition(0); // rewind for reading
+  MediaAnalyticsItem item2;
+  item2.readFromParcel(p);
+
+  ASSERT_EQ(item, item2);
+}
+
+TEST(mediametrics_tests, item_byteserialization) {
+  MediaAnalyticsItem item;
+  item.setInt32("i32", 1)
+      .setInt64("i64", 2)
+      .setDouble("double", 3.1)
+      .setCString("string", "abc")
+      .setRate("rate", 11, 12);
+
+  char *data;
+  size_t length;
+  ASSERT_EQ(0, item.writeToByteString(&data, &length));
+  ASSERT_GT(length, (size_t)0);
+
+  MediaAnalyticsItem item2;
+  item2.readFromByteString(data, length);
+
+  printf("item: %s\n", item.toString().c_str());
+  printf("item2: %s\n", item2.toString().c_str());
+  ASSERT_EQ(item, item2);
+
+  free(data);
+}
+
+TEST(mediametrics_tests, item_iteration) {
+  MediaAnalyticsItem item;
+  item.setInt32("i32", 1)
+      .setInt64("i64", 2)
+      .setDouble("double", 3.125)
+      .setCString("string", "abc")
+      .setRate("rate", 11, 12);
+
+  int mask = 0;
+  for (auto &prop : item) {
+      const char *name = prop.getName();
+      if (!strcmp(name, "i32")) {
+          int32_t i32;
+          ASSERT_TRUE(prop.get(&i32));
+          ASSERT_EQ(1, i32);
+          mask |= 1;
+      } else if (!strcmp(name, "i64")) {
+          int64_t i64;
+          ASSERT_TRUE(prop.get(&i64));
+          ASSERT_EQ(2, i64);
+          mask |= 2;
+      } else if (!strcmp(name, "double")) {
+          double d;
+          ASSERT_TRUE(prop.get(&d));
+          ASSERT_EQ(3.125, d);
+          mask |= 4;
+      } else if (!strcmp(name, "string")) {
+          const char *s;
+          ASSERT_TRUE(prop.get(&s));
+          ASSERT_EQ(0, strcmp(s, "abc"));
+          mask |= 8;
+      } else if (!strcmp(name, "rate")) {
+          std::pair<int64_t, int64_t> r;
+          ASSERT_TRUE(prop.get(&r));
+          ASSERT_EQ(11, r.first);
+          ASSERT_EQ(12, r.second);
+          mask |= 16;
+      } else {
+          FAIL();
+      }
+  }
+  ASSERT_EQ(31, mask);
+}
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index 36042a4..3141c31 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -62,5 +62,8 @@
             src: "seccomp_policy/mediacodec-x86.policy",
         },
     },
-    required: ["crash_dump.policy"],
+    required: [
+        "crash_dump.policy",
+        "code_coverage.policy",
+    ],
 }
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index d878d72..1cf0534 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -70,7 +70,7 @@
 LOCAL_MODULE := mediacodec.policy
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy
+LOCAL_REQUIRED_MODULES := crash_dump.policy code_coverage.policy
 # mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
 # use the 32 bit policy
 ifdef TARGET_2ND_ARCH
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index fa5bc4a..ad03e68 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -9,12 +9,11 @@
         "libmedia_headers",
     ],
 
+    defaults: [
+        "libcodec2-hidl-defaults",
+    ],
     shared_libs: [
-        "android.hardware.media.c2@1.0",
         "libbase",
-        "libcodec2_hidl@1.0",
-        "libcodec2_vndk",
-        "libutils",
     ],
 
     // Codecs
diff --git a/services/mediacodec/registrant/CodecServiceRegistrant.cpp b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
index 706ebee..58db801e 100644
--- a/services/mediacodec/registrant/CodecServiceRegistrant.cpp
+++ b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
@@ -20,11 +20,11 @@
 #include <android-base/logging.h>
 
 #include <C2PlatformSupport.h>
-#include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.1/ComponentStore.h>
 #include <media/CodecServiceRegistrant.h>
 
 extern "C" void RegisterCodecServices() {
-    using namespace ::android::hardware::media::c2::V1_0;
+    using namespace ::android::hardware::media::c2::V1_1;
     LOG(INFO) << "Creating software Codec2 service...";
     android::sp<IComponentStore> store =
         new utils::ComponentStore(
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 3870a11..835f8bb 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -59,3 +59,5 @@
 getrandom: 1
 
 @include /system/etc/seccomp_policy/crash_dump.arm.policy
+
+@include /system/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index d9c4045..a9d32d6 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -69,3 +69,4 @@
 gettid: 1
 
 @include /system/etc/seccomp_policy/crash_dump.x86.policy
+@include /system/etc/seccomp_policy/code_coverage.x86.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 9042cd7..93b4852 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -84,3 +84,5 @@
 getgid32: 1
 getegid32: 1
 getgroups32: 1
+
+@include /system/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index 4faf8b2..bb05770 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
@@ -79,3 +79,4 @@
 getegid: 1
 getgroups: 1
 
+@include /system/etc/seccomp_policy/code_coverage.arm64.policy
diff --git a/services/mediadrm/Android.mk b/services/mediadrm/Android.mk
deleted file mode 100644
index 9f03964..0000000
--- a/services/mediadrm/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    MediaDrmService.cpp \
-    main_mediadrmserver.cpp
-
-LOCAL_HEADER_LIBRARIES:= \
-    libmedia_headers \
-    libmediadrm_headers
-
-LOCAL_SHARED_LIBRARIES:= \
-    libbinder \
-    liblog \
-    libmediadrm \
-    libutils \
-    libhidlbase \
-    libhidlmemory \
-    android.hardware.drm@1.0 \
-    android.hardware.drm@1.1 \
-    android.hardware.drm@1.2
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= mediadrmserver
-
-# TODO: Some legacy DRM plugins only support 32-bit. They need to be migrated to
-# 64-bit. (b/18948909) Once all of a device's legacy DRM plugins support 64-bit,
-# that device can turn on TARGET_ENABLE_MEDIADRM_64 to build this service as
-# 64-bit.
-ifneq ($(TARGET_ENABLE_MEDIADRM_64), true)
-LOCAL_32_BIT_ONLY := true
-endif
-
-LOCAL_INIT_RC := mediadrmserver.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/mediadrm/MediaDrmService.cpp b/services/mediadrm/MediaDrmService.cpp
deleted file mode 100644
index 5afd079..0000000
--- a/services/mediadrm/MediaDrmService.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-**
-** Copyright 2008, 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.
-*/
-
-// Proxy for media player implementations
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaDrmService"
-
-#include "MediaDrmService.h"
-#include <binder/IServiceManager.h>
-#include <utils/Log.h>
-
-#include <mediadrm/CryptoHal.h>
-#include <mediadrm/DrmHal.h>
-
-namespace android {
-
-void MediaDrmService::instantiate() {
-    defaultServiceManager()->addService(
-            String16("media.drm"), new MediaDrmService());
-}
-
-sp<ICrypto> MediaDrmService::makeCrypto() {
-    return new CryptoHal;
-}
-
-sp<IDrm> MediaDrmService::makeDrm() {
-    return new DrmHal;
-}
-
-} // namespace android
diff --git a/services/mediadrm/MediaDrmService.h b/services/mediadrm/MediaDrmService.h
deleted file mode 100644
index 3607201..0000000
--- a/services/mediadrm/MediaDrmService.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-**
-** Copyright 2008, 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_MEDIADRMSERVICE_H
-#define ANDROID_MEDIADRMSERVICE_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-
-#include <media/Metadata.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <mediadrm/IMediaDrmService.h>
-
-namespace android {
-
-class MediaDrmService : public BnMediaDrmService
-{
-public:
-    static void instantiate();
-
-    // IMediaDrmService interface
-    virtual sp<ICrypto> makeCrypto();
-    virtual sp<IDrm> makeDrm();
-private:
-    MediaDrmService() {}
-    virtual ~MediaDrmService() {}
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIADRMSERVICE_H
diff --git a/services/mediadrm/OWNERS b/services/mediadrm/OWNERS
deleted file mode 100644
index 6d3b533..0000000
--- a/services/mediadrm/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-jtinker@google.com
-marcone@google.com
diff --git a/services/mediadrm/main_mediadrmserver.cpp b/services/mediadrm/main_mediadrmserver.cpp
deleted file mode 100644
index b767b8c..0000000
--- a/services/mediadrm/main_mediadrmserver.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "mediaserver"
-//#define LOG_NDEBUG 0
-
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
-#include <utils/Log.h>
-#include "MediaDrmService.h"
-
-using namespace android;
-
-int main()
-{
-    signal(SIGPIPE, SIG_IGN);
-
-    sp<ProcessState> proc(ProcessState::self());
-    sp<IServiceManager> sm = defaultServiceManager();
-    ALOGI("ServiceManager: %p", sm.get());
-    MediaDrmService::instantiate();
-    ProcessState::self()->startThreadPool();
-    IPCThreadState::self()->joinThreadPool();
-}
diff --git a/services/mediadrm/mediadrmserver.rc b/services/mediadrm/mediadrmserver.rc
deleted file mode 100644
index 359c2cf..0000000
--- a/services/mediadrm/mediadrmserver.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service mediadrm /system/bin/mediadrmserver
-    class main
-    user media
-    group mediadrm drmrpc
-    ioprio rt 4
-    writepid /dev/cpuset/foreground/tasks
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index e906500..816a6b1 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -13,6 +13,7 @@
         "libstagefright",
         "libbinder",
         "libutils",
+        "liblog",
     ],
 }
 
@@ -67,6 +68,9 @@
             src: "seccomp_policy/mediaextractor-x86_64.policy",
         },
     },
-    required: ["crash_dump.policy"],
+    required: [
+        "crash_dump.policy",
+        "code_coverage.policy",
+    ],
 }
 
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 964acf4..38f9be6 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -50,3 +50,4 @@
 _llseek: 1
 
 @include /system/etc/seccomp_policy/crash_dump.arm.policy
+@include /system/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index e6c676c..8fd8787 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -44,3 +44,4 @@
 sched_yield: 1
 
 @include /system/etc/seccomp_policy/crash_dump.arm64.policy
+@include /system/etc/seccomp_policy/code_coverage.arm64.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 56ad8df..05915d1 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -57,3 +57,4 @@
 gettid: 1
 
 @include /system/etc/seccomp_policy/crash_dump.x86.policy
+@include /system/etc/seccomp_policy/code_coverage.x86.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
index 607a03e..e6a55d0 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
@@ -51,3 +51,4 @@
 gettid: 1
 
 @include /system/etc/seccomp_policy/crash_dump.x86_64.policy
+@include /system/etc/seccomp_policy/code_coverage.x86_64.policy
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index f3339a0..d468406 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -23,4 +23,6 @@
         "-Wall",
     ],
 
+    export_include_dirs: ["."],
+
 }
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index bdcd5e4..ae832c7 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -23,6 +23,7 @@
 #include <binder/IServiceManager.h>
 #include <cutils/sched_policy.h>
 #include <dirent.h>
+#include <media/MediaResourcePolicy.h>
 #include <media/stagefright/ProcessInfo.h>
 #include <mediautils/BatteryNotifier.h>
 #include <mediautils/SchedulingPolicyService.h>
@@ -37,7 +38,7 @@
 
 namespace android {
 
-namespace {
+namespace media {
 
 class DeathNotifier : public IBinder::DeathRecipient {
 public:
@@ -60,20 +61,18 @@
     int64_t mClientId;
 };
 
-}  // namespace
-
 template <typename T>
-static String8 getString(const Vector<T> &items) {
+static String8 getString(const std::vector<T> &items) {
     String8 itemsStr;
     for (size_t i = 0; i < items.size(); ++i) {
-        itemsStr.appendFormat("%s ", items[i].toString().string());
+        itemsStr.appendFormat("%s ", toString(items[i]).string());
     }
     return itemsStr;
 }
 
 static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
     for (auto it = resources.begin(); it != resources.end(); it++) {
-        if (it->second.mType == type) {
+        if (it->second.type == type) {
             return true;
         }
     }
@@ -121,15 +120,15 @@
     return infos.editValueAt(index);
 }
 
-static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
+static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel> &resources) {
     static const char* const kServiceName = "media_resource_monitor";
     sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
     if (binder != NULL) {
         sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
         for (size_t i = 0; i < resources.size(); ++i) {
-            if (resources[i].mSubType == MediaResource::kAudioCodec) {
+            if (resources[i].subType == MediaResource::SubType::kAudioCodec) {
                 service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
-            } else if (resources[i].mSubType == MediaResource::kVideoCodec) {
+            } else if (resources[i].subType == MediaResource::SubType::kVideoCodec) {
                 service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
             }
         }
@@ -182,13 +181,18 @@
             snprintf(buffer, SIZE, "        Id: %lld\n", (long long)infos[j].clientId);
             result.append(buffer);
 
-            snprintf(buffer, SIZE, "        Name: %s\n", infos[j].client->getName().string());
+            std::string clientName;
+            Status status = infos[j].client->getName(&clientName);
+            if (!status.isOk()) {
+                clientName = "<unknown client>";
+            }
+            snprintf(buffer, SIZE, "        Name: %s\n", clientName.c_str());
             result.append(buffer);
 
             const ResourceList &resources = infos[j].resources;
             result.append("        Resources:\n");
             for (auto it = resources.begin(); it != resources.end(); it++) {
-                snprintf(buffer, SIZE, "          %s\n", it->second.toString().string());
+                snprintf(buffer, SIZE, "          %s\n", toString(it->second).string());
                 result.append(buffer);
             }
         }
@@ -242,27 +246,28 @@
 
 ResourceManagerService::~ResourceManagerService() {}
 
-void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
+Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParcel>& policies) {
     String8 log = String8::format("config(%s)", getString(policies).string());
     mServiceLog->add(log);
 
     Mutex::Autolock lock(mLock);
     for (size_t i = 0; i < policies.size(); ++i) {
-        String8 type = policies[i].mType;
-        String8 value = policies[i].mValue;
-        if (type == kPolicySupportsMultipleSecureCodecs) {
+        const std::string &type = policies[i].type;
+        const std::string &value = policies[i].value;
+        if (type == MediaResourcePolicy::kPolicySupportsMultipleSecureCodecs()) {
             mSupportsMultipleSecureCodecs = (value == "true");
-        } else if (type == kPolicySupportsSecureWithNonSecureCodec) {
+        } else if (type == MediaResourcePolicy::kPolicySupportsSecureWithNonSecureCodec()) {
             mSupportsSecureWithNonSecureCodec = (value == "true");
         }
     }
+    return Status::ok();
 }
 
 void ResourceManagerService::onFirstAdded(
-        const MediaResource& resource, const ResourceInfo& clientInfo) {
+        const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
     // first time added
-    if (resource.mType == MediaResource::kCpuBoost
-     && resource.mSubType == MediaResource::kUnspecifiedSubType) {
+    if (resource.type == MediaResource::Type::kCpuBoost
+     && resource.subType == MediaResource::SubType::kUnspecifiedSubType) {
         // Request it on every new instance of kCpuBoost, as the media.codec
         // could have died, if we only do it the first time subsequent instances
         // never gets the boost.
@@ -270,32 +275,49 @@
             ALOGW("couldn't request cpuset boost");
         }
         mCpuBoostCount++;
-    } else if (resource.mType == MediaResource::kBattery
-            && resource.mSubType == MediaResource::kVideoCodec) {
+    } else if (resource.type == MediaResource::Type::kBattery
+            && resource.subType == MediaResource::SubType::kVideoCodec) {
         mSystemCB->noteStartVideo(clientInfo.uid);
     }
 }
 
 void ResourceManagerService::onLastRemoved(
-        const MediaResource& resource, const ResourceInfo& clientInfo) {
-    if (resource.mType == MediaResource::kCpuBoost
-            && resource.mSubType == MediaResource::kUnspecifiedSubType
+        const MediaResourceParcel& resource, const ResourceInfo& clientInfo) {
+    if (resource.type == MediaResource::Type::kCpuBoost
+            && resource.subType == MediaResource::SubType::kUnspecifiedSubType
             && mCpuBoostCount > 0) {
         if (--mCpuBoostCount == 0) {
             mSystemCB->requestCpusetBoost(false, this);
         }
-    } else if (resource.mType == MediaResource::kBattery
-            && resource.mSubType == MediaResource::kVideoCodec) {
+    } else if (resource.type == MediaResource::Type::kBattery
+            && resource.subType == MediaResource::SubType::kVideoCodec) {
         mSystemCB->noteStopVideo(clientInfo.uid);
     }
 }
 
-void ResourceManagerService::addResource(
-        int pid,
-        int uid,
+void ResourceManagerService::mergeResources(
+        MediaResourceParcel& r1, const MediaResourceParcel& r2) {
+    // The resource entry on record is maintained to be in [0,INT64_MAX].
+    // Clamp if merging in the new resource value causes it to go out of bound.
+    // Note that the new resource value could be negative, eg.DrmSession, the
+    // value goes lower when the session is used more often. During reclaim
+    // the session with the highest value (lowest usage) would be closed.
+    if (r2.value < INT64_MAX - r1.value) {
+        r1.value += r2.value;
+        if (r1.value < 0) {
+            r1.value = 0;
+        }
+    } else {
+        r1.value = INT64_MAX;
+    }
+}
+
+Status ResourceManagerService::addResource(
+        int32_t pid,
+        int32_t uid,
         int64_t clientId,
-        const sp<IResourceManagerClient> client,
-        const Vector<MediaResource> &resources) {
+        const sp<IResourceManagerClient>& client,
+        const std::vector<MediaResourceParcel>& resources) {
     String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
             pid, (long long) clientId, getString(resources).string());
     mServiceLog->add(log);
@@ -303,29 +325,43 @@
     Mutex::Autolock lock(mLock);
     if (!mProcessInfo->isValidPid(pid)) {
         ALOGE("Rejected addResource call with invalid pid.");
-        return;
+        return Status::fromServiceSpecificError(BAD_VALUE);
     }
     ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
     ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
 
     for (size_t i = 0; i < resources.size(); ++i) {
-        const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+        const auto &res = resources[i];
+        const auto resType = std::tuple(res.type, res.subType, res.id);
+
+        if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
+            ALOGW("Ignoring request to remove negative value of non-drm resource");
+            continue;
+        }
         if (info.resources.find(resType) == info.resources.end()) {
-            onFirstAdded(resources[i], info);
-            info.resources[resType] = resources[i];
+            if (res.value <= 0) {
+                // We can't init a new entry with negative value, although it's allowed
+                // to merge in negative values after the initial add.
+                ALOGW("Ignoring request to add new resource entry with value <= 0");
+                continue;
+            }
+            onFirstAdded(res, info);
+            info.resources[resType] = res;
         } else {
-            info.resources[resType].mValue += resources[i].mValue;
+            mergeResources(info.resources[resType], res);
         }
     }
-    if (info.deathNotifier == nullptr) {
+    if (info.deathNotifier == nullptr && client != nullptr) {
         info.deathNotifier = new DeathNotifier(this, pid, clientId);
         IInterface::asBinder(client)->linkToDeath(info.deathNotifier);
     }
     notifyResourceGranted(pid, resources);
+    return Status::ok();
 }
 
-void ResourceManagerService::removeResource(int pid, int64_t clientId,
-        const Vector<MediaResource> &resources) {
+Status ResourceManagerService::removeResource(
+        int32_t pid, int64_t clientId,
+        const std::vector<MediaResourceParcel>& resources) {
     String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
             pid, (long long) clientId, getString(resources).string());
     mServiceLog->add(log);
@@ -333,43 +369,51 @@
     Mutex::Autolock lock(mLock);
     if (!mProcessInfo->isValidPid(pid)) {
         ALOGE("Rejected removeResource call with invalid pid.");
-        return;
+        return Status::fromServiceSpecificError(BAD_VALUE);
     }
     ssize_t index = mMap.indexOfKey(pid);
     if (index < 0) {
         ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
-        return;
+        return Status::ok();
     }
     ResourceInfos &infos = mMap.editValueAt(index);
 
     index = infos.indexOfKey(clientId);
     if (index < 0) {
         ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
-        return;
+        return Status::ok();
     }
 
     ResourceInfo &info = infos.editValueAt(index);
 
     for (size_t i = 0; i < resources.size(); ++i) {
-        const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+        const auto &res = resources[i];
+        const auto resType = std::tuple(res.type, res.subType, res.id);
+
+        if (res.value < 0) {
+            ALOGW("Ignoring request to remove negative value of resource");
+            continue;
+        }
         // ignore if we don't have it
         if (info.resources.find(resType) != info.resources.end()) {
-            MediaResource &resource = info.resources[resType];
-            if (resource.mValue > resources[i].mValue) {
-                resource.mValue -= resources[i].mValue;
+            MediaResourceParcel &resource = info.resources[resType];
+            if (resource.value > res.value) {
+                resource.value -= res.value;
             } else {
-                onLastRemoved(resources[i], info);
+                onLastRemoved(res, info);
                 info.resources.erase(resType);
             }
         }
     }
+    return Status::ok();
 }
 
-void ResourceManagerService::removeClient(int pid, int64_t clientId) {
+Status ResourceManagerService::removeClient(int32_t pid, int64_t clientId) {
     removeResource(pid, clientId, true);
+    return Status::ok();
 }
 
-void ResourceManagerService::removeResource(int pid, int64_t clientId, bool checkValid) {
+Status ResourceManagerService::removeResource(int pid, int64_t clientId, bool checkValid) {
     String8 log = String8::format(
             "removeResource(pid %d, clientId %lld)",
             pid, (long long) clientId);
@@ -378,19 +422,19 @@
     Mutex::Autolock lock(mLock);
     if (checkValid && !mProcessInfo->isValidPid(pid)) {
         ALOGE("Rejected removeResource call with invalid pid.");
-        return;
+        return Status::fromServiceSpecificError(BAD_VALUE);
     }
     ssize_t index = mMap.indexOfKey(pid);
     if (index < 0) {
         ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
-        return;
+        return Status::ok();
     }
     ResourceInfos &infos = mMap.editValueAt(index);
 
     index = infos.indexOfKey(clientId);
     if (index < 0) {
         ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
-        return;
+        return Status::ok();
     }
 
     const ResourceInfo &info = infos[index];
@@ -401,66 +445,79 @@
     IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);
 
     infos.removeItemsAt(index);
+    return Status::ok();
 }
 
 void ResourceManagerService::getClientForResource_l(
-        int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients) {
+        int callingPid, const MediaResourceParcel *res, Vector<sp<IResourceManagerClient>> *clients) {
     if (res == NULL) {
         return;
     }
     sp<IResourceManagerClient> client;
-    if (getLowestPriorityBiggestClient_l(callingPid, res->mType, &client)) {
+    if (getLowestPriorityBiggestClient_l(callingPid, res->type, &client)) {
         clients->push_back(client);
     }
 }
 
-bool ResourceManagerService::reclaimResource(
-        int callingPid, const Vector<MediaResource> &resources) {
+Status ResourceManagerService::reclaimResource(
+        int32_t callingPid,
+        const std::vector<MediaResourceParcel>& resources,
+        bool* _aidl_return) {
     String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
             callingPid, getString(resources).string());
     mServiceLog->add(log);
+    *_aidl_return = false;
 
     Vector<sp<IResourceManagerClient>> clients;
     {
         Mutex::Autolock lock(mLock);
         if (!mProcessInfo->isValidPid(callingPid)) {
             ALOGE("Rejected reclaimResource call with invalid callingPid.");
-            return false;
+            return Status::fromServiceSpecificError(BAD_VALUE);
         }
-        const MediaResource *secureCodec = NULL;
-        const MediaResource *nonSecureCodec = NULL;
-        const MediaResource *graphicMemory = NULL;
+        const MediaResourceParcel *secureCodec = NULL;
+        const MediaResourceParcel *nonSecureCodec = NULL;
+        const MediaResourceParcel *graphicMemory = NULL;
+        const MediaResourceParcel *drmSession = NULL;
         for (size_t i = 0; i < resources.size(); ++i) {
-            MediaResource::Type type = resources[i].mType;
-            if (resources[i].mType == MediaResource::kSecureCodec) {
+            MediaResource::Type type = resources[i].type;
+            if (resources[i].type == MediaResource::Type::kSecureCodec) {
                 secureCodec = &resources[i];
-            } else if (type == MediaResource::kNonSecureCodec) {
+            } else if (type == MediaResource::Type::kNonSecureCodec) {
                 nonSecureCodec = &resources[i];
-            } else if (type == MediaResource::kGraphicMemory) {
+            } else if (type == MediaResource::Type::kGraphicMemory) {
                 graphicMemory = &resources[i];
+            } else if (type == MediaResource::Type::kDrmSession) {
+                drmSession = &resources[i];
             }
         }
 
         // first pass to handle secure/non-secure codec conflict
         if (secureCodec != NULL) {
             if (!mSupportsMultipleSecureCodecs) {
-                if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
-                    return false;
+                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+                    return Status::ok();
                 }
             }
             if (!mSupportsSecureWithNonSecureCodec) {
-                if (!getAllClients_l(callingPid, MediaResource::kNonSecureCodec, &clients)) {
-                    return false;
+                if (!getAllClients_l(callingPid, MediaResource::Type::kNonSecureCodec, &clients)) {
+                    return Status::ok();
                 }
             }
         }
         if (nonSecureCodec != NULL) {
             if (!mSupportsSecureWithNonSecureCodec) {
-                if (!getAllClients_l(callingPid, MediaResource::kSecureCodec, &clients)) {
-                    return false;
+                if (!getAllClients_l(callingPid, MediaResource::Type::kSecureCodec, &clients)) {
+                    return Status::ok();
                 }
             }
         }
+        if (drmSession != NULL) {
+            getClientForResource_l(callingPid, drmSession, &clients);
+            if (clients.size() == 0) {
+                return Status::ok();
+            }
+        }
 
         if (clients.size() == 0) {
             // if no secure/non-secure codec conflict, run second pass to handle other resources.
@@ -476,32 +533,35 @@
         if (clients.size() == 0) {
             // if we are here, run the fourth pass to free one codec with the different type.
             if (secureCodec != NULL) {
-                MediaResource temp(MediaResource::kNonSecureCodec, 1);
+                MediaResource temp(MediaResource::Type::kNonSecureCodec, 1);
                 getClientForResource_l(callingPid, &temp, &clients);
             }
             if (nonSecureCodec != NULL) {
-                MediaResource temp(MediaResource::kSecureCodec, 1);
+                MediaResource temp(MediaResource::Type::kSecureCodec, 1);
                 getClientForResource_l(callingPid, &temp, &clients);
             }
         }
     }
 
     if (clients.size() == 0) {
-        return false;
+        return Status::ok();
     }
 
     sp<IResourceManagerClient> failedClient;
     for (size_t i = 0; i < clients.size(); ++i) {
         log = String8::format("reclaimResource from client %p", clients[i].get());
         mServiceLog->add(log);
-        if (!clients[i]->reclaimResource()) {
+        bool success;
+        Status status = clients[i]->reclaimResource(&success);
+        if (!status.isOk() || !success) {
             failedClient = clients[i];
             break;
         }
     }
 
     if (failedClient == NULL) {
-        return true;
+        *_aidl_return = true;
+        return Status::ok();
     }
 
     {
@@ -526,7 +586,7 @@
         }
     }
 
-    return false;
+    return Status::ok();
 }
 
 bool ResourceManagerService::getAllClients_l(
@@ -641,10 +701,10 @@
     for (size_t i = 0; i < infos.size(); ++i) {
         const ResourceList &resources = infos[i].resources;
         for (auto it = resources.begin(); it != resources.end(); it++) {
-            const MediaResource &resource = it->second;
-            if (resource.mType == type) {
-                if (resource.mValue > largestValue) {
-                    largestValue = resource.mValue;
+            const MediaResourceParcel &resource = it->second;
+            if (resource.type == type) {
+                if (resource.value > largestValue) {
+                    largestValue = resource.value;
                     clientTemp = infos[i].client;
                 }
             }
@@ -660,4 +720,5 @@
     return true;
 }
 
+} // namespace media
 } // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f086dc3..b5b9f86 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -15,25 +15,32 @@
 ** limitations under the License.
 */
 
-#ifndef ANDROID_RESOURCEMANAGERSERVICE_H
-#define ANDROID_RESOURCEMANAGERSERVICE_H
+#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
+#define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
 
+#include <android/media/BnResourceManagerService.h>
 #include <arpa/inet.h>
 #include <binder/BinderService.h>
+#include <media/MediaResource.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Vector.h>
 
-#include <media/IResourceManagerService.h>
-
 namespace android {
 
 class ServiceLog;
 struct ProcessInfoInterface;
 
-typedef std::map<std::pair<MediaResource::Type, MediaResource::SubType>, MediaResource> ResourceList;
+namespace media {
+
+using android::binder::Status;
+
+typedef std::map<std::tuple<
+        MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
+        MediaResourceParcel> ResourceList;
+
 struct ResourceInfo {
     int64_t clientId;
     uid_t uid;
@@ -69,26 +76,31 @@
             const sp<SystemCallbackInterface> &systemResource);
 
     // IResourceManagerService interface
-    virtual void config(const Vector<MediaResourcePolicy> &policies);
+    Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
 
-    virtual void addResource(
-            int pid,
-            int uid,
+    Status addResource(
+            int32_t pid,
+            int32_t uid,
             int64_t clientId,
-            const sp<IResourceManagerClient> client,
-            const Vector<MediaResource> &resources);
+            const sp<IResourceManagerClient>& client,
+            const std::vector<MediaResourceParcel>& resources) override;
 
-    virtual void removeResource(int pid, int64_t clientId,
-            const Vector<MediaResource> &resources);
+    Status removeResource(
+            int32_t pid,
+            int64_t clientId,
+            const std::vector<MediaResourceParcel>& resources) override;
 
-    virtual void removeClient(int pid, int64_t clientId);
+    Status removeClient(int32_t pid, int64_t clientId) override;
 
     // Tries to reclaim resource from processes with lower priority than the calling process
     // according to the requested resources.
     // Returns true if any resource has been reclaimed, otherwise returns false.
-    virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources);
+    Status reclaimResource(
+            int32_t callingPid,
+            const std::vector<MediaResourceParcel>& resources,
+            bool* _aidl_return) override;
 
-    void removeResource(int pid, int64_t clientId, bool checkValid);
+    Status removeResource(int pid, int64_t clientId, bool checkValid);
 
 protected:
     virtual ~ResourceManagerService();
@@ -120,11 +132,14 @@
 
     // A helper function basically calls getLowestPriorityBiggestClient_l and add the result client
     // to the given Vector.
-    void getClientForResource_l(
-        int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients);
+    void getClientForResource_l(int callingPid,
+            const MediaResourceParcel *res, Vector<sp<IResourceManagerClient>> *clients);
 
-    void onFirstAdded(const MediaResource& res, const ResourceInfo& clientInfo);
-    void onLastRemoved(const MediaResource& res, const ResourceInfo& clientInfo);
+    void onFirstAdded(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
+    void onLastRemoved(const MediaResourceParcel& res, const ResourceInfo& clientInfo);
+
+    // Merge r2 into r1
+    void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
 
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
@@ -137,7 +152,7 @@
 };
 
 // ----------------------------------------------------------------------------
+} // namespace media
+} // namespace android
 
-}; // namespace android
-
-#endif // ANDROID_RESOURCEMANAGERSERVICE_H
+#endif // ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ae97ec8..203baf5 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -21,13 +21,16 @@
 #include <gtest/gtest.h>
 
 #include "ResourceManagerService.h"
-#include <media/IResourceManagerService.h>
+#include <android/media/BnResourceManagerClient.h>
 #include <media/MediaResource.h>
 #include <media/MediaResourcePolicy.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/ProcessInfoInterface.h>
 
 namespace android {
+namespace media {
+
+using ::android::binder::Status;
 
 static int64_t getId(const sp<IResourceManagerClient>& client) {
     return (int64_t) client.get();
@@ -112,15 +115,17 @@
     TestClient(int pid, sp<ResourceManagerService> service)
         : mReclaimed(false), mPid(pid), mService(service) {}
 
-    virtual bool reclaimResource() {
+    Status reclaimResource(bool* _aidl_return) override {
         sp<IResourceManagerClient> client(this);
         mService->removeClient(mPid, (int64_t) client.get());
         mReclaimed = true;
-        return true;
+        *_aidl_return = true;
+        return Status::ok();
     }
 
-    virtual String8 getName() {
-        return String8("test_client");
+    Status getName(::std::string* _aidl_return) override {
+        *_aidl_return = "test_client";
+        return Status::ok();
     }
 
     bool reclaimed() const {
@@ -157,6 +162,12 @@
     return lhs.type == rhs.type && lhs.arg == rhs.arg;
 }
 
+#define CHECK_STATUS_TRUE(condition) \
+    EXPECT_TRUE((condition).isOk() && (result))
+
+#define CHECK_STATUS_FALSE(condition) \
+    EXPECT_TRUE((condition).isOk() && !(result))
+
 class ResourceManagerServiceTest : public ::testing::Test {
 public:
     ResourceManagerServiceTest()
@@ -168,13 +179,14 @@
     }
 
 protected:
-    static bool isEqualResources(const Vector<MediaResource> &resources1,
+    static bool isEqualResources(const std::vector<MediaResourceParcel> &resources1,
             const ResourceList &resources2) {
         // convert resource1 to ResourceList
         ResourceList r1;
         for (size_t i = 0; i < resources1.size(); ++i) {
-            const auto resType = std::make_pair(resources1[i].mType, resources1[i].mSubType);
-            r1[resType] = resources1[i];
+            const auto &res = resources1[i];
+            const auto resType = std::tuple(res.type, res.subType, res.id);
+            r1[resType] = res;
         }
         return r1 == resources2;
     }
@@ -182,7 +194,7 @@
     static void expectEqResourceInfo(const ResourceInfo &info,
             int uid,
             sp<IResourceManagerClient> client,
-            const Vector<MediaResource> &resources) {
+            const std::vector<MediaResourceParcel> &resources) {
         EXPECT_EQ(uid, info.uid);
         EXPECT_EQ(client, info.client);
         EXPECT_TRUE(isEqualResources(resources, info.resources));
@@ -218,25 +230,25 @@
     // ---------------------------------------------------------------------------------
     void addResource() {
         // kTestPid1 mTestClient1
-        Vector<MediaResource> resources1;
-        resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        std::vector<MediaResourceParcel> resources1;
+        resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
-        resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
-        Vector<MediaResource> resources11;
-        resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+        resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
+        std::vector<MediaResourceParcel> resources11;
+        resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
 
         // kTestPid2 mTestClient2
-        Vector<MediaResource> resources2;
-        resources2.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
-        resources2.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+        std::vector<MediaResourceParcel> resources2;
+        resources2.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+        resources2.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
         mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
 
         // kTestPid2 mTestClient3
-        Vector<MediaResource> resources3;
+        std::vector<MediaResourceParcel> resources3;
         mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
-        resources3.push_back(MediaResource(MediaResource::kSecureCodec, 1));
-        resources3.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+        resources3.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+        resources3.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
         mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
 
         const PidResourceInfosMap &map = mService->mMap;
@@ -255,32 +267,92 @@
         expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
     }
 
+    void testCombineResourceWithNegativeValues() {
+        // kTestPid1 mTestClient1
+        std::vector<MediaResourceParcel> resources1;
+        resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -100));
+        resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -100));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+        // Expected result:
+        // 1) the client should have been added;
+        // 2) both resource entries should have been rejected, resource list should be empty.
+        const PidResourceInfosMap &map = mService->mMap;
+        EXPECT_EQ(1u, map.size());
+        ssize_t index1 = map.indexOfKey(kTestPid1);
+        ASSERT_GE(index1, 0);
+        const ResourceInfos &infos1 = map[index1];
+        EXPECT_EQ(1u, infos1.size());
+        std::vector<MediaResourceParcel> expected;
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+        resources1.clear();
+        resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
+        resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+        resources1.clear();
+        resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, 10));
+        resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 10));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+        // Expected result:
+        // Both values should saturate to INT64_MAX
+        expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX));
+        expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+        resources1.clear();
+        resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, -10));
+        resources1.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, -10));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+        // Expected result:
+        // 1) DrmSession resource should allow negative value addition, and value should drop accordingly
+        // 2) Non-drm session resource should ignore negative value addition.
+        expected.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MAX - 10));
+        expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+        resources1.clear();
+        resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
+        expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
+        mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+        // Expected result:
+        // 1) DrmSession resource value should drop to 0, but the entry shouldn't be removed.
+        // 2) Non-drm session resource should ignore negative value addition.
+        expected.clear();
+        expected.push_back(MediaResource(MediaResource::Type::kDrmSession, 0));
+        expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MAX));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+    }
+
     void testConfig() {
         EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
         EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
 
-        Vector<MediaResourcePolicy> policies1;
+        std::vector<MediaResourcePolicyParcel> policies1;
         policies1.push_back(
                 MediaResourcePolicy(
-                        String8(kPolicySupportsMultipleSecureCodecs),
-                        String8("true")));
+                        IResourceManagerService::kPolicySupportsMultipleSecureCodecs(),
+                        "true"));
         policies1.push_back(
                 MediaResourcePolicy(
-                        String8(kPolicySupportsSecureWithNonSecureCodec),
-                        String8("false")));
+                        IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec(),
+                        "false"));
         mService->config(policies1);
         EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
         EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
 
-        Vector<MediaResourcePolicy> policies2;
+        std::vector<MediaResourcePolicyParcel> policies2;
         policies2.push_back(
                 MediaResourcePolicy(
-                        String8(kPolicySupportsMultipleSecureCodecs),
-                        String8("false")));
+                        IResourceManagerService::kPolicySupportsMultipleSecureCodecs(),
+                        "false"));
         policies2.push_back(
                 MediaResourcePolicy(
-                        String8(kPolicySupportsSecureWithNonSecureCodec),
-                        String8("true")));
+                        IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec(),
+                        "true"));
         mService->config(policies2);
         EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
         EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
@@ -288,12 +360,12 @@
 
     void testCombineResource() {
         // kTestPid1 mTestClient1
-        Vector<MediaResource> resources1;
-        resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        std::vector<MediaResourceParcel> resources1;
+        resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
 
-        Vector<MediaResource> resources11;
-        resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+        std::vector<MediaResourceParcel> resources11;
+        resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
 
         const PidResourceInfosMap &map = mService->mMap;
@@ -304,35 +376,35 @@
         EXPECT_EQ(1u, infos1.size());
 
         // test adding existing types to combine values
-        resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+        resources1.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
 
-        Vector<MediaResource> expected;
-        expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
-        expected.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+        std::vector<MediaResourceParcel> expected;
+        expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
+        expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 300));
         expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         // test adding new types (including types that differs only in subType)
-        resources11.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
-        resources11.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
+        resources11.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+        resources11.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
 
         expected.clear();
-        expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
-        expected.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
-        expected.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
-        expected.push_back(MediaResource(MediaResource::kGraphicMemory, 500));
+        expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 2));
+        expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+        expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, MediaResource::SubType::kVideoCodec, 1));
+        expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 500));
         expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
     }
 
     void testRemoveResource() {
         // kTestPid1 mTestClient1
-        Vector<MediaResource> resources1;
-        resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        std::vector<MediaResourceParcel> resources1;
+        resources1.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
 
-        Vector<MediaResource> resources11;
-        resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+        std::vector<MediaResourceParcel> resources11;
+        resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
 
         const PidResourceInfosMap &map = mService->mMap;
@@ -343,20 +415,26 @@
         EXPECT_EQ(1u, infos1.size());
 
         // test partial removal
-        resources11.editItemAt(0).mValue = 100;
+        resources11[0].value = 100;
         mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
 
-        Vector<MediaResource> expected;
-        expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
-        expected.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+        std::vector<MediaResourceParcel> expected;
+        expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+        expected.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
+        expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+        // test removal request with negative value, should be ignored
+        resources11[0].value = -10000;
+        mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
+
         expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
 
         // test complete removal with overshoot value
-        resources11.editItemAt(0).mValue = 1000;
+        resources11[0].value = 1000;
         mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
 
         expected.clear();
-        expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+        expected.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
         expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
     }
 
@@ -379,7 +457,7 @@
     void testGetAllClients() {
         addResource();
 
-        MediaResource::Type type = MediaResource::kSecureCodec;
+        MediaResource::Type type = MediaResource::Type::kSecureCodec;
         Vector<sp<IResourceManagerClient> > clients;
         EXPECT_FALSE(mService->getAllClients_l(kLowPriorityPid, type, &clients));
         // some higher priority process (e.g. kTestPid2) owns the resource, so getAllClients_l
@@ -394,9 +472,10 @@
     }
 
     void testReclaimResourceSecure() {
-        Vector<MediaResource> resources;
-        resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
-        resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
+        bool result;
+        std::vector<MediaResourceParcel> resources;
+        resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
+        resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
 
         // ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
         {
@@ -405,19 +484,19 @@
             mService->mSupportsSecureWithNonSecureCodec = true;
 
             // priority too low
-            EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
-            EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
 
             // reclaim all secure codecs
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
 
             // call again should reclaim one largest graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
 
             // nothing left
-            EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
         }
 
         // ### secure codecs can't coexist and secure codec can't coexist with non-secure codec ###
@@ -427,15 +506,15 @@
             mService->mSupportsSecureWithNonSecureCodec = false;
 
             // priority too low
-            EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
-            EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
 
             // reclaim all secure and non-secure codecs
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(true /* c1 */, true /* c2 */, true /* c3 */);
 
             // nothing left
-            EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
         }
 
 
@@ -446,23 +525,23 @@
             mService->mSupportsSecureWithNonSecureCodec = false;
 
             // priority too low
-            EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
-            EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
 
             // reclaim all non-secure codecs
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
 
             // call again should reclaim one largest graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
 
             // call again should reclaim another largest graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
 
             // nothing left
-            EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
         }
 
         // ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
@@ -472,22 +551,22 @@
             mService->mSupportsSecureWithNonSecureCodec = true;
 
             // priority too low
-            EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
 
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // one largest graphic memory from lowest process got reclaimed
             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
 
             // call again should reclaim another graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
 
             // call again should reclaim another graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
 
             // nothing left
-            EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
         }
 
         // ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
@@ -496,27 +575,28 @@
             mService->mSupportsMultipleSecureCodecs = true;
             mService->mSupportsSecureWithNonSecureCodec = true;
 
-            Vector<MediaResource> resources;
-            resources.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
 
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // secure codec from lowest process got reclaimed
             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
 
             // call again should reclaim another secure codec from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
 
             // no more secure codec, non-secure codec will be reclaimed.
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
         }
     }
 
     void testReclaimResourceNonSecure() {
-        Vector<MediaResource> resources;
-        resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
-        resources.push_back(MediaResource(MediaResource::kGraphicMemory, 150));
+        bool result;
+        std::vector<MediaResourceParcel> resources;
+        resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+        resources.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 150));
 
         // ### secure codec can't coexist with non-secure codec ###
         {
@@ -524,19 +604,19 @@
             mService->mSupportsSecureWithNonSecureCodec = false;
 
             // priority too low
-            EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
-            EXPECT_FALSE(mService->reclaimResource(kMidPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kMidPriorityPid, resources, &result));
 
             // reclaim all secure codecs
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(true /* c1 */, false /* c2 */, true /* c3 */);
 
             // call again should reclaim one graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
 
             // nothing left
-            EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
         }
 
 
@@ -546,22 +626,22 @@
             mService->mSupportsSecureWithNonSecureCodec = true;
 
             // priority too low
-            EXPECT_FALSE(mService->reclaimResource(kLowPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kLowPriorityPid, resources, &result));
 
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // one largest graphic memory from lowest process got reclaimed
             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
 
             // call again should reclaim another graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
 
             // call again should reclaim another graphic memory from lowest process
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(false /* c1 */, false /* c2 */, true /* c3 */);
 
             // nothing left
-            EXPECT_FALSE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_FALSE(mService->reclaimResource(kHighPriorityPid, resources, &result));
         }
 
         // ### secure codec can coexist with non-secure codec ###
@@ -569,15 +649,15 @@
             addResource();
             mService->mSupportsSecureWithNonSecureCodec = true;
 
-            Vector<MediaResource> resources;
-            resources.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
+            std::vector<MediaResourceParcel> resources;
+            resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
 
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             // one non secure codec from lowest process got reclaimed
             verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
 
             // no more non-secure codec, secure codec from lowest priority process will be reclaimed
-            EXPECT_TRUE(mService->reclaimResource(kHighPriorityPid, resources));
+            CHECK_STATUS_TRUE(mService->reclaimResource(kHighPriorityPid, resources, &result));
             verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
 
             // clean up client 3 which still left
@@ -586,7 +666,7 @@
     }
 
     void testGetLowestPriorityBiggestClient() {
-        MediaResource::Type type = MediaResource::kGraphicMemory;
+        MediaResource::Type type = MediaResource::Type::kGraphicMemory;
         sp<IResourceManagerClient> client;
         EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
 
@@ -595,8 +675,8 @@
         EXPECT_FALSE(mService->getLowestPriorityBiggestClient_l(kLowPriorityPid, type, &client));
         EXPECT_TRUE(mService->getLowestPriorityBiggestClient_l(kHighPriorityPid, type, &client));
 
-        // kTestPid1 is the lowest priority process with MediaResource::kGraphicMemory.
-        // mTestClient1 has the largest MediaResource::kGraphicMemory within kTestPid1.
+        // kTestPid1 is the lowest priority process with MediaResource::Type::kGraphicMemory.
+        // mTestClient1 has the largest MediaResource::Type::kGraphicMemory within kTestPid1.
         EXPECT_EQ(mTestClient1, client);
     }
 
@@ -605,7 +685,7 @@
         int priority;
         TestProcessInfo processInfo;
 
-        MediaResource::Type type = MediaResource::kGraphicMemory;
+        MediaResource::Type type = MediaResource::Type::kGraphicMemory;
         EXPECT_FALSE(mService->getLowestPriorityPid_l(type, &pid, &priority));
 
         addResource();
@@ -616,7 +696,7 @@
         processInfo.getPriority(kTestPid1, &priority1);
         EXPECT_EQ(priority1, priority);
 
-        type = MediaResource::kNonSecureCodec;
+        type = MediaResource::Type::kNonSecureCodec;
         EXPECT_TRUE(mService->getLowestPriorityPid_l(type, &pid, &priority));
         EXPECT_EQ(kTestPid2, pid);
         int priority2;
@@ -625,7 +705,7 @@
     }
 
     void testGetBiggestClient() {
-        MediaResource::Type type = MediaResource::kGraphicMemory;
+        MediaResource::Type type = MediaResource::Type::kGraphicMemory;
         sp<IResourceManagerClient> client;
         EXPECT_FALSE(mService->getBiggestClient_l(kTestPid2, type, &client));
 
@@ -647,8 +727,8 @@
         EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
 
         // new client request should cause VIDEO_ON
-        Vector<MediaResource> resources1;
-        resources1.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1));
+        std::vector<MediaResourceParcel> resources1;
+        resources1.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 1));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
         EXPECT_EQ(2u, mSystemCB->eventCount());
         EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid1}), mSystemCB->lastEvent());
@@ -658,8 +738,8 @@
         EXPECT_EQ(2u, mSystemCB->eventCount());
 
         // new client request should cause VIDEO_ON
-        Vector<MediaResource> resources2;
-        resources2.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 2));
+        std::vector<MediaResourceParcel> resources2;
+        resources2.push_back(MediaResource(MediaResource::Type::kBattery, MediaResource::SubType::kVideoCodec, 2));
         mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
         EXPECT_EQ(3u, mSystemCB->eventCount());
         EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid2}), mSystemCB->lastEvent());
@@ -686,8 +766,8 @@
         EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
 
         // new client request should cause CPUSET_ENABLE
-        Vector<MediaResource> resources1;
-        resources1.push_back(MediaResource(MediaResource::kCpuBoost, 1));
+        std::vector<MediaResourceParcel> resources1;
+        resources1.push_back(MediaResource(MediaResource::Type::kCpuBoost, 1));
         mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
         EXPECT_EQ(2u, mSystemCB->eventCount());
         EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
@@ -697,8 +777,8 @@
         EXPECT_EQ(2u, mSystemCB->eventCount());
 
         // new client request should cause CPUSET_ENABLE
-        Vector<MediaResource> resources2;
-        resources2.push_back(MediaResource(MediaResource::kCpuBoost, 2));
+        std::vector<MediaResourceParcel> resources2;
+        resources2.push_back(MediaResource(MediaResource::Type::kCpuBoost, 2));
         mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
         EXPECT_EQ(3u, mSystemCB->eventCount());
         EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
@@ -737,6 +817,10 @@
     testCombineResource();
 }
 
+TEST_F(ResourceManagerServiceTest, combineResourceNegative) {
+    testCombineResourceWithNegativeValues();
+}
+
 TEST_F(ResourceManagerServiceTest, removeResource) {
     testRemoveResource();
 }
@@ -778,4 +862,5 @@
     testCpusetBoost();
 }
 
+} // namespace media
 } // namespace android
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index e6a8375..af8c67b 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -78,6 +78,11 @@
     AAudioClientTracker::getInstance().registerClient(pid, client);
 }
 
+bool AAudioService::isCallerInService() {
+    return mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
+        mAudioClient.clientUid == IPCThreadState::self()->getCallingUid();
+}
+
 aaudio_handle_t AAudioService::openStream(const aaudio::AAudioStreamRequest &request,
                                           aaudio::AAudioStreamConfiguration &configurationOutput) {
     aaudio_result_t result = AAUDIO_OK;
@@ -105,8 +110,7 @@
     if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
         // only trust audioserver for in service indication
         bool inService = false;
-        if (mAudioClient.clientPid == IPCThreadState::self()->getCallingPid() &&
-                mAudioClient.clientUid == IPCThreadState::self()->getCallingUid()) {
+        if (isCallerInService()) {
             inService = request.isInService();
         }
         serviceStream = new AAudioServiceStreamMMAP(*this, inService);
@@ -274,12 +278,14 @@
         result = AAUDIO_ERROR_INVALID_STATE;
     } else {
         const pid_t ownerPid = IPCThreadState::self()->getCallingPid(); // TODO review
+        int32_t priority = isCallerInService()
+            ? kRealTimeAudioPriorityService : kRealTimeAudioPriorityClient;
         serviceStream->setRegisteredThread(clientThreadId);
         int err = android::requestPriority(ownerPid, clientThreadId,
-                                           DEFAULT_AUDIO_PRIORITY, true /* isForApp */);
+                                           priority, true /* isForApp */);
         if (err != 0) {
             ALOGE("AAudioService::registerAudioThread(%d) failed, errno = %d, priority = %d",
-                  clientThreadId, errno, DEFAULT_AUDIO_PRIORITY);
+                  clientThreadId, errno, priority);
             result = AAUDIO_ERROR_INTERNAL;
         }
     }
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index d21b1cd..43a59c3 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -87,6 +87,10 @@
 
 private:
 
+    /** @return true if the client is the audioserver
+     */
+    bool isCallerInService();
+
     /**
      * Lookup stream and then validate access to the stream.
      * @param streamHandle
@@ -106,9 +110,10 @@
 
     aaudio::AAudioStreamTracker     mStreamTracker;
 
-    enum constants {
-        DEFAULT_AUDIO_PRIORITY = 2
-    };
+    // 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/Android.bp b/services/oboeservice/Android.bp
new file mode 100644
index 0000000..ca1354d
--- /dev/null
+++ b/services/oboeservice/Android.bp
@@ -0,0 +1,58 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+
+    name: "libaaudioservice",
+
+    srcs: [
+        "AAudioClientTracker.cpp",
+        "AAudioEndpointManager.cpp",
+        "AAudioMixer.cpp",
+        "AAudioService.cpp",
+        "AAudioServiceEndpoint.cpp",
+        "AAudioServiceEndpointCapture.cpp",
+        "AAudioServiceEndpointMMAP.cpp",
+        "AAudioServiceEndpointPlay.cpp",
+        "AAudioServiceEndpointShared.cpp",
+        "AAudioServiceStreamBase.cpp",
+        "AAudioServiceStreamMMAP.cpp",
+        "AAudioServiceStreamShared.cpp",
+        "AAudioStreamTracker.cpp",
+        "AAudioThread.cpp",
+        "SharedMemoryProxy.cpp",
+        "SharedRingBuffer.cpp",
+        "TimestampScheduler.cpp",
+    ],
+
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wall",
+        "-Werror",
+    ],
+
+    shared_libs: [
+        "libaaudio_internal",
+        "libaudioclient",
+        "libaudioflinger",
+        "libaudioutils",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "libmediautils",
+        "libutils",
+    ],
+
+}
diff --git a/services/oboeservice/Android.mk b/services/oboeservice/Android.mk
deleted file mode 100644
index 5e4cd39..0000000
--- a/services/oboeservice/Android.mk
+++ /dev/null
@@ -1,60 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# AAudio Service
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudioservice
-LOCAL_MODULE_TAGS := optional
-
-LIBAAUDIO_DIR := ../../media/libaaudio
-LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
-
-LOCAL_C_INCLUDES := \
-    $(TOPDIR)frameworks/av/services/audioflinger \
-    $(call include-path-for, audio-utils) \
-    frameworks/native/include \
-    system/core/base/include \
-    $(TOP)/frameworks/av/media/libaaudio/include \
-    $(TOP)/frameworks/av/media/utils/include \
-    frameworks/native/include \
-    $(TOP)/external/tinyalsa/include \
-    $(TOP)/frameworks/av/media/libaaudio/src
-
-LOCAL_SRC_FILES += \
-    SharedMemoryProxy.cpp \
-    SharedRingBuffer.cpp \
-    AAudioClientTracker.cpp \
-    AAudioEndpointManager.cpp \
-    AAudioMixer.cpp \
-    AAudioService.cpp \
-    AAudioServiceEndpoint.cpp \
-    AAudioServiceEndpointCapture.cpp \
-    AAudioServiceEndpointMMAP.cpp \
-    AAudioServiceEndpointPlay.cpp \
-    AAudioServiceEndpointShared.cpp \
-    AAudioServiceStreamBase.cpp \
-    AAudioServiceStreamMMAP.cpp \
-    AAudioServiceStreamShared.cpp \
-    AAudioStreamTracker.cpp \
-    TimestampScheduler.cpp \
-    AAudioThread.cpp
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-# LOCAL_CFLAGS += -fvisibility=hidden
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES :=  \
-    libaaudio_internal \
-    libaudioflinger \
-    libaudioclient \
-    libbinder \
-    libcutils \
-    libmediautils \
-    libutils \
-    liblog
-
-include $(BUILD_SHARED_LIBRARY)
-
-
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 377d30b..ccbeb77 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -40,6 +40,32 @@
 #define HW_MODULE_PREFIX "primary"
 namespace android {
 
+namespace {
+
+// Given an IMemory, returns a copy of its content along with its size.
+// Returns nullptr on failure or if input is nullptr.
+std::pair<std::unique_ptr<uint8_t[]>,
+          size_t> CopyToArray(const sp<IMemory>& mem) {
+    if (mem == nullptr) {
+        return std::make_pair(nullptr, 0);
+    }
+
+    const size_t size = mem->size();
+    if (size == 0) {
+        return std::make_pair(nullptr, 0);
+    }
+
+    std::unique_ptr<uint8_t[]> ar = std::make_unique<uint8_t[]>(size);
+    if (ar == nullptr) {
+        return std::make_pair(nullptr, 0);
+    }
+
+    memcpy(ar.get(), mem->unsecurePointer(), size);
+    return std::make_pair(std::move(ar), size);
+}
+
+}
+
 SoundTriggerHwService::SoundTriggerHwService()
     : BnSoundTriggerHwService(),
       mNextUniqueId(1),
@@ -234,11 +260,11 @@
 
     size_t size = event->data_offset + event->data_size;
     eventMemory = mMemoryDealer->allocate(size);
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         eventMemory.clear();
         return eventMemory;
     }
-    memcpy(eventMemory->pointer(), event, size);
+    memcpy(eventMemory->unsecurePointer(), event, size);
 
     return eventMemory;
 }
@@ -283,11 +309,11 @@
 
     size_t size = event->data_offset + event->data_size;
     eventMemory = mMemoryDealer->allocate(size);
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         eventMemory.clear();
         return eventMemory;
     }
-    memcpy(eventMemory->pointer(), event, size);
+    memcpy(eventMemory->unsecurePointer(), event, size);
 
     return eventMemory;
 }
@@ -313,11 +339,11 @@
 
     size_t size = sizeof(sound_trigger_service_state_t);
     eventMemory = mMemoryDealer->allocate(size);
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         eventMemory.clear();
         return eventMemory;
     }
-    *((sound_trigger_service_state_t *)eventMemory->pointer()) = state;
+    *((sound_trigger_service_state_t *)eventMemory->unsecurePointer()) = state;
     return eventMemory;
 }
 
@@ -557,8 +583,13 @@
         return NO_INIT;
     }
 
-    struct sound_trigger_sound_model *sound_model =
-            (struct sound_trigger_sound_model *)modelMemory->pointer();
+    auto immutableMemory = CopyToArray(modelMemory);
+    if (immutableMemory.first == nullptr) {
+        return NO_MEMORY;
+    }
+
+    struct sound_trigger_sound_model* sound_model =
+        (struct sound_trigger_sound_model*) immutableMemory.first.get();
 
     size_t structSize;
     if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
@@ -568,9 +599,10 @@
     }
 
     if (sound_model->data_offset < structSize ||
-           sound_model->data_size > (UINT_MAX - sound_model->data_offset) ||
-           modelMemory->size() < sound_model->data_offset ||
-           sound_model->data_size > (modelMemory->size() - sound_model->data_offset)) {
+        sound_model->data_size > (UINT_MAX - sound_model->data_offset) ||
+        immutableMemory.second < sound_model->data_offset ||
+            sound_model->data_size >
+            (immutableMemory.second - sound_model->data_offset)) {
         android_errorWriteLog(0x534e4554, "30148546");
         ALOGE("loadSoundModel() data_size is too big");
         return BAD_VALUE;
@@ -651,13 +683,19 @@
         return NO_INIT;
     }
 
-    struct sound_trigger_recognition_config *config =
-            (struct sound_trigger_recognition_config *)dataMemory->pointer();
+    auto immutableMemory = CopyToArray(dataMemory);
+    if (immutableMemory.first == nullptr) {
+        return NO_MEMORY;
+    }
+
+    struct sound_trigger_recognition_config* config =
+        (struct sound_trigger_recognition_config*) immutableMemory.first.get();
 
     if (config->data_offset < sizeof(struct sound_trigger_recognition_config) ||
-            config->data_size > (UINT_MAX - config->data_offset) ||
-            dataMemory->size() < config->data_offset ||
-            config->data_size > (dataMemory->size() - config->data_offset)) {
+        config->data_size > (UINT_MAX - config->data_offset) ||
+        immutableMemory.second < config->data_offset ||
+            config->data_size >
+            (immutableMemory.second - config->data_offset)) {
         ALOGE("startRecognition() data_size is too big");
         return BAD_VALUE;
     }
@@ -734,9 +772,10 @@
 {
     ALOGV("onCallbackEvent type %d", event->mType);
 
+    // Memory is coming from a trusted process.
     sp<IMemory> eventMemory = event->mMemory;
 
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         return;
     }
     if (mModuleClients.isEmpty()) {
@@ -749,7 +788,7 @@
     switch (event->mType) {
     case CallbackEvent::TYPE_RECOGNITION: {
         struct sound_trigger_recognition_event *recognitionEvent =
-                (struct sound_trigger_recognition_event *)eventMemory->pointer();
+                (struct sound_trigger_recognition_event *)eventMemory->unsecurePointer();
         {
             AutoMutex lock(mLock);
             sp<Model> model = getModel(recognitionEvent->model);
@@ -769,7 +808,7 @@
     } break;
     case CallbackEvent::TYPE_SOUNDMODEL: {
         struct sound_trigger_model_event *soundmodelEvent =
-                (struct sound_trigger_model_event *)eventMemory->pointer();
+                (struct sound_trigger_model_event *)eventMemory->unsecurePointer();
         {
             AutoMutex lock(mLock);
             sp<Model> model = getModel(soundmodelEvent->model);
@@ -1082,7 +1121,8 @@
 
     sp<IMemory> eventMemory = event->mMemory;
 
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    // Memory is coming from a trusted process.
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         return;
     }
 
diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp
index 9708ea7..e297ee7 100644
--- a/soundtrigger/SoundTrigger.cpp
+++ b/soundtrigger/SoundTrigger.cpp
@@ -204,39 +204,42 @@
 void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory)
 {
     Mutex::Autolock _l(mLock);
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         return;
     }
 
     if (mCallback != 0) {
+        // Memory is coming from a trusted process.
         mCallback->onRecognitionEvent(
-                (struct sound_trigger_recognition_event *)eventMemory->pointer());
+                (struct sound_trigger_recognition_event *)eventMemory->unsecurePointer());
     }
 }
 
 void SoundTrigger::onSoundModelEvent(const sp<IMemory>& eventMemory)
 {
     Mutex::Autolock _l(mLock);
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         return;
     }
 
     if (mCallback != 0) {
+        // Memory is coming from a trusted process.
         mCallback->onSoundModelEvent(
-                (struct sound_trigger_model_event *)eventMemory->pointer());
+                (struct sound_trigger_model_event *)eventMemory->unsecurePointer());
     }
 }
 
 void SoundTrigger::onServiceStateChange(const sp<IMemory>& eventMemory)
 {
     Mutex::Autolock _l(mLock);
-    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
+    if (eventMemory == 0 || eventMemory->unsecurePointer() == NULL) {
         return;
     }
 
     if (mCallback != 0) {
+        // Memory is coming from a trusted process.
         mCallback->onServiceStateChange(
-                *((sound_trigger_service_state_t *)eventMemory->pointer()));
+                *((sound_trigger_service_state_t *)eventMemory->unsecurePointer()));
     }
 }