Merge "gralloc: name codec buffer at allocation time"
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index 8f60bb2..ec8f049 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -49,7 +49,7 @@
 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.
-# Add /apex/... pat to the permitted paths because linker uses realpath(3)
+# Add /apex/... path to the permitted paths because linker uses realpath(3)
 # to check the accessibility of the lib. We could add this to search.paths
 # instead but that makes the resolution of bionic libs be dependent on
 # the order of /system/lib and /apex/... in search.paths. If /apex/...
@@ -136,3 +136,9 @@
 
 # Add a link for libz.so which is llndk on devices where VNDK is not enforced.
 namespace.sphal.link.platform.shared_libs += libz.so
+
+# With VNDK APEX, /system/${LIB}/vndk-sp${VNDK_VER} is a symlink to the following.
+# Add /apex/... path to the permitted paths because linker uses realpath(3)
+# to check the accessibility of the lib.
+namespace.sphal.permitted.paths += /apex/com.android.vndk.${VNDK_APEX_VER}/${LIB}
+namespace.sphal.asan.permitted.paths += /apex/com.android.vndk.${VNDK_APEX_VER}/${LIB}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 334f879..320c499 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -17,6 +17,10 @@
 
     srcs: ["main_cameraserver.cpp"],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libcameraservice",
         "liblog",
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index d24cb81..46a8dae 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -29,7 +29,7 @@
 #include "ACameraCaptureSession.inc"
 
 ACameraDevice::~ACameraDevice() {
-    mDevice->stopLooper();
+    mDevice->stopLooperAndDisconnect();
 }
 
 namespace android {
@@ -112,19 +112,7 @@
     }
 }
 
-// Device close implementaiton
-CameraDevice::~CameraDevice() {
-    sp<ACameraCaptureSession> session = mCurrentSession.promote();
-    {
-        Mutex::Autolock _l(mDeviceLock);
-        if (!isClosed()) {
-            disconnectLocked(session);
-        }
-        LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
-                "CameraDevice looper should've been stopped before ~CameraDevice");
-        mCurrentSession = nullptr;
-    }
-}
+CameraDevice::~CameraDevice() { }
 
 void
 CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
@@ -892,8 +880,14 @@
     return;
 }
 
-void CameraDevice::stopLooper() {
+void CameraDevice::stopLooperAndDisconnect() {
     Mutex::Autolock _l(mDeviceLock);
+    sp<ACameraCaptureSession> session = mCurrentSession.promote();
+    if (!isClosed()) {
+        disconnectLocked(session);
+    }
+    mCurrentSession = nullptr;
+
     if (mCbLooper != nullptr) {
       mCbLooper->unregisterHandler(mHandler->id());
       mCbLooper->stop();
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 7a35bf0..6c2ceb3 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -40,6 +40,7 @@
 
 #include <camera/NdkCameraManager.h>
 #include <camera/NdkCameraCaptureSession.h>
+
 #include "ACameraMetadata.h"
 
 namespace android {
@@ -110,7 +111,7 @@
     inline ACameraDevice* getWrapper() const { return mWrapper; };
 
     // Stop the looper thread and unregister the handler
-    void stopLooper();
+    void stopLooperAndDisconnect();
 
   private:
     friend ACameraCaptureSession;
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 68fe045..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>
@@ -1734,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,
 
     /**
@@ -7002,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
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 35c8355..e511a3f 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -45,7 +45,7 @@
 using namespace android;
 
 ACameraDevice::~ACameraDevice() {
-    mDevice->stopLooper();
+    mDevice->stopLooperAndDisconnect();
 }
 
 namespace android {
@@ -125,19 +125,7 @@
     }
 }
 
-// Device close implementaiton
-CameraDevice::~CameraDevice() {
-    sp<ACameraCaptureSession> session = mCurrentSession.promote();
-    {
-        Mutex::Autolock _l(mDeviceLock);
-        if (!isClosed()) {
-            disconnectLocked(session);
-        }
-        mCurrentSession = nullptr;
-        LOG_ALWAYS_FATAL_IF(mCbLooper != nullptr,
-            "CameraDevice looper should've been stopped before ~CameraDevice");
-    }
-}
+CameraDevice::~CameraDevice() { }
 
 void
 CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
@@ -1388,6 +1376,7 @@
             // before cbh goes out of scope and causing we call the session
             // destructor while holding device lock
             cbh.mSession.clear();
+
             postSessionMsgAndCleanup(msg);
         }
 
@@ -1400,8 +1389,13 @@
     }
 }
 
-void CameraDevice::stopLooper() {
+void CameraDevice::stopLooperAndDisconnect() {
     Mutex::Autolock _l(mDeviceLock);
+    sp<ACameraCaptureSession> session = mCurrentSession.promote();
+    if (!isClosed()) {
+        disconnectLocked(session);
+    }
+    mCurrentSession = nullptr;
     if (mCbLooper != nullptr) {
       mCbLooper->unregisterHandler(mHandler->id());
       mCbLooper->stop();
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 9e034c4..7fc699e 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -36,6 +36,7 @@
 
 #include <camera/NdkCameraManager.h>
 #include <camera/NdkCameraCaptureSession.h>
+
 #include "ACameraMetadata.h"
 #include "utils.h"
 
@@ -134,7 +135,7 @@
     inline ACameraDevice* getWrapper() const { return mWrapper; };
 
     // Stop the looper thread and unregister the handler
-    void stopLooper();
+    void stopLooperAndDisconnect();
 
   private:
     friend ACameraCaptureSession;
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index cc43b61..defc94f 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -3,6 +3,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=       \
+        AudioPlayer.cpp \
         stagefright.cpp \
         jpeg.cpp        \
         SineSource.cpp
@@ -10,7 +11,7 @@
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libmedia libmedia_codeclist libutils libbinder \
         libstagefright_foundation libjpeg libui libgui libcutils liblog \
-        libhidlbase libdatasource \
+        libhidlbase libdatasource libaudioclient \
         android.hardware.media.omx@1.0 \
 
 LOCAL_C_INCLUDES:= \
@@ -31,12 +32,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
+        AudioPlayer.cpp \
         SineSource.cpp    \
         record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libmedia liblog libutils libbinder \
-        libstagefright_foundation libdatasource
+        libstagefright_foundation libdatasource libaudioclient
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/camera/include \
@@ -57,12 +59,12 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
-        SineSource.cpp    \
+        AudioPlayer.cpp \
         recordvideo.cpp
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libmedia liblog libutils libbinder \
-        libstagefright_foundation
+        libstagefright_foundation libaudioclient
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
@@ -83,12 +85,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=         \
+        AudioPlayer.cpp \
         SineSource.cpp    \
         audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libmedia liblog libutils libbinder \
-        libstagefright_foundation
+        libstagefright_foundation libaudioclient
 
 LOCAL_C_INCLUDES:= \
         frameworks/av/media/libstagefright \
diff --git a/media/libstagefright/AudioPlayer.cpp b/cmds/stagefright/AudioPlayer.cpp
similarity index 99%
rename from media/libstagefright/AudioPlayer.cpp
rename to cmds/stagefright/AudioPlayer.cpp
index 199b57b..208713d 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/cmds/stagefright/AudioPlayer.cpp
@@ -28,12 +28,13 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALookup.h>
 #include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
+#include "AudioPlayer.h"
+
 namespace android {
 
 AudioPlayer::AudioPlayer(
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/cmds/stagefright/AudioPlayer.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/AudioPlayer.h
rename to cmds/stagefright/AudioPlayer.h
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index d4f2e8d..bd274d8 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -29,11 +29,11 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/AMRWriter.h>
-#include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/SimpleDecodingSource.h>
+#include "AudioPlayer.h"
 #include "SineSource.h"
 
 using namespace android;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 498237d..37091c4 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -21,7 +21,6 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
@@ -33,6 +32,8 @@
 #include <media/stagefright/SimpleDecodingSource.h>
 #include <media/MediaPlayerInterface.h>
 
+#include "AudioPlayer.h"
+
 using namespace android;
 
 static const int32_t kAudioBitRate = 12200;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index a63b9b9..01a178e 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "SineSource.h"
-
 #include <inttypes.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -25,8 +23,8 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaCodecSource.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 58e3f2c..e8cfece 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -40,7 +40,6 @@
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/InterfaceUtils.h>
 #include <media/stagefright/MediaCodec.h>
@@ -67,6 +66,8 @@
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
 
+#include "AudioPlayer.h"
+
 using namespace android;
 
 static long gNumRepetitions;
@@ -303,7 +304,7 @@
             seekTimeUs = -1;
 
             if (shouldSeek) {
-                seekTimeUs = (rand() * (float)durationUs) / RAND_MAX;
+                seekTimeUs = (rand() * (float)durationUs) / (float)RAND_MAX;
                 options.setSeekTo(seekTimeUs);
 
                 printf("seeking to %" PRId64 " us (%.2f secs)\n",
@@ -1084,7 +1085,7 @@
         const char *filename = argv[k];
 
         sp<DataSource> dataSource =
-            DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+            DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, filename);
 
         if (strncasecmp(filename, "sine:", 5) && dataSource == NULL) {
             fprintf(stderr, "Unable to create data source.\n");
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 8cc0e81..fe613a8 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -164,7 +164,7 @@
     : mCurrentBufferIndex(-1),
       mCurrentBufferOffset(0) {
     sp<DataSource> dataSource =
-        DataSourceFactory::CreateFromURI(NULL /* httpService */, filename);
+        DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, filename);
 
     CHECK(dataSource != NULL);
 
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 66610b3..e2ea83a 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -59,7 +59,6 @@
     IDrmEngine& engine = mPlugInManager.getPlugIn(plugInId);
 
     std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("drmmanager"));
-    item->generateSessionID();
     item->setUid(IPCThreadState::self()->getCallingUid());
     item->setCString("function_name", func);
     item->setCString("plugin_id", plugInId.getPathLeaf().getBasePath().c_str());
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 8507729..b3fd7e9 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -24,6 +24,7 @@
         "SharedLibrary.cpp",
         "DrmHal.cpp",
         "CryptoHal.cpp",
+        "DrmUtils.cpp",
     ],
 
     local_include_dirs: [
@@ -35,6 +36,10 @@
         "include"
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libbinder",
         "libcutils",
@@ -54,6 +59,12 @@
         "libhidlbase",
     ],
 
+    export_shared_lib_headers: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.2",
+    ],
+
     cflags: [
         "-Werror",
         "-Wall",
@@ -77,6 +88,9 @@
         export_proto_headers: true,
         type: "lite",
     },
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
@@ -112,6 +126,9 @@
         export_proto_headers: true,
         type: "full",
     },
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.1",
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index 58110d4..6a0e75e 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -118,7 +118,6 @@
 CryptoHal::CryptoHal()
     : mFactories(makeCryptoFactories()),
       mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT),
-      mNextBufferId(0),
       mHeapSeqNum(0) {
 }
 
@@ -260,17 +259,18 @@
     using ::android::hardware::fromHeap;
     using ::android::hardware::HidlMemory;
 
-    if (heap == NULL) {
-        ALOGE("setHeapBase(): heap is NULL");
+    if (heap == NULL || mHeapSeqNum < 0) {
+        ALOGE("setHeapBase(): heap %p mHeapSeqNum %d", heap.get(), mHeapSeqNum);
         return -1;
     }
 
     Mutex::Autolock autoLock(mLock);
 
     int32_t seqNum = mHeapSeqNum++;
+    uint32_t bufferId = static_cast<uint32_t>(seqNum);
     sp<HidlMemory> hidlMemory = fromHeap(heap);
-    mHeapBases.add(seqNum, HeapBase(mNextBufferId, heap->getSize()));
-    Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, mNextBufferId++);
+    mHeapBases.add(seqNum, HeapBase(bufferId, heap->getSize()));
+    Return<void> hResult = mPlugin->setSharedBufferBase(*hidlMemory, bufferId);
     ALOGE_IF(!hResult.isOk(), "setSharedBufferBase(): remote call failed");
     return seqNum;
 }
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index bd4b521..40077f9 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -25,6 +25,7 @@
 
 #include <android/hardware/drm/1.2/types.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
+#include <android/media/BnResourceManagerClient.h>
 #include <hidl/ServiceManagement.h>
 #include <media/EventMetric.h>
 #include <media/PluginMetricsReporting.h>
@@ -38,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;
@@ -295,21 +298,43 @@
 
 Mutex DrmHal::mLock;
 
-bool DrmHal::DrmSessionClient::reclaimResource() {
+struct DrmHal::DrmSessionClient : public android::media::BnResourceManagerClient {
+    explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
+      : mSessionId(sessionId),
+        mDrm(drm) {}
+
+    ::android::binder::Status reclaimResource(bool* _aidl_return) override;
+    ::android::binder::Status getName(::std::string* _aidl_return) override;
+
+    const Vector<uint8_t> mSessionId;
+
+protected:
+    virtual ~DrmSessionClient();
+
+private:
+    wp<DrmHal> mDrm;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
+};
+
+::android::binder::Status DrmHal::DrmSessionClient::reclaimResource(bool* _aidl_return) {
     sp<DrmHal> drm = mDrm.promote();
     if (drm == NULL) {
-        return true;
+        *_aidl_return = true;
+        return ::android::binder::Status::ok();
     }
     status_t err = drm->closeSession(mSessionId);
     if (err != OK) {
-        return false;
+        *_aidl_return = false;
+        return ::android::binder::Status::ok();
     }
     drm->sendEvent(EventType::SESSION_RECLAIMED,
             toHidlVec(mSessionId), hidl_vec<uint8_t>());
-    return true;
+    *_aidl_return = true;
+    return ::android::binder::Status::ok();
 }
 
-String8 DrmHal::DrmSessionClient::getName() {
+::android::binder::Status DrmHal::DrmSessionClient::getName(::std::string* _aidl_return) {
     String8 name;
     sp<DrmHal> drm = mDrm.promote();
     if (drm == NULL) {
@@ -323,7 +348,8 @@
         name.appendFormat("%02x", mSessionId[i]);
     }
     name.append("]");
-    return name;
+    *_aidl_return = name;
+    return ::android::binder::Status::ok();
 }
 
 DrmHal::DrmSessionClient::~DrmSessionClient() {
@@ -472,10 +498,6 @@
     mEventLock.unlock();
 
     if (listener != NULL) {
-        Parcel obj;
-        writeByteArray(obj, sessionId);
-        writeByteArray(obj, data);
-
         Mutex::Autolock lock(mNotifyLock);
         DrmPlugin::EventType eventType;
         switch(hEventType) {
@@ -497,7 +519,7 @@
         default:
             return Void();
         }
-        listener->notify(eventType, 0, &obj);
+        listener->sendEvent(eventType, sessionId, data);
     }
     return Void();
 }
@@ -510,12 +532,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();
 }
@@ -532,21 +550,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:
@@ -569,19 +583,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);
         }
     }
 
@@ -596,10 +609,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();
 }
@@ -899,9 +910,8 @@
 status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
         Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
     Mutex::Autolock autoLock(mLock);
-    EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
-
     INIT_CHECK();
+    EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
 
     DrmSessionManager::Instance()->useSession(sessionId);
 
@@ -1562,20 +1572,9 @@
     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());
     String8 vendor;
     String8 description;
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 0b927ef..165a4d6 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -18,12 +18,14 @@
 #define LOG_TAG "DrmSessionManager"
 #include <utils/Log.h>
 
+#include <android/media/IResourceManagerClient.h>
+#include <android/media/IResourceManagerService.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IProcessInfoService.h>
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
-#include <media/IResourceManagerClient.h>
 #include <media/MediaResource.h>
+#include <mediadrm/DrmUtils.h>
 #include <mediadrm/DrmSessionManager.h>
 #include <unistd.h>
 #include <utils/String8.h>
@@ -33,6 +35,7 @@
 #include "ResourceManagerService.h"
 
 namespace android {
+using android::binder::Status;
 
 static String8 GetSessionIdString(const Vector<uint8_t> &sessionId) {
     String8 sessionIdStr;
@@ -52,16 +55,17 @@
     return reinterpret_cast<int64_t>(drm.get());
 }
 
-static Vector<MediaResource> toResourceVec(const Vector<uint8_t> &sessionId) {
-    Vector<MediaResource> resources;
-    // use UINT64_MAX to decrement through addition overflow
-    resources.push_back(MediaResource(MediaResource::kDrmSession, toStdVec(sessionId), UINT64_MAX));
+static std::vector<MediaResourceParcel> toResourceVec(
+        const Vector<uint8_t> &sessionId, int64_t value) {
+    std::vector<MediaResourceParcel> resources;
+    resources.push_back(MediaResource::DrmSessionResource(toStdVec(sessionId), value));
     return resources;
 }
 
 static sp<IResourceManagerService> getResourceManagerService() {
-    if (property_get_bool("persist.device_config.media_native.mediadrmserver", 1)) {
-        return new ResourceManagerService();
+    if (DrmUtils::UseDrmService()) {
+        // Create ResourceManagerService object in mediadrmserver process
+        return new android::media::ResourceManagerService();
     }
     sp<IServiceManager> sm = defaultServiceManager();
     if (sm == NULL) {
@@ -131,7 +135,7 @@
 
     int64_t clientId = toClientId(drm);
     mSessionMap[toStdVec(sessionId)] = (SessionInfo){pid, uid, clientId};
-    mService->addResource(pid, uid, clientId, drm, toResourceVec(sessionId));
+    mService->addResource(pid, uid, clientId, drm, toResourceVec(sessionId, INT64_MAX));
 }
 
 void DrmSessionManager::useSession(const Vector<uint8_t> &sessionId) {
@@ -144,7 +148,7 @@
     }
 
     auto info = it->second;
-    mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId));
+    mService->addResource(info.pid, info.uid, info.clientId, NULL, toResourceVec(sessionId, -1));
 }
 
 void DrmSessionManager::removeSession(const Vector<uint8_t> &sessionId) {
@@ -157,7 +161,7 @@
     }
 
     auto info = it->second;
-    mService->removeResource(info.pid, info.clientId, toResourceVec(sessionId));
+    mService->removeResource(info.pid, info.clientId, toResourceVec(sessionId, INT64_MAX));
     mSessionMap.erase(it);
 }
 
@@ -176,7 +180,9 @@
     // cannot update mSessionMap because we do not know which sessionId is reclaimed;
     // we rely on IResourceManagerClient to removeSession in reclaimResource
     Vector<uint8_t> dummy;
-    return service->reclaimResource(callingPid, toResourceVec(dummy));
+    bool success;
+    Status status = service->reclaimResource(callingPid, toResourceVec(dummy, INT64_MAX), &success);
+    return status.isOk() && success;
 }
 
 size_t DrmSessionManager::getSessionCount() const {
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
new file mode 100644
index 0000000..7cc1697
--- /dev/null
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmUtils"
+
+#include <utils/String16.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.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>
+#include <mediadrm/IMediaDrmService.h>
+
+namespace android {
+namespace DrmUtils {
+
+namespace {
+template<typename Iface>
+sp<Iface> MakeObjectWithService(status_t *pstatus) {
+    status_t err = OK;
+    status_t &status = pstatus ? *pstatus : err;
+    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;
+        return NULL;
+    }
+
+    auto obj = service->makeObject<Iface>();
+    if (obj == NULL) {
+        status = UNKNOWN_ERROR;
+        return NULL;
+    }
+
+    status = obj->initCheck();
+    if (status != OK && status != NO_INIT) {
+        return NULL;
+    }
+    return obj;
+}
+
+template<typename Iface, typename Hal>
+sp<Iface> MakeObject(status_t *pstatus) {
+    if (UseDrmService()) {
+        return MakeObjectWithService<Iface>(pstatus);
+    } else {
+        return new Hal();
+    }
+}
+} // namespace
+
+bool UseDrmService() {
+    return property_get_bool("persist.device_config.media_native.mediadrmserver", true);
+}
+
+sp<IDrm> MakeDrm(status_t *pstatus) {
+    return MakeObject<IDrm, DrmHal>(pstatus);
+}
+
+sp<ICrypto> MakeCrypto(status_t *pstatus) {
+    return MakeObject<ICrypto, CryptoHal>(pstatus);
+}
+
+}  // namespace DrmUtils
+}  // namespace android
diff --git a/drm/libmediadrm/IDrmClient.cpp b/drm/libmediadrm/IDrmClient.cpp
index 357de9d..2e05093 100644
--- a/drm/libmediadrm/IDrmClient.cpp
+++ b/drm/libmediadrm/IDrmClient.cpp
@@ -17,39 +17,104 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "IDrmClient"
-#include <utils/Log.h>
 
+#include <utils/Errors.h>
+#include <utils/Log.h>
 #include <utils/RefBase.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
+#include <hidl/HidlSupport.h>
 
 #include <media/IMediaPlayerClient.h>
+#include <mediadrm/DrmUtils.h>
 #include <mediadrm/IDrmClient.h>
 
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
 namespace android {
 
 enum {
-    NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+    SEND_EVENT = IBinder::FIRST_CALL_TRANSACTION,
+    SEND_EXPIRATION_UPDATE,
+    SEND_KEYS_CHANGE,
+    SEND_SESSION_LOST_STATE,
 };
 
+namespace {
+
+hardware::hidl_vec<uint8_t> ReadByteArray(const Parcel &obj, status_t *err)
+{
+    int32_t len = obj.readInt32();
+    hardware::hidl_vec<uint8_t> ret;
+    if (len < 0) {
+        ALOGE("Invalid array len");
+        *err = BAD_VALUE;
+        return ret;
+    }
+    ret.resize(static_cast<size_t>(len));
+    *err = obj.read(ret.data(), ret.size());
+    return ret;
+}
+
+}
+
 class BpDrmClient: public BpInterface<IDrmClient>
 {
+    template <typename F>
+    void notify(uint32_t code, F fillParcel) {
+        Parcel obj, reply;
+        obj.writeInterfaceToken(IDrmClient::getInterfaceDescriptor());
+        fillParcel(obj);
+        remote()->transact(code, obj, &reply, IBinder::FLAG_ONEWAY);
+    }
+
 public:
     explicit BpDrmClient(const sp<IBinder>& impl)
         : BpInterface<IDrmClient>(impl)
     {
     }
 
-    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj)
+    virtual void sendEvent(
+            DrmPlugin::EventType eventType,
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const hardware::hidl_vec<uint8_t> &data)
     {
-        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);
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteEventToParcel(p, eventType, sessionId, data);
+        };
+        notify(SEND_EVENT, fillParcel);
+    }
+
+    virtual void sendExpirationUpdate(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            int64_t expiryTimeInMS)
+    {
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteExpirationUpdateToParcel(p, sessionId, expiryTimeInMS);
+        };
+        notify(SEND_EXPIRATION_UPDATE, fillParcel);
+    }
+
+    virtual void sendKeysChange(
+            const hardware::hidl_vec<uint8_t> &sessionId,
+            const std::vector<DrmKeyStatus> &keyStatusList,
+            bool hasNewUsableKey)
+    {
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteKeysChange(p, sessionId, keyStatusList, hasNewUsableKey);
+        };
+        notify(SEND_KEYS_CHANGE, fillParcel);
+    }
+
+    virtual void sendSessionLostState(
+            const hardware::hidl_vec<uint8_t> &sessionId)
+    {
+        auto fillParcel = [&] (Parcel &p) {
+            DrmUtils::WriteByteArray(p, sessionId);
+        };
+        notify(SEND_SESSION_LOST_STATE, fillParcel);
     }
 };
 
@@ -58,23 +123,58 @@
 // ----------------------------------------------------------------------
 
 status_t BnDrmClient::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+    uint32_t code, const Parcel& obj, 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());
-            }
+    CHECK_INTERFACE(IDrmClient, obj, reply);
+    status_t err = NO_ERROR;
+    hardware::hidl_vec<uint8_t> sessionId(ReadByteArray(obj, &err));
+    if (err != NO_ERROR) {
+        ALOGE("Failed to read session id, error=%d", err);
+        return err;
+    }
 
-            notify((DrmPlugin::EventType)eventType, extra, &obj);
+    switch (code) {
+        case SEND_EVENT: {
+            hardware::hidl_vec<uint8_t> data(ReadByteArray(obj, &err));
+            int eventType = obj.readInt32();
+            if (err == NO_ERROR) {
+                sendEvent(static_cast<DrmPlugin::EventType>(eventType), sessionId, data);
+            }
+            return err;
+        } break;
+        case SEND_EXPIRATION_UPDATE: {
+            int64_t expiryTimeInMS = obj.readInt64();
+            sendExpirationUpdate(sessionId, expiryTimeInMS);
+            return NO_ERROR;
+        } break;
+        case SEND_KEYS_CHANGE: {
+            // ...
+            int32_t n = obj.readInt32();
+            if (n < 0) {
+                return BAD_VALUE;
+            }
+            std::vector<DrmKeyStatus> keyStatusList;
+            for (int32_t i = 0; i < n; ++i) {
+                hardware::hidl_vec<uint8_t> keyId(ReadByteArray(obj, &err));
+                if (err != NO_ERROR) {
+                    return err;
+                }
+                int32_t type = obj.readInt32();
+                if (type < 0) {
+                    return BAD_VALUE;
+                }
+                keyStatusList.push_back({static_cast<uint32_t>(type), keyId});
+            }
+            int32_t hasNewUsableKey = obj.readInt32();
+            sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+            return NO_ERROR;
+        } break;
+        case SEND_SESSION_LOST_STATE: {
+            sendSessionLostState(sessionId);
             return NO_ERROR;
         } break;
         default:
-            return BBinder::onTransact(code, data, reply, flags);
+            return BBinder::onTransact(code, obj, reply, flags);
     }
 }
 
diff --git a/drm/libmediadrm/IMediaDrmService.cpp b/drm/libmediadrm/IMediaDrmService.cpp
index f320d0b..0b650f2 100644
--- a/drm/libmediadrm/IMediaDrmService.cpp
+++ b/drm/libmediadrm/IMediaDrmService.cpp
@@ -85,4 +85,14 @@
 
 // ----------------------------------------------------------------------------
 
+template<>
+sp<IDrm> IMediaDrmService::makeObject<IDrm>() {
+    return makeDrm();
+}
+
+template<>
+sp<ICrypto> IMediaDrmService::makeObject<ICrypto>() {
+    return makeCrypto();
+}
+
 } // namespace android
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 8cd6f96..098f07b 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -35,8 +35,6 @@
                              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);
     if (metrics.size() > 0) {
@@ -44,7 +42,7 @@
     }
 
     if (!analyticsItem->selfrecord()) {
-      ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem->getSessionID());
+      ALOGE("%s: selfrecord() returned false", __func__);
     }
 
     return OK;
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
index 73c029f..9e61777 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHal.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -97,7 +97,6 @@
     };
 
     KeyedVector<int32_t, HeapBase> mHeapBases;
-    uint32_t mNextBufferId;
     int32_t mHeapSeqNum;
 
     Vector<sp<ICryptoFactory>> makeCryptoFactories();
diff --git a/drm/libmediadrm/include/mediadrm/DrmHal.h b/drm/libmediadrm/include/mediadrm/DrmHal.h
index 542d300..0431c93 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHal.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHal.h
@@ -26,7 +26,6 @@
 #include <android/hardware/drm/1.2/IDrmPlugin.h>
 #include <android/hardware/drm/1.2/IDrmPluginListener.h>
 
-#include <media/IResourceManagerService.h>
 #include <media/MediaAnalyticsItem.h>
 #include <mediadrm/DrmMetrics.h>
 #include <mediadrm/DrmSessionManager.h>
@@ -62,24 +61,7 @@
                 public IBinder::DeathRecipient,
                 public IDrmPluginListener_V1_2 {
 
-    struct DrmSessionClient : public BnResourceManagerClient {
-        explicit DrmSessionClient(DrmHal* drm, const Vector<uint8_t>& sessionId)
-          : mSessionId(sessionId),
-            mDrm(drm) {}
-
-        virtual bool reclaimResource();
-        virtual String8 getName();
-
-        const Vector<uint8_t> mSessionId;
-
-    protected:
-        virtual ~DrmSessionClient();
-
-    private:
-        wp<DrmHal> mDrm;
-
-        DISALLOW_EVIL_CONSTRUCTORS(DrmSessionClient);
-    };
+    struct DrmSessionClient;
 
     DrmHal();
     virtual ~DrmHal();
diff --git a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
index b1ad580..3258f7a 100644
--- a/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
+++ b/drm/libmediadrm/include/mediadrm/DrmSessionManager.h
@@ -19,7 +19,6 @@
 #define DRM_SESSION_MANAGER_H_
 
 #include <binder/IBinder.h>
-#include <media/IResourceManagerService.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/RefBase.h>
 #include <utils/KeyedVector.h>
@@ -33,7 +32,13 @@
 namespace android {
 
 class DrmSessionManagerTest;
+
+namespace media {
 class IResourceManagerClient;
+class IResourceManagerService;
+}
+using android::media::IResourceManagerClient;
+using android::media::IResourceManagerService;
 
 bool isEqualSessionId(const Vector<uint8_t> &sessionId1, const Vector<uint8_t> &sessionId2);
 
diff --git a/drm/libmediadrm/include/mediadrm/IDrmClient.h b/drm/libmediadrm/include/mediadrm/IDrmClient.h
index 3b2fc7c..f8f2b25 100644
--- a/drm/libmediadrm/include/mediadrm/IDrmClient.h
+++ b/drm/libmediadrm/include/mediadrm/IDrmClient.h
@@ -22,14 +22,41 @@
 #include <binder/Parcel.h>
 #include <media/drm/DrmAPI.h>
 
+#include <android/hardware/drm/1.2/types.h>
+#include <hidl/HidlSupport.h>
+
+#include <cstdint>
+#include <vector>
+
 namespace android {
 
+struct DrmKeyStatus {
+    const uint32_t type;
+    const hardware::hidl_vec<uint8_t> keyId;
+};
+
 class IDrmClient: public IInterface
 {
 public:
     DECLARE_META_INTERFACE(DrmClient);
 
-    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) = 0;
+    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;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/drm/libmediadrm/include/mediadrm/IMediaDrmService.h b/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
index 323fae5..7dcce94 100644
--- a/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
+++ b/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
@@ -33,8 +33,12 @@
 public:
     DECLARE_META_INTERFACE(MediaDrmService);
 
+
     virtual sp<ICrypto>         makeCrypto() = 0;
     virtual sp<IDrm>            makeDrm() = 0;
+
+    template<typename I> sp<I>  makeObject();
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
new file mode 100644
index 0000000..a5bc09b
--- /dev/null
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -0,0 +1,84 @@
+/*
+ * 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 <utils/Errors.h>  // for status_t
+#include <utils/StrongPointer.h>
+#include <binder/Parcel.h>
+
+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);
+}
+
+} // namespace DrmUtils
+
+} // namespace android
+
+#endif // ANDROID_DRMUTILS_H
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index 873083b..2e39943 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -3,8 +3,8 @@
 cc_test {
     name: "CounterMetric_test",
     srcs: ["CounterMetric_test.cpp"],
+    header_libs: ["libmedia_headers"],
     shared_libs: ["libmediadrm"],
-    include_dirs: ["frameworks/av/include/media"],
     cflags: [
       "-Werror",
       "-Wall",
@@ -14,6 +14,9 @@
 cc_test {
     name: "DrmMetrics_test",
     srcs: ["DrmMetrics_test.cpp"],
+    header_libs: [
+        "libmedia_headers"
+    ],
     shared_libs: [
       "android.hardware.drm@1.0",
       "android.hardware.drm@1.1",
@@ -29,7 +32,6 @@
     static_libs: ["libgmock"],
     include_dirs: [
       "frameworks/av/drm/libmediadrm/include",
-      "frameworks/av/include/media",
     ],
     cflags: [
         // Suppress unused parameter and no error options. These cause problems
@@ -41,12 +43,14 @@
 cc_test {
     name: "EventMetric_test",
     srcs: ["EventMetric_test.cpp"],
+    header_libs: [
+        "libmedia_headers"
+    ],
     shared_libs: [
       "liblog",
       "libmediadrm",
       "libutils",
     ],
-    include_dirs: ["frameworks/av/include/media"],
     cflags: [
       "-Werror",
       "-Wall",
diff --git a/drm/libmediadrm/tests/CounterMetric_test.cpp b/drm/libmediadrm/tests/CounterMetric_test.cpp
index 6bca0da..c2becb4 100644
--- a/drm/libmediadrm/tests/CounterMetric_test.cpp
+++ b/drm/libmediadrm/tests/CounterMetric_test.cpp
@@ -16,7 +16,7 @@
 
 #include <gtest/gtest.h>
 
-#include "CounterMetric.h"
+#include <media/CounterMetric.h>
 
 namespace android {
 
diff --git a/drm/libmediadrm/tests/EventMetric_test.cpp b/drm/libmediadrm/tests/EventMetric_test.cpp
index eb6c4f6..b3c3f62 100644
--- a/drm/libmediadrm/tests/EventMetric_test.cpp
+++ b/drm/libmediadrm/tests/EventMetric_test.cpp
@@ -16,7 +16,7 @@
 
 #include <gtest/gtest.h>
 
-#include "EventMetric.h"
+#include <media/EventMetric.h>
 
 namespace android {
 
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index bf35224..af7c367 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -97,7 +97,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 ClearKeyCasPlugin::ClearKeyCasPlugin(
         void *appData, CasPluginCallback callback)
-    : mCallback(callback), mCallbackExt(NULL), mAppData(appData) {
+    : mCallback(callback), mCallbackExt(NULL), mStatusCallback(NULL),
+    mAppData(appData) {
     ALOGV("CTOR");
 }
 
@@ -112,6 +113,13 @@
     ClearKeySessionLibrary::get()->destroyPlugin(this);
 }
 
+status_t ClearKeyCasPlugin::setStatusCallback(
+    CasPluginStatusCallback callback) {
+    ALOGV("setStatusCallback");
+    mStatusCallback = callback;
+    return OK;
+}
+
 status_t ClearKeyCasPlugin::setPrivateData(const CasData &/*data*/) {
     ALOGV("setPrivateData");
 
@@ -135,6 +143,19 @@
     return ClearKeySessionLibrary::get()->addSession(this, sessionId);
 }
 
+status_t ClearKeyCasPlugin::openSession(uint32_t intent, uint32_t mode,
+    CasSessionId* sessionId) {
+    ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+    // Echo the received information to the callback.
+    // Clear key plugin doesn't use any event, echo'ing for testing only.
+    if (mStatusCallback != NULL) {
+        mStatusCallback((void*)mAppData, intent, mode);
+    }
+
+    // Clear key plugin doesn't use intent and mode.
+    return ClearKeySessionLibrary::get()->addSession(this, sessionId);
+}
+
 status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
     ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
     std::shared_ptr<ClearKeyCasSession> session =
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index f48d5b1..c6938e6 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -71,11 +71,17 @@
     ClearKeyCasPlugin(void *appData, CasPluginCallbackExt callback);
     virtual ~ClearKeyCasPlugin();
 
+    virtual status_t setStatusCallback(
+            CasPluginStatusCallback callback) override;
+
     virtual status_t setPrivateData(
             const CasData &data) override;
 
     virtual status_t openSession(CasSessionId *sessionId) override;
 
+    virtual status_t openSession(uint32_t intent, uint32_t mode,
+                                     CasSessionId *sessionId) override;
+
     virtual status_t closeSession(
             const CasSessionId &sessionId) override;
 
@@ -105,6 +111,7 @@
     std::unique_ptr<KeyFetcher> mKeyFetcher;
     CasPluginCallback mCallback;
     CasPluginCallbackExt mCallbackExt;
+    CasPluginStatusCallback mStatusCallback;
     void* mAppData;
 };
 
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 2964791..f8bab0a 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -111,6 +111,12 @@
     MockSessionLibrary::get()->destroyPlugin(this);
 }
 
+status_t MockCasPlugin::setStatusCallback(
+    CasPluginStatusCallback /*callback*/) {
+    ALOGV("setStatusCallback");
+    return OK;
+}
+
 status_t MockCasPlugin::setPrivateData(const CasData& /*data*/) {
     ALOGV("setPrivateData");
     return OK;
@@ -121,6 +127,13 @@
     return MockSessionLibrary::get()->addSession(this, sessionId);
 }
 
+status_t MockCasPlugin::openSession(uint32_t intent, uint32_t mode,
+    CasSessionId* sessionId) {
+    ALOGV("openSession with intent=%d, mode=%d", intent, mode);
+    // Clear key plugin doesn't use intent and mode.
+    return MockSessionLibrary::get()->addSession(this, sessionId);
+}
+
 status_t MockCasPlugin::closeSession(const CasSessionId &sessionId) {
     ALOGV("closeSession: sessionId=%s", arrayToString(sessionId).string());
     Mutex::Autolock lock(mLock);
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.h b/drm/mediacas/plugins/mock/MockCasPlugin.h
index 74b540c..660fd44 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.h
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.h
@@ -65,11 +65,17 @@
     MockCasPlugin();
     virtual ~MockCasPlugin();
 
+    virtual status_t setStatusCallback(
+            CasPluginStatusCallback callback) override;
+
     virtual status_t setPrivateData(
             const CasData &data) override;
 
     virtual status_t openSession(CasSessionId *sessionId) override;
 
+    virtual status_t openSession(uint32_t intent, uint32_t mode,
+                                     CasSessionId *sessionId) override;
+
     virtual status_t closeSession(
             const CasSessionId &sessionId) override;
 
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/include/media/CounterMetric.h b/include/media/CounterMetric.h
deleted file mode 120000
index baba043..0000000
--- a/include/media/CounterMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/CounterMetric.h
\ No newline at end of file
diff --git a/include/media/EventMetric.h b/include/media/EventMetric.h
deleted file mode 120000
index 5707d9a..0000000
--- a/include/media/EventMetric.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/EventMetric.h
\ No newline at end of file
diff --git a/include/media/IDataSource.h b/include/media/IDataSource.h
deleted file mode 120000
index 41cdd8b..0000000
--- a/include/media/IDataSource.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IDataSource.h
\ No newline at end of file
diff --git a/include/media/IMediaLogService.h b/include/media/IMediaLogService.h
deleted file mode 120000
index 245a29d..0000000
--- a/include/media/IMediaLogService.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaLogService.h
\ No newline at end of file
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
deleted file mode 120000
index b6547ce..0000000
--- a/include/media/IMediaPlayerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaPlayerClient.h
\ No newline at end of file
diff --git a/include/media/IMediaRecorderClient.h b/include/media/IMediaRecorderClient.h
deleted file mode 120000
index 89f4359..0000000
--- a/include/media/IMediaRecorderClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/IMediaRecorderClient.h
\ No newline at end of file
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
deleted file mode 120000
index 504173e..0000000
--- a/include/media/MemoryLeakTrackUtil.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MemoryLeakTrackUtil.h
\ No newline at end of file
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
deleted file mode 120000
index e421168..0000000
--- a/include/media/Metadata.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Metadata.h
\ No newline at end of file
diff --git a/include/media/MidiIoWrapper.h b/include/media/MidiIoWrapper.h
deleted file mode 120000
index 786ec3d..0000000
--- a/include/media/MidiIoWrapper.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/MidiIoWrapper.h
\ No newline at end of file
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
deleted file mode 120000
index 989c4cb..0000000
--- a/include/media/Modulo.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/Modulo.h
\ No newline at end of file
diff --git a/include/media/PluginMetricsReporting.h b/include/media/PluginMetricsReporting.h
deleted file mode 120000
index 7d9a7a0..0000000
--- a/include/media/PluginMetricsReporting.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/PluginMetricsReporting.h
\ No newline at end of file
diff --git a/include/media/RingBuffer.h b/include/media/RingBuffer.h
deleted file mode 120000
index 9af28d5..0000000
--- a/include/media/RingBuffer.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmedia/include/media/RingBuffer.h
\ No newline at end of file
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 3f3ef69..5484613 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -6,10 +6,10 @@
     capabilities BLOCK_SUSPEND
     ioprio rt 4
     writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
-    onrestart restart vendor.audio-hal-2-0
+    onrestart restart vendor.audio-hal
     onrestart restart vendor.audio-hal-4-0-msd
-    # Keep the original service name for backward compatibility when upgrading
-    # O-MR1 devices with framework-only.
+    # Keep the original service names for backward compatibility
+    onrestart restart vendor.audio-hal-2-0
     onrestart restart audio-hal-2-0
 
 on property:vts.native_server.on=1
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 84ce172..1947656 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -38,7 +38,7 @@
     static constexpr int64_t kLogDurationUs = 5000000; // 5 secs
 
     static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
-    static constexpr size_t kMinBufferCountForEviction = 40;
+    static constexpr size_t kMinBufferCountForEviction = 25;
 }
 
 // Buffer structure in bufferpool process
@@ -723,8 +723,8 @@
                   mStats.mTotalFetches, mStats.mTotalTransfers);
         }
         for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
-            if (!clearCache && mStats.mSizeCached < kMinAllocBytesForEviction
-                    && mBuffers.size() < kMinBufferCountForEviction) {
+            if (!clearCache && (mStats.mSizeCached < kMinAllocBytesForEviction
+                    || mBuffers.size() < kMinBufferCountForEviction)) {
                 break;
             }
             auto it = mBuffers.find(*freeIt);
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index a8f39d5..4db94f5 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -155,9 +155,7 @@
       mNumBytesPerInputFrame(0u),
       mOutBufferSize(0u),
       mSentCodecSpecificData(false),
-      mInputTimeSet(false),
       mInputSize(0),
-      mNextFrameTimestampUs(0),
       mSignalledError(false),
       mOutIndex(0u),
       mRemainderLen(0u) {
@@ -182,9 +180,9 @@
 
 c2_status_t C2SoftAacEnc::onStop() {
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mNextFrameTimestampUs = 0;
+    mNextFrameTimestampUs.reset();
+    mLastFrameEndTimestampUs.reset();
     mSignalledError = false;
     mRemainderLen = 0;
     return C2_OK;
@@ -201,9 +199,9 @@
 
 c2_status_t C2SoftAacEnc::onFlush_sm() {
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mNextFrameTimestampUs = 0;
+    mNextFrameTimestampUs.reset();
+    mLastFrameEndTimestampUs.reset();
     return C2_OK;
 }
 
@@ -366,9 +364,19 @@
         data = view.data();
         capacity = view.capacity();
     }
-    if (!mInputTimeSet && capacity > 0) {
-        mNextFrameTimestampUs = work->input.ordinal.timestamp;
-        mInputTimeSet = true;
+    c2_cntr64_t inputTimestampUs = work->input.ordinal.timestamp;
+    if (inputTimestampUs < mLastFrameEndTimestampUs.value_or(inputTimestampUs)) {
+        ALOGW("Correcting overlapping timestamp: last frame ended at %lldus but "
+              "current frame is starting at %lldus. Using the last frame's end timestamp",
+              mLastFrameEndTimestampUs->peekll(), inputTimestampUs.peekll());
+        inputTimestampUs = *mLastFrameEndTimestampUs;
+    }
+    if (capacity > 0) {
+        if (!mNextFrameTimestampUs) {
+            mNextFrameTimestampUs = work->input.ordinal.timestamp;
+        }
+        mLastFrameEndTimestampUs = inputTimestampUs
+                + (capacity / sizeof(int16_t) * 1000000ll / channelCount / sampleRate);
     }
 
     size_t numFrames =
@@ -376,8 +384,7 @@
         / mNumBytesPerInputFrame;
     ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu "
           "mNumBytesPerInputFrame = %u inputTS = %lld remaining = %zu",
-          capacity, mInputSize, numFrames,
-          mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll(),
+          capacity, mInputSize, numFrames, mNumBytesPerInputFrame, inputTimestampUs.peekll(),
           mRemainderLen);
 
     std::shared_ptr<C2LinearBlock> block;
@@ -505,8 +512,10 @@
                 mInputSize = 0;
                 int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
                         + outargs.numInSamples;
-                c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs;
-                mNextFrameTimestampUs = work->input.ordinal.timestamp
+                ALOGV("consumed = %d, capacity = %zu, inSamples = %d, outSamples = %d",
+                      consumed, capacity, inargs.numInSamples, outargs.numInSamples);
+                c2_cntr64_t currentFrameTimestampUs = *mNextFrameTimestampUs;
+                mNextFrameTimestampUs = inputTimestampUs
                         + (consumed * 1000000ll / channelCount / sampleRate);
                 std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
 #if 0
@@ -521,21 +530,19 @@
                 mInputSize += outargs.numInSamples * sizeof(int16_t);
             }
 
-            if (outargs.numInSamples > 0) {
-                inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples;
-                inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t);
-                inargs.numInSamples -= outargs.numInSamples;
-            }
-
             if (inBuffer[0] == mRemainder) {
                 inBuffer[0] = const_cast<uint8_t *>(data);
                 inBufferSize[0] = capacity;
                 inargs.numInSamples = capacity / sizeof(int16_t);
+            } else if (outargs.numInSamples > 0) {
+                inBuffer[0] = (int16_t *)inBuffer[0] + outargs.numInSamples;
+                inBufferSize[0] -= outargs.numInSamples * sizeof(int16_t);
+                inargs.numInSamples -= outargs.numInSamples;
             }
         }
         ALOGV("encoderErr = %d mInputSize = %zu "
               "inargs.numInSamples = %d, mNextFrameTimestampUs = %lld",
-              encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll());
+              encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs->peekll());
     }
     if (eos && inBufferSize[0] > 0) {
         if (numFrames && !block) {
@@ -619,9 +626,9 @@
 
     (void)pool;
     mSentCodecSpecificData = false;
-    mInputTimeSet = false;
     mInputSize = 0u;
-    mNextFrameTimestampUs = 0;
+    mNextFrameTimestampUs.reset();
+    mLastFrameEndTimestampUs.reset();
 
     // TODO: we don't have any pending work at this time to drain.
     return C2_OK;
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index 6ecfbdd..9a28280 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -18,6 +18,7 @@
 #define ANDROID_C2_SOFT_AAC_ENC_H_
 
 #include <atomic>
+#include <optional>
 
 #include <SimpleC2Component.h>
 
@@ -54,9 +55,9 @@
     UINT mOutBufferSize;
 
     bool mSentCodecSpecificData;
-    bool mInputTimeSet;
     size_t mInputSize;
-    c2_cntr64_t mNextFrameTimestampUs;
+    std::optional<c2_cntr64_t> mNextFrameTimestampUs;
+    std::optional<c2_cntr64_t> mLastFrameEndTimestampUs;
 
     bool mSignalledError;
     std::atomic_uint64_t mOutIndex;
diff --git a/media/codec2/components/cmds/codec2.cpp b/media/codec2/components/cmds/codec2.cpp
index e572a53..38eaf88 100644
--- a/media/codec2/components/cmds/codec2.cpp
+++ b/media/codec2/components/cmds/codec2.cpp
@@ -418,7 +418,7 @@
         const char *filename = argv[k];
 
         sp<DataSource> dataSource =
-            DataSourceFactory::CreateFromURI(nullptr /* httpService */, filename);
+            DataSourceFactory::getInstance()->CreateFromURI(nullptr /* httpService */, filename);
 
         if (strncasecmp(filename, "sine:", 5) && dataSource == nullptr) {
             fprintf(stderr, "Unable to create data source.\n");
diff --git a/media/codec2/components/g711/C2SoftG711Dec.cpp b/media/codec2/components/g711/C2SoftG711Dec.cpp
index b6cc32e..4ff0793 100644
--- a/media/codec2/components/g711/C2SoftG711Dec.cpp
+++ b/media/codec2/components/g711/C2SoftG711Dec.cpp
@@ -73,8 +73,8 @@
 
         addParameter(
                 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
-                .withDefault(new C2StreamChannelCountInfo::output(0u, 6))
-                .withFields({C2F(mChannelCount, value).equalTo(1)})
+                .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
+                .withFields({C2F(mChannelCount, value).inRange(1, 6)})
                 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
                 .build());
 
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 62076f8..c7d73f4 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -594,12 +594,10 @@
         }
     }
 
-    int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
-
     if (inSize) {
         uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
         vpx_codec_err_t err = vpx_codec_decode(
-                mCodecCtx, bitstream, inSize, &frameIndex, 0);
+                mCodecCtx, bitstream, inSize, &work->input.ordinal.frameIndex, 0);
         if (err != VPX_CODEC_OK) {
             ALOGE("on2 decoder failed to decode frame. err: %d", err);
             mSignalledError = true;
@@ -609,7 +607,20 @@
         }
     }
 
-    (void)outputBuffer(pool, work);
+    status_t err = outputBuffer(pool, work);
+    if (err == NOT_ENOUGH_DATA) {
+        if (inSize > 0) {
+            ALOGV("Maybe non-display frame at %lld.",
+                  work->input.ordinal.frameIndex.peekll());
+            // send the work back with empty buffer.
+            inSize = 0;
+        }
+    } else if (err != OK) {
+        ALOGD("Error while getting the output frame out");
+        // work->result would be already filled; do fillEmptyWork() below to
+        // send the work back.
+        inSize = 0;
+    }
 
     if (eos) {
         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
@@ -743,16 +754,16 @@
     }
     return;
 }
-bool C2SoftVpxDec::outputBuffer(
+status_t C2SoftVpxDec::outputBuffer(
         const std::shared_ptr<C2BlockPool> &pool,
         const std::unique_ptr<C2Work> &work)
 {
-    if (!(work && pool)) return false;
+    if (!(work && pool)) return BAD_VALUE;
 
     vpx_codec_iter_t iter = nullptr;
     vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
 
-    if (!img) return false;
+    if (!img) return NOT_ENOUGH_DATA;
 
     if (img->d_w != mWidth || img->d_h != mHeight) {
         mWidth = img->d_w;
@@ -769,7 +780,7 @@
             mSignalledError = true;
             work->workletsProcessed = 1u;
             work->result = C2_CORRUPTED;
-            return false;
+            return UNKNOWN_ERROR;
         }
 
     }
@@ -792,18 +803,19 @@
     if (err != C2_OK) {
         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
         work->result = err;
-        return false;
+        return UNKNOWN_ERROR;
     }
 
     C2GraphicView wView = block->map().get();
     if (wView.error()) {
         ALOGE("graphic view map failed %d", wView.error());
         work->result = C2_CORRUPTED;
-        return false;
+        return UNKNOWN_ERROR;
     }
 
-    ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
-           block->width(), block->height(), mWidth, mHeight, (int)*(int64_t *)img->user_priv);
+    ALOGV("provided (%dx%d) required (%dx%d), out frameindex %lld",
+           block->width(), block->height(), mWidth, mHeight,
+           ((c2_cntr64_t *)img->user_priv)->peekll());
 
     uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
     size_t srcYStride = img->stride[VPX_PLANE_Y];
@@ -859,8 +871,8 @@
                 dstYStride, dstUVStride,
                 mWidth, mHeight);
     }
-    finishWork(*(int64_t *)img->user_priv, work, std::move(block));
-    return true;
+    finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
+    return OK;
 }
 
 c2_status_t C2SoftVpxDec::drainInternal(
@@ -876,7 +888,7 @@
         return C2_OMITTED;
     }
 
-    while ((outputBuffer(pool, work))) {
+    while (outputBuffer(pool, work) == OK) {
     }
 
     if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index e51bcee..2065165 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -85,7 +85,7 @@
     status_t destroyDecoder();
     void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
                     const std::shared_ptr<C2GraphicBlock> &block);
-    bool outputBuffer(
+    status_t outputBuffer(
             const std::shared_ptr<C2BlockPool> &pool,
             const std::unique_ptr<C2Work> &work);
     c2_status_t drainInternal(
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 6dab70b..ebc7a8f 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -514,7 +514,7 @@
                         return;
                     }
                     vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
-                                 mStrideAlign, (uint8_t*)rView->data()[0]);
+                                 mStrideAlign, mConversionBuffer.data());
                     vpx_img_set_rect(&raw_frame, 0, 0, width, height);
                 } else {
                     ALOGE("Conversion buffer is too small: %u x %u for %zu",
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index a2930a6..4a9dc55 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",
     ],
 
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/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/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..6469735 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -547,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));
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index c620bad..c747190 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -125,6 +125,9 @@
         if (!mClient) {
             mClient = Codec2Client::_CreateFromIndex(mIndex);
         }
+        CHECK(mClient) << "Failed to create Codec2Client to service \""
+                       << GetServiceNames()[mIndex] << "\". (Index = "
+                       << mIndex << ").";
         return mClient;
     }
 
@@ -832,6 +835,7 @@
 
 c2_status_t Codec2Client::ForAllServices(
         const std::string &key,
+        size_t numberOfAttempts,
         std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
             predicate) {
     c2_status_t status = C2_NO_INIT;  // no IComponentStores present
@@ -860,23 +864,31 @@
 
     for (size_t index : indices) {
         Cache& cache = Cache::List()[index];
-        std::shared_ptr<Codec2Client> client{cache.getClient()};
-        if (client) {
+        for (size_t tries = numberOfAttempts; tries > 0; --tries) {
+            std::shared_ptr<Codec2Client> client{cache.getClient()};
             status = predicate(client);
             if (status == C2_OK) {
                 std::scoped_lock lock{key2IndexMutex};
                 key2Index[key] = index; // update last known client index
                 return C2_OK;
+            } else if (status == C2_TRANSACTION_FAILED) {
+                LOG(WARNING) << "\"" << key << "\" failed for service \""
+                             << client->getName()
+                             << "\" due to transaction failure. "
+                             << "(Service may have crashed.)"
+                             << (tries > 1 ? " Retrying..." : "");
+                cache.invalidate();
+                continue;
             }
-        }
-        if (wasMapped) {
-            LOG(INFO) << "Could not find \"" << key << "\""
-                         " in the last instance. Retrying...";
-            wasMapped = false;
-            cache.invalidate();
+            if (wasMapped) {
+                LOG(INFO) << "\"" << key << "\" became invalid in service \""
+                          << client->getName() << "\". Retrying...";
+                wasMapped = false;
+            }
+            break;
         }
     }
-    return status;  // return the last status from a valid client
+    return status; // return the last status from a valid client
 }
 
 std::shared_ptr<Codec2Client::Component>
@@ -885,35 +897,37 @@
         const std::shared_ptr<Listener>& listener,
         std::shared_ptr<Codec2Client>* owner,
         size_t numberOfAttempts) {
-    while (true) {
-        std::shared_ptr<Component> component;
-        c2_status_t status = ForAllServices(
-                componentName,
-                [owner, &component, componentName, &listener](
-                        const std::shared_ptr<Codec2Client> &client)
-                            -> c2_status_t {
-                    c2_status_t status = client->createComponent(componentName,
-                                                                 listener,
-                                                                 &component);
-                    if (status == C2_OK) {
-                        if (owner) {
-                            *owner = client;
-                        }
-                    } else if (status != C2_NOT_FOUND) {
-                        LOG(DEBUG) << "IComponentStore("
-                                       << client->getServiceName()
-                                   << ")::createComponent(\"" << componentName
-                                   << "\") returned status = "
-                                   << status << ".";
+    std::string key{"create:"};
+    key.append(componentName);
+    std::shared_ptr<Component> component;
+    c2_status_t status = ForAllServices(
+            key,
+            numberOfAttempts,
+            [owner, &component, componentName, &listener](
+                    const std::shared_ptr<Codec2Client> &client)
+                        -> c2_status_t {
+                c2_status_t status = client->createComponent(componentName,
+                                                             listener,
+                                                             &component);
+                if (status == C2_OK) {
+                    if (owner) {
+                        *owner = client;
                     }
-                    return status;
-                });
-        if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
-            --numberOfAttempts;
-            continue;
-        }
-        return component;
+                } else if (status != C2_NOT_FOUND) {
+                    LOG(DEBUG) << "IComponentStore("
+                                   << client->getServiceName()
+                               << ")::createComponent(\"" << componentName
+                               << "\") returned status = "
+                               << status << ".";
+                }
+                return status;
+            });
+    if (status != C2_OK) {
+        LOG(DEBUG) << "Failed to create component \"" << componentName
+                   << "\" from all known services. "
+                      "Last returned status = " << status << ".";
     }
+    return component;
 }
 
 std::shared_ptr<Codec2Client::Interface>
@@ -921,34 +935,36 @@
         const char* interfaceName,
         std::shared_ptr<Codec2Client>* owner,
         size_t numberOfAttempts) {
-    while (true) {
-        std::shared_ptr<Interface> interface;
-        c2_status_t status = ForAllServices(
-                interfaceName,
-                [owner, &interface, interfaceName](
-                        const std::shared_ptr<Codec2Client> &client)
-                            -> c2_status_t {
-                    c2_status_t status = client->createInterface(interfaceName,
-                                                                 &interface);
-                    if (status == C2_OK) {
-                        if (owner) {
-                            *owner = client;
-                        }
-                    } else if (status != C2_NOT_FOUND) {
-                        LOG(DEBUG) << "IComponentStore("
-                                       << client->getServiceName()
-                                   << ")::createInterface(\"" << interfaceName
-                                   << "\") returned status = "
-                                   << status << ".";
+    std::string key{"create:"};
+    key.append(interfaceName);
+    std::shared_ptr<Interface> interface;
+    c2_status_t status = ForAllServices(
+            key,
+            numberOfAttempts,
+            [owner, &interface, interfaceName](
+                    const std::shared_ptr<Codec2Client> &client)
+                        -> c2_status_t {
+                c2_status_t status = client->createInterface(interfaceName,
+                                                             &interface);
+                if (status == C2_OK) {
+                    if (owner) {
+                        *owner = client;
                     }
-                    return status;
-                });
-        if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
-            --numberOfAttempts;
-            continue;
-        }
-        return interface;
+                } else if (status != C2_NOT_FOUND) {
+                    LOG(DEBUG) << "IComponentStore("
+                                   << client->getServiceName()
+                               << ")::createInterface(\"" << interfaceName
+                               << "\") returned status = "
+                               << status << ".";
+                }
+                return status;
+            });
+    if (status != C2_OK) {
+        LOG(DEBUG) << "Failed to create interface \"" << interfaceName
+                   << "\" from all known services. "
+                      "Last returned status = " << status << ".";
     }
+    return interface;
 }
 
 std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 848901d..dca28f7 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -18,7 +18,7 @@
 #define CODEC2_HIDL_CLIENT_H
 
 #include <gui/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/ClientBlockHelper.h>
+#include <codec2/hidl/1.0/OutputBufferQueue.h>
 #include <C2PlatformSupport.h>
 #include <C2Component.h>
 #include <C2Buffer.h>
@@ -208,11 +208,25 @@
 protected:
     sp<Base> mBase;
 
-    // Finds the first store where the predicate returns OK, and returns the last
-    // predicate result. Uses key to remember the last store found, and if cached,
-    // it tries that store before trying all stores (one retry).
+    // 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
+    // function will return C2_OK the first time the predicate returns C2_OK,
+    // or it will return the value from the last time that predicate is tried.
+    // (The latter case corresponds to a failure on every store.) The order of
+    // the stores to try is the same as the return value of GetServiceNames().
+    //
+    // key is used to remember the last store with which the predicate last
+    // succeeded. If the last successful store is cached, it will be tried
+    // first before all the stores are tried. Note that the last successful
+    // store will be tried twice---first before all the stores, and another time
+    // with all the stores.
+    //
+    // If an attempt to evaluate the predicate results in a transaction failure,
+    // repeated attempts will be made until the predicate returns without a
+    // transaction failure or numberOfAttempts attempts have been made.
     static c2_status_t ForAllServices(
             const std::string& key,
+            size_t numberOfAttempts,
             std::function<c2_status_t(std::shared_ptr<Codec2Client> const&)>
                 predicate);
 
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 11c1ba0..e174751 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",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 4a31953..1cbbbb8 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -26,7 +26,6 @@
 #include <C2ParamInternal.h>
 #include <C2PlatformSupport.h>
 
-#include <android/IGraphicBufferSource.h>
 #include <android/IOMXBufferSource.h>
 #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
@@ -35,8 +34,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 +47,6 @@
 #include "CCodec.h"
 #include "CCodecBufferChannel.h"
 #include "InputSurfaceWrapper.h"
-#include "Omx2IGraphicBufferSource.h"
 
 extern "C" android::PersistentSurface *CreateInputSurface();
 
@@ -54,9 +55,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 +182,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 +197,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 +208,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 +225,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 +359,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 +396,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 +1101,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 +1132,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 +1219,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 +1230,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 +1873,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 +1887,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/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index d6bf101..cd179be 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -633,7 +633,7 @@
             int32_t stride;
             if (mMapper2) {
                 stride = int32_t(mInfo2.stride);
-            } if (mMapper3) {
+            } else if (mMapper3) {
                 stride = int32_t(mInfo3.stride);
             } else {
                 stride = int32_t(mInfo4.stride);
@@ -769,7 +769,7 @@
             int32_t stride;
             if (mMapper2) {
                 stride = int32_t(mInfo2.stride);
-            } if (mMapper3) {
+            } else if (mMapper3) {
                 stride = int32_t(mInfo3.stride);
             } else {
                 stride = int32_t(mInfo4.stride);
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 7d42e70..d36cb49 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -6,6 +6,10 @@
         "frameworks/av/media/libstagefright/include",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "liblog",
         "libmediandk",
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 81e1b8c..6f85960 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1082,9 +1082,14 @@
                         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 && bl_compatibility_id)) {
+                                (profile >= 8 && profile < 11 && create_two_tracks)) {
                             // we need a backward compatible track
                             ALOGV("Adding new backward compatible track");
                             Track *track_b = new Track;
@@ -2388,6 +2393,9 @@
         }
         case FOURCC("dvcC"):
         case FOURCC("dvvC"): {
+
+            CHECK_EQ(chunk_data_size, 24);
+
             auto buffer = heapbuffer<uint8_t>(chunk_data_size);
 
             if (buffer.get() == NULL) {
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index ee5d089..a4322a1 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -472,6 +472,8 @@
  * This is intended for developers to use when debugging.
  * It is not for display to users.
  *
+ * Available since API level 26.
+ *
  * @return pointer to a text representation of an AAudio result code.
  */
 AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) __INTRODUCED_IN(26);
@@ -482,6 +484,8 @@
  * This is intended for developers to use when debugging.
  * It is not for display to users.
  *
+ * Available since API level 26.
+ *
  * @return pointer to a text representation of an AAudio state.
  */
 AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state)
@@ -502,6 +506,8 @@
  * chosen by the device when it is opened.
  *
  * AAudioStreamBuilder_delete() must be called when you are done using the builder.
+ *
+ * Available since API level 26.
  */
 AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
         __INTRODUCED_IN(26);
@@ -513,6 +519,8 @@
  * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED},
  * in which case the primary device will be used.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param deviceId device identifier or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -530,6 +538,8 @@
  * If an exact value is specified then an opened stream will use that value.
  * If a stream cannot be opened with the specified value then the open will fail.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param sampleRate frames per second. Common rates include 44100 and 48000 Hz.
  */
@@ -547,6 +557,8 @@
  * If an exact value is specified then an opened stream will use that value.
  * If a stream cannot be opened with the specified value then the open will fail.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param channelCount Number of channels desired.
  */
@@ -556,6 +568,8 @@
 /**
  * Identical to AAudioStreamBuilder_setChannelCount().
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param samplesPerFrame Number of samples in a frame.
  */
@@ -573,6 +587,8 @@
  * If an exact value is specified then an opened stream will use that value.
  * If a stream cannot be opened with the specified value then the open will fail.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param format common formats are {@link #AAUDIO_FORMAT_PCM_FLOAT} and
  *               {@link #AAUDIO_FORMAT_PCM_I16}.
@@ -588,6 +604,8 @@
  * The requested sharing mode may not be available.
  * The application can query for the actual mode after the stream is opened.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param sharingMode {@link #AAUDIO_SHARING_MODE_SHARED} or {@link #AAUDIO_SHARING_MODE_EXCLUSIVE}
  */
@@ -599,6 +617,8 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_DIRECTION_OUTPUT}.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param direction {@link #AAUDIO_DIRECTION_OUTPUT} or {@link #AAUDIO_DIRECTION_INPUT}
  */
@@ -611,6 +631,8 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_UNSPECIFIED}.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param numFrames the desired buffer capacity in frames or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -629,6 +651,8 @@
  * You can call AAudioStream_getPerformanceMode()
  * to find out the final mode for the stream.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param mode the desired performance mode, eg. {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}
  */
@@ -644,7 +668,7 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_USAGE_MEDIA}.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param usage the desired usage, eg. {@link #AAUDIO_USAGE_GAME}
@@ -661,7 +685,7 @@
  *
  * The default, if you do not call this function, is {@link #AAUDIO_CONTENT_TYPE_MUSIC}.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param contentType the type of audio data, eg. {@link #AAUDIO_CONTENT_TYPE_SPEECH}
@@ -681,7 +705,7 @@
  * That is because VOICE_RECOGNITION is the preset with the lowest latency
  * on many platforms.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param inputPreset the desired configuration for recording
@@ -697,10 +721,10 @@
  * Note that an application can also set its global policy, in which case the most restrictive
  * policy is always applied. See {@link android.media.AudioAttributes#setAllowedCapturePolicy(int)}
  *
- * Added in API level 29.
+ * 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);
@@ -727,7 +751,7 @@
  *
  * Allocated session IDs will always be positive and nonzero.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param sessionId an allocated sessionID or {@link #AAUDIO_SESSION_ID_ALLOCATE}
@@ -826,6 +850,8 @@
  *
  * Note that the AAudio callbacks will never be called simultaneously from multiple threads.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param callback pointer to a function that will process audio data.
  * @param userData pointer to an application data structure that will be passed
@@ -854,6 +880,8 @@
  * If you do call this function then the requested size should be less than
  * half the buffer capacity, to allow double buffering.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param numFrames the desired buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -905,6 +933,8 @@
  *
  * Note that the AAudio callbacks will never be called simultaneously from multiple threads.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param callback pointer to a function that will be called if an error occurs.
  * @param userData pointer to an application data structure that will be passed
@@ -919,6 +949,8 @@
  * AAudioStream_close() must be called when finished with the stream to recover
  * the memory and to free the associated resources.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @param stream pointer to a variable to receive the new stream reference
  * @return {@link #AAUDIO_OK} or a negative error.
@@ -929,6 +961,8 @@
 /**
  * Delete the resources associated with the StreamBuilder.
  *
+ * Available since API level 26.
+ *
  * @param builder reference provided by AAudio_createStreamBuilder()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -942,6 +976,8 @@
 /**
  * Free the resources associated with a stream created by AAudioStreamBuilder_openStream()
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -954,6 +990,8 @@
  * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STARTING} or
  * {@link #AAUDIO_STREAM_STATE_STARTED}.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -969,6 +1007,8 @@
  * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
  * For input streams use AAudioStream_requestStop().
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -984,6 +1024,8 @@
  *
  * This will return {@link #AAUDIO_ERROR_UNIMPLEMENTED} for input streams.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -995,6 +1037,8 @@
  * After this call the state will be in {@link #AAUDIO_STREAM_STATE_STOPPING} or
  * {@link #AAUDIO_STREAM_STATE_STOPPED}.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return {@link #AAUDIO_OK} or a negative error.
  */
@@ -1008,6 +1052,8 @@
  * call AAudioStream_waitForStateChange() with currentState
  * set to {@link #AAUDIO_STREAM_STATE_UNKNOWN} and a zero timeout.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  */
 AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream) __INTRODUCED_IN(26);
@@ -1028,6 +1074,8 @@
  * }
  * </code></pre>
  *
+ * Available since API level 26.
+ *
  * @param stream A reference provided by AAudioStreamBuilder_openStream()
  * @param inputState The state we want to avoid.
  * @param nextState Pointer to a variable that will be set to the new state.
@@ -1056,6 +1104,8 @@
  *
  * If the call times out then zero or a partial frame count will be returned.
  *
+ * Available since API level 26.
+ *
  * @param stream A stream created using AAudioStreamBuilder_openStream().
  * @param buffer The address of the first sample.
  * @param numFrames Number of frames to read. Only complete frames will be written.
@@ -1079,6 +1129,8 @@
  *
  * If the call times out then zero or a partial frame count will be returned.
  *
+ * Available since API level 26.
+ *
  * @param stream A stream created using AAudioStreamBuilder_openStream().
  * @param buffer The address of the first sample.
  * @param numFrames Number of frames to write. Only complete frames will be written.
@@ -1104,6 +1156,8 @@
  * You can check the return value or call AAudioStream_getBufferSizeInFrames()
  * to see what the actual final size is.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @param numFrames requested number of frames that can be filled without blocking
  * @return actual buffer size in frames or a negative error
@@ -1114,6 +1168,8 @@
 /**
  * Query the maximum number of frames that can be filled without blocking.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return buffer size in frames.
  */
@@ -1129,6 +1185,8 @@
  * For some endpoints, the burst size can vary dynamically.
  * But these tend to be devices with high latency.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return burst size
  */
@@ -1137,6 +1195,8 @@
 /**
  * Query maximum buffer capacity in frames.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return  buffer capacity in frames
  */
@@ -1158,6 +1218,8 @@
  * {@link #AAUDIO_UNSPECIFIED} indicates that the callback buffer size for this stream
  * may vary from one dataProc callback to the next.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return callback buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
  */
@@ -1175,12 +1237,16 @@
  * Note that some INPUT devices may not support this function.
  * In that case a 0 will always be returned.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return the underrun or overrun count
  */
 AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual sample rate
  */
@@ -1190,6 +1256,8 @@
  * A stream has one or more channels of data.
  * A frame will contain one sample for each channel.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual number of channels
  */
@@ -1198,18 +1266,24 @@
 /**
  * Identical to AAudioStream_getChannelCount().
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual number of samples frame
  */
 AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual device ID
  */
 AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream) __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual data format
  */
@@ -1217,6 +1291,9 @@
 
 /**
  * Provide actual sharing mode.
+ *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return  actual sharing mode
  */
@@ -1226,12 +1303,16 @@
 /**
  * Get the performance mode used by the stream.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  */
 AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* stream)
         __INTRODUCED_IN(26);
 
 /**
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return direction
  */
@@ -1245,6 +1326,8 @@
  *
  * The frame position is monotonically increasing.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return frames written
  */
@@ -1258,6 +1341,8 @@
  *
  * The frame position is monotonically increasing.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return frames read
  */
@@ -1281,7 +1366,7 @@
  *
  * The sessionID for a stream should not change once the stream has been opened.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return session ID or {@link #AAUDIO_SESSION_ID_NONE}
@@ -1304,6 +1389,8 @@
  *
  * The position and time passed back are monotonically increasing.
  *
+ * Available since API level 26.
+ *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @param clockid CLOCK_MONOTONIC or CLOCK_BOOTTIME
  * @param framePosition pointer to a variable to receive the position
@@ -1316,7 +1403,7 @@
 /**
  * Return the use case for the stream.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return frames read
@@ -1326,7 +1413,7 @@
 /**
  * Return the content type for the stream.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return content type, for example {@link #AAUDIO_CONTENT_TYPE_MUSIC}
@@ -1337,7 +1424,7 @@
 /**
  * Return the input preset for the stream.
  *
- * Added in API level 28.
+ * Available since API level 28.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return input preset, for example {@link #AAUDIO_INPUT_PRESET_CAMCORDER}
@@ -1349,7 +1436,7 @@
  * Return the policy that determines whether the audio may or may not be captured
  * by other apps or the system.
  *
- * Added in API level 29.
+ * Available since API level 29.
  *
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return the allowed capture policy, for example {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 56c0170..850b1d0 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -10,7 +10,9 @@
         "legacy",
         "utility",
     ],
-    header_libs: ["libaaudio_headers"],
+    header_libs: [
+        "libaaudio_headers",
+    ],
     export_header_lib_headers: ["libaaudio_headers"],
     version_script: "libaaudio.map.txt",
 
@@ -53,7 +55,10 @@
     ],
 
     export_include_dirs: ["."],
-    header_libs: ["libaaudio_headers"],
+    header_libs: [
+        "libaaudio_headers",
+        "libmedia_headers"
+    ],
     export_header_lib_headers: ["libaaudio_headers"],
 
     shared_libs: [
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 2ece474..7481daa 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -250,6 +250,8 @@
         mTimeOffsetNanos = offsetMicros * AAUDIO_NANOS_PER_MICROSECOND;
     }
 
+    setBufferSize(capacity / 2); // Default buffer size to match Q
+
     setState(AAUDIO_STREAM_STATE_OPEN);
 
     return result;
@@ -653,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.
@@ -712,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 9395416..596d37f 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -204,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/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/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index c516d20..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",
@@ -84,6 +94,7 @@
     header_libs: [
         "libaudioclient_headers",
         "libbase_headers",
+        "libmedia_headers",
     ],
     export_header_lib_headers: ["libaudioclient_headers"],
 
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/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 46cfb68..6e9a7cf 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -392,20 +392,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 +418,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;
     }
@@ -1198,19 +1195,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;
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..3f846f7 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>
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index b580a88..0a65857 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>
@@ -416,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,
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 32275cf..8669ee6 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>
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 52bb2fb..d509be6 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -11,6 +11,9 @@
     defaults: ["libaudioclient_tests_defaults"],
     srcs: ["test_create_audiotrack.cpp",
            "test_create_utils.cpp"],
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "libaudioclient",
         "libbinder",
@@ -25,6 +28,9 @@
     defaults: ["libaudioclient_tests_defaults"],
     srcs: ["test_create_audiorecord.cpp",
            "test_create_utils.cpp"],
+    header_libs: [
+        "libmedia_headers",
+    ],
     shared_libs: [
         "libaudioclient",
         "libbinder",
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index 10f3e67..93bc4d9 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -2,14 +2,24 @@
     name: "libaudiofoundation_headers",
     vendor_available: true,
     export_include_dirs: ["include"],
+    header_libs: [
+        "libaudio_system_headers",
+        "libmedia_helper_headers",
+    ],
+    export_header_lib_headers: [
+        "libaudio_system_headers",
+        "libmedia_helper_headers",
+    ],
 }
 
-cc_library_shared {
+cc_library {
     name: "libaudiofoundation",
     vendor_available: true,
+    double_loadable: true,
 
     srcs: [
         "AudioContainers.cpp",
+        "AudioDeviceTypeAddr.cpp",
         "AudioGain.cpp",
         "AudioPort.cpp",
         "AudioProfile.cpp",
@@ -26,12 +36,12 @@
     ],
 
     header_libs: [
-        "libaudio_system_headers",
-        "libaudioclient_headers",
         "libaudiofoundation_headers",
     ],
 
-    export_header_lib_headers: ["libaudiofoundation_headers"],
+    export_header_lib_headers: [
+        "libaudiofoundation_headers",
+    ],
 
     cflags: [
         "-Werror",
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
new file mode 100644
index 0000000..3e43ead
--- /dev/null
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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;
+}
+
+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;
+}
+
+}
\ No newline at end of file
diff --git a/media/libaudiofoundation/DeviceDescriptorBase.cpp b/media/libaudiofoundation/DeviceDescriptorBase.cpp
index 18fd184..8933002 100644
--- a/media/libaudiofoundation/DeviceDescriptorBase.cpp
+++ b/media/libaudiofoundation/DeviceDescriptorBase.cpp
@@ -27,11 +27,11 @@
 DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type) :
     AudioPort("", AUDIO_PORT_TYPE_DEVICE,
               audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
-                                             AUDIO_PORT_ROLE_SOURCE),
-    mDeviceType(type)
+                                             AUDIO_PORT_ROLE_SOURCE)
 {
+    mDeviceTypeAddr.mType = type;
     if (audio_is_remote_submix_device(type)) {
-        mAddress = "0";
+        mDeviceTypeAddr.mAddress = "0";
     }
 }
 
@@ -55,22 +55,22 @@
 
     AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
 
-    dstConfig->role = audio_is_output_device(mDeviceType) ?
+    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 = mDeviceType;
+    dstConfig->ext.device.type = mDeviceTypeAddr.mType;
 
-    (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mAddress.c_str());
+    (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, mDeviceType);
+    ALOGV("DeviceDescriptorBase::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
     AudioPort::toAudioPort(port);
     toAudioPortConfig(&port->active_config);
     port->id = mId;
-    port->ext.device.type = mDeviceType;
-    (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mAddress.c_str());
+    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,
@@ -86,10 +86,11 @@
     }
 
     dst->append(base::StringPrintf("%*s- type: %-48s\n",
-            spaces, "", ::android::toString(mDeviceType).c_str()));
+            spaces, "", ::android::toString(mDeviceTypeAddr.mType).c_str()));
 
-    if (mAddress.size() != 0) {
-        dst->append(base::StringPrintf("%*s- address: %-32s\n", spaces, "", mAddress.c_str()));
+    if (mDeviceTypeAddr.mAddress.size() != 0) {
+        dst->append(base::StringPrintf(
+                "%*s- address: %-32s\n", spaces, "", mDeviceTypeAddr.getAddress()));
     }
     AudioPort::dump(dst, spaces, verbose);
 }
@@ -97,15 +98,15 @@
 std::string DeviceDescriptorBase::toString() const
 {
     std::stringstream sstream;
-    sstream << "type:0x" << std::hex << type() << ",@:" << mAddress;
+    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,  mDeviceType,
-          ::android::toString(mDeviceType).c_str(),
-          mAddress.c_str());
+    ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId,  mDeviceTypeAddr.mType,
+          ::android::toString(mDeviceTypeAddr.mType).c_str(),
+          mDeviceTypeAddr.getAddress());
 
     AudioPort::log("  ");
 }
@@ -115,8 +116,7 @@
     return other != nullptr &&
            static_cast<const AudioPort*>(this)->equals(other) &&
            static_cast<const AudioPortConfig*>(this)->equals(other) &&
-           mAddress.compare(other->address()) == 0 &&
-           mDeviceType == other->type();
+           mDeviceTypeAddr.equals(other->mDeviceTypeAddr);
 }
 
 status_t DeviceDescriptorBase::writeToParcel(Parcel *parcel) const
@@ -124,8 +124,7 @@
     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->writeUtf8AsUtf16(mAddress)) != NO_ERROR) return status;
-    if ((status = parcel->writeUint32(mDeviceType)) != NO_ERROR) return status;
+    if ((status = parcel->writeParcelable(mDeviceTypeAddr)) != NO_ERROR) return status;
     return status;
 }
 
@@ -134,8 +133,7 @@
     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->readUtf8FromUtf16(&mAddress)) != NO_ERROR) return status;
-    if ((status = parcel->readUint32(&mDeviceType)) != NO_ERROR) return status;
+    if ((status = parcel->readParcelable(&mDeviceTypeAddr)) != NO_ERROR) return status;
     return status;
 }
 
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
index 8347c71..05e68fa 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <algorithm>
+#include <functional>
 #include <iterator>
 #include <set>
 #include <vector>
@@ -78,6 +79,11 @@
     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);
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
new file mode 100644
index 0000000..392a355
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -0,0 +1,46 @@
+/*
+ * 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/Parcelable.h>
+#include <binder/Parcel.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;
+
+    status_t readFromParcel(const Parcel *parcel) override;
+
+    status_t writeToParcel(Parcel *parcel) const override;
+
+    audio_devices_t mType = AUDIO_DEVICE_NONE;
+    std::string mAddress;
+};
+
+}
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
index 6a34b4d..5a60502 100644
--- a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -19,6 +19,7 @@
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
 #include <media/AudioPort.h>
+#include <media/AudioDeviceTypeAddr.h>
 #include <utils/Errors.h>
 #include <cutils/config_utils.h>
 #include <system/audio.h>
@@ -34,9 +35,10 @@
 
     virtual ~DeviceDescriptorBase() {}
 
-    audio_devices_t type() const { return mDeviceType; }
-    std::string address() const { return mAddress; }
-    void setAddress(const std::string &address) { mAddress = address; }
+    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 {
@@ -59,8 +61,7 @@
     status_t readFromParcel(const Parcel* parcel) override;
 
 protected:
-    std::string mAddress{""};
-    audio_devices_t     mDeviceType;
+    AudioDeviceTypeAddr mDeviceTypeAddr;
 };
 
 } // 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/Android.bp b/media/libaudiohal/Android.bp
index 5837fcf..74b48f3 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -16,6 +16,7 @@
         "libaudiohal@2.0",
         "libaudiohal@4.0",
         "libaudiohal@5.0",
+        "libaudiohal@6.0",
         "libutils",
     ],
 
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index a23d945..8669e2a 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -99,3 +99,20 @@
         "-include common/all-versions/VersionMacro.h",
     ]
 }
+
+cc_library_shared {
+    name: "libaudiohal@6.0",
+    defaults: ["libaudiohal_default"],
+    shared_libs: [
+        "android.hardware.audio.common@6.0",
+        "android.hardware.audio.common@6.0-util",
+        "android.hardware.audio.effect@6.0",
+        "android.hardware.audio@6.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=6",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ]
+}
+
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index b07f21d..3d3a5eb 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -229,14 +229,14 @@
 
 status_t DeviceHalHidl::openOutputStream(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address,
         sp<StreamOutHalInterface> *outStream) {
     if (mDevice == 0) return NO_INIT;
     DeviceAddress hidlDevice;
-    status_t status = deviceAddressFromHal(devices, address, &hidlDevice);
+    status_t status = deviceAddressFromHal(deviceType, address, &hidlDevice);
     if (status != OK) return status;
     AudioConfig hidlConfig;
     HidlUtils::audioConfigFromHal(*config, &hidlConfig);
diff --git a/media/libaudiohal/impl/DeviceHalLocal.cpp b/media/libaudiohal/impl/DeviceHalLocal.cpp
index ee68252..dfbb6b2 100644
--- a/media/libaudiohal/impl/DeviceHalLocal.cpp
+++ b/media/libaudiohal/impl/DeviceHalLocal.cpp
@@ -104,7 +104,7 @@
 
 status_t DeviceHalLocal::openOutputStream(
         audio_io_handle_t handle,
-        audio_devices_t devices,
+        audio_devices_t deviceType,
         audio_output_flags_t flags,
         struct audio_config *config,
         const char *address,
@@ -112,11 +112,11 @@
     audio_stream_out_t *halStream;
     ALOGV("open_output_stream handle: %d devices: %x flags: %#x"
             "srate: %d format %#x channels %x address %s",
-            handle, devices, flags,
+            handle, deviceType, flags,
             config->sample_rate, config->format, config->channel_mask,
             address);
     int openResut = mDev->open_output_stream(
-            mDev, handle, devices, flags, config, &halStream, address);
+            mDev, handle, deviceType, flags, config, &halStream, address);
     if (openResut == OK) {
         *outStream = new StreamOutHalLocal(halStream, this);
     }
diff --git a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
index 829f99c..271bafc 100644
--- a/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
+++ b/media/libaudiohal/impl/include/libaudiohal/FactoryHalHidl.h
@@ -34,6 +34,7 @@
  * the preferred available impl.
  */
 enum class AudioHALVersion {
+    V6_0,
     V5_0,
     V4_0,
     V2_0,
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/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index e8aa700..9b5d58c 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -33,6 +33,7 @@
 
     header_libs: [
         "libbase_headers",
+        "libmedia_headers"
     ],
 
     shared_libs: [
diff --git a/media/libaudioprocessing/tests/Android.bp b/media/libaudioprocessing/tests/Android.bp
index f4e497b..20c2c2c 100644
--- a/media/libaudioprocessing/tests/Android.bp
+++ b/media/libaudioprocessing/tests/Android.bp
@@ -3,7 +3,11 @@
 cc_defaults {
     name: "libaudioprocessing_test_defaults",
 
-    header_libs: ["libbase_headers"],
+    header_libs: [
+        "libbase_headers",
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libaudioclient",
         "libaudioprocessing",
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..1df47b7
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -0,0 +1,10 @@
+cc_fuzz {
+  name: "libaudioprocessing_resampler_fuzzer",
+  srcs: [
+    "libaudioprocessing_resampler_fuzzer.cpp",
+  ],
+  defaults: ["libaudioprocessing_test_defaults"],
+  static_libs: [
+    "libsndfile",
+  ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
new file mode 100644
index 0000000..938c610
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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-base/macros.h>
+#include <audio_utils/primitives.h>
+#include <audio_utils/sndfile.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <media/AudioBufferProvider.h>
+#include <media/AudioResampler.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Vector.h>
+
+#include <memory>
+
+using namespace android;
+
+const int MAX_FRAMES = 10;
+const int MIN_FREQ = 1e3;
+const int MAX_FREQ = 100e3;
+
+const AudioResampler::src_quality qualities[] = {
+    AudioResampler::DEFAULT_QUALITY,
+    AudioResampler::LOW_QUALITY,
+    AudioResampler::MED_QUALITY,
+    AudioResampler::HIGH_QUALITY,
+    AudioResampler::VERY_HIGH_QUALITY,
+    AudioResampler::DYN_LOW_QUALITY,
+    AudioResampler::DYN_MED_QUALITY,
+    AudioResampler::DYN_HIGH_QUALITY,
+};
+
+class Provider : public AudioBufferProvider {
+  const void* mAddr;        // base address
+  const size_t mNumFrames;  // total frames
+  const size_t mFrameSize;  // size of each frame in bytes
+  size_t mNextFrame;        // index of next frame to provide
+  size_t mUnrel;            // number of frames not yet released
+ public:
+  Provider(const void* addr, size_t frames, size_t frameSize)
+      : mAddr(addr),
+        mNumFrames(frames),
+        mFrameSize(frameSize),
+        mNextFrame(0),
+        mUnrel(0) {}
+  status_t getNextBuffer(Buffer* buffer) override {
+    if (buffer->frameCount > mNumFrames - mNextFrame) {
+      buffer->frameCount = mNumFrames - mNextFrame;
+    }
+    mUnrel = buffer->frameCount;
+    if (buffer->frameCount > 0) {
+      buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
+      return NO_ERROR;
+    } else {
+      buffer->raw = nullptr;
+      return NOT_ENOUGH_DATA;
+    }
+  }
+  virtual void releaseBuffer(Buffer* buffer) {
+    if (buffer->frameCount > mUnrel) {
+      mNextFrame += mUnrel;
+      mUnrel = 0;
+    } else {
+      mNextFrame += buffer->frameCount;
+      mUnrel -= buffer->frameCount;
+    }
+    buffer->frameCount = 0;
+    buffer->raw = nullptr;
+  }
+  void reset() { mNextFrame = 0; }
+};
+
+audio_format_t chooseFormat(AudioResampler::src_quality quality,
+                            uint8_t input_byte) {
+  switch (quality) {
+    case AudioResampler::DYN_LOW_QUALITY:
+    case AudioResampler::DYN_MED_QUALITY:
+    case AudioResampler::DYN_HIGH_QUALITY:
+      if (input_byte % 2) {
+        return AUDIO_FORMAT_PCM_FLOAT;
+      }
+      FALLTHROUGH_INTENDED;
+    default:
+      return AUDIO_FORMAT_PCM_16_BIT;
+  }
+}
+
+int parseValue(const uint8_t* src, int index, void* dst, size_t size) {
+  memcpy(dst, &src[index], size);
+  return size;
+}
+
+bool validFreq(int freq) { return freq > MIN_FREQ && freq < MAX_FREQ; }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  int input_freq = 0;
+  int output_freq = 0;
+  int input_channels = 0;
+
+  float left_volume = 0;
+  float right_volume = 0;
+
+  size_t metadata_size = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+  if (size < metadata_size) {
+    // not enough data to set options
+    return 0;
+  }
+
+  AudioResampler::src_quality quality = qualities[data[0] % 8];
+  audio_format_t format = chooseFormat(quality, data[1]);
+
+  int index = 2;
+
+  index += parseValue(data, index, &input_freq, sizeof(int));
+  index += parseValue(data, index, &output_freq, sizeof(int));
+  index += parseValue(data, index, &input_channels, sizeof(int));
+
+  index += parseValue(data, index, &left_volume, sizeof(float));
+  index += parseValue(data, index, &right_volume, sizeof(float));
+
+  if (!validFreq(input_freq) || !validFreq(output_freq)) {
+    // sampling frequencies must be reasonable
+    return 0;
+  }
+
+  if (input_channels < 1 ||
+      input_channels > (quality < AudioResampler::DYN_LOW_QUALITY ? 2 : 8)) {
+    // invalid number of input channels
+    return 0;
+  }
+
+  size_t single_channel_size =
+      format == AUDIO_FORMAT_PCM_FLOAT ? sizeof(float) : sizeof(int16_t);
+  size_t input_frame_size = single_channel_size * input_channels;
+  size_t input_size = size - metadata_size;
+  uint8_t input_data[input_size];
+  memcpy(input_data, &data[metadata_size], input_size);
+
+  size_t input_frames = input_size / input_frame_size;
+  if (input_frames > MAX_FRAMES) {
+    return 0;
+  }
+
+  Provider provider(input_data, input_frames, input_frame_size);
+
+  std::unique_ptr<AudioResampler> resampler(
+      AudioResampler::create(format, input_channels, output_freq, quality));
+
+  resampler->setSampleRate(input_freq);
+  resampler->setVolume(left_volume, right_volume);
+
+  // output is at least stereo samples
+  int output_channels = input_channels > 2 ? input_channels : 2;
+  size_t output_frame_size = output_channels * sizeof(int32_t);
+  size_t output_frames = (input_frames * output_freq) / input_freq;
+  size_t output_size = output_frames * output_frame_size;
+
+  uint8_t output_data[output_size];
+  for (size_t i = 0; i < output_frames; i++) {
+    memset(output_data, 0, output_size);
+    resampler->resample((int*)output_data, i, &provider);
+  }
+
+  return 0;
+}
diff --git a/media/libdatasource/Android.bp b/media/libdatasource/Android.bp
index dd8ef74..f191c21 100644
--- a/media/libdatasource/Android.bp
+++ b/media/libdatasource/Android.bp
@@ -2,8 +2,6 @@
     name: "libdatasource",
 
     srcs: [
-        "ClearFileSource.cpp",
-        "ClearMediaHTTP.cpp",
         "DataSourceFactory.cpp",
         "DataURISource.cpp",
         "FileSource.cpp",
@@ -31,7 +29,6 @@
     shared_libs: [
         "liblog",
         "libcutils",
-        "libdrmframework",
         "libutils",
         "libstagefright_foundation",
         "libdl",
diff --git a/media/libdatasource/ClearFileSource.cpp b/media/libdatasource/ClearFileSource.cpp
deleted file mode 100644
index afafa23..0000000
--- a/media/libdatasource/ClearFileSource.cpp
+++ /dev/null
@@ -1,143 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearFileSource"
-#include <utils/Log.h>
-
-#include <datasource/ClearFileSource.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/FoundationUtils.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-namespace android {
-
-ClearFileSource::ClearFileSource(const char *filename)
-    : mFd(-1),
-      mOffset(0),
-      mLength(-1),
-      mName("<null>") {
-
-    if (filename) {
-        mName = String8::format("FileSource(%s)", filename);
-    }
-    ALOGV("%s", filename);
-    mFd = open(filename, O_LARGEFILE | O_RDONLY);
-
-    if (mFd >= 0) {
-        mLength = lseek64(mFd, 0, SEEK_END);
-    } else {
-        ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
-    }
-}
-
-ClearFileSource::ClearFileSource(int fd, int64_t offset, int64_t length)
-    : mFd(fd),
-      mOffset(offset),
-      mLength(length),
-      mName("<null>") {
-    ALOGV("fd=%d (%s), offset=%lld, length=%lld",
-            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
-
-    if (mOffset < 0) {
-        mOffset = 0;
-    }
-    if (mLength < 0) {
-        mLength = 0;
-    }
-    if (mLength > INT64_MAX - mOffset) {
-        mLength = INT64_MAX - mOffset;
-    }
-    struct stat s;
-    if (fstat(fd, &s) == 0) {
-        if (mOffset > s.st_size) {
-            mOffset = s.st_size;
-            mLength = 0;
-        }
-        if (mOffset + mLength > s.st_size) {
-            mLength = s.st_size - mOffset;
-        }
-    }
-    if (mOffset != offset || mLength != length) {
-        ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
-                (long long) offset, (long long) length,
-                (long long) mOffset, (long long) mLength);
-    }
-
-    mName = String8::format(
-            "FileSource(fd(%s), %lld, %lld)",
-            nameForFd(fd).c_str(),
-            (long long) mOffset,
-            (long long) mLength);
-
-}
-
-ClearFileSource::~ClearFileSource() {
-    if (mFd >= 0) {
-        ::close(mFd);
-        mFd = -1;
-    }
-}
-
-status_t ClearFileSource::initCheck() const {
-    return mFd >= 0 ? OK : NO_INIT;
-}
-
-ssize_t ClearFileSource::readAt(off64_t offset, void *data, size_t size) {
-    if (mFd < 0) {
-        return NO_INIT;
-    }
-
-    Mutex::Autolock autoLock(mLock);
-    if (mLength >= 0) {
-        if (offset >= mLength) {
-            return 0;  // read beyond EOF.
-        }
-        uint64_t numAvailable = mLength - offset;
-        if ((uint64_t)size > numAvailable) {
-            size = numAvailable;
-        }
-    }
-    return readAt_l(offset, data, size);
-}
-
-ssize_t ClearFileSource::readAt_l(off64_t offset, void *data, size_t size) {
-    off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
-    if (result == -1) {
-        ALOGE("seek to %lld failed", (long long)(offset + mOffset));
-        return UNKNOWN_ERROR;
-    }
-
-    return ::read(mFd, data, size);
-}
-
-status_t ClearFileSource::getSize(off64_t *size) {
-    Mutex::Autolock autoLock(mLock);
-
-    if (mFd < 0) {
-        return NO_INIT;
-    }
-
-    *size = mLength;
-
-    return OK;
-}
-
-}  // namespace android
diff --git a/media/libdatasource/ClearMediaHTTP.cpp b/media/libdatasource/ClearMediaHTTP.cpp
deleted file mode 100644
index 7249c84..0000000
--- a/media/libdatasource/ClearMediaHTTP.cpp
+++ /dev/null
@@ -1,184 +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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ClearMediaHTTP"
-#include <utils/Log.h>
-
-#include <datasource/ClearMediaHTTP.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/FoundationUtils.h>
-
-#include <media/MediaHTTPConnection.h>
-
-namespace android {
-
-ClearMediaHTTP::ClearMediaHTTP(const sp<MediaHTTPConnection> &conn)
-    : mInitCheck((conn != NULL) ? OK : NO_INIT),
-      mHTTPConnection(conn),
-      mCachedSizeValid(false),
-      mCachedSize(0ll) {
-}
-
-ClearMediaHTTP::~ClearMediaHTTP() {
-}
-
-status_t ClearMediaHTTP::connect(
-        const char *uri,
-        const KeyedVector<String8, String8> *headers,
-        off64_t /* offset */) {
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    KeyedVector<String8, String8> extHeaders;
-    if (headers != NULL) {
-        extHeaders = *headers;
-    }
-
-    if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
-        extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
-    }
-
-    mLastURI = uri;
-    // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
-    // as part of the above assignment. Ensure no accidental later use.
-    uri = NULL;
-
-    bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
-
-    mLastHeaders = extHeaders;
-
-    mCachedSizeValid = false;
-
-    if (success) {
-        AString sanitized = uriDebugString(mLastURI);
-        mName = String8::format("ClearMediaHTTP(%s)", sanitized.c_str());
-    }
-
-    return success ? OK : UNKNOWN_ERROR;
-}
-
-void ClearMediaHTTP::close() {
-    disconnect();
-}
-
-void ClearMediaHTTP::disconnect() {
-    mName = String8("ClearMediaHTTP(<disconnected>)");
-    if (mInitCheck != OK) {
-        return;
-    }
-
-    mHTTPConnection->disconnect();
-}
-
-status_t ClearMediaHTTP::initCheck() const {
-    return mInitCheck;
-}
-
-ssize_t ClearMediaHTTP::readAt(off64_t offset, void *data, size_t size) {
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    int64_t startTimeUs = ALooper::GetNowUs();
-
-    size_t numBytesRead = 0;
-    while (numBytesRead < size) {
-        size_t copy = size - numBytesRead;
-
-        if (copy > 64 * 1024) {
-            // limit the buffer sizes transferred across binder boundaries
-            // to avoid spurious transaction failures.
-            copy = 64 * 1024;
-        }
-
-        ssize_t n = mHTTPConnection->readAt(
-                offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
-
-        if (n < 0) {
-            return n;
-        } else if (n == 0) {
-            break;
-        }
-
-        numBytesRead += n;
-    }
-
-    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
-
-    addBandwidthMeasurement(numBytesRead, delayUs);
-
-    return numBytesRead;
-}
-
-status_t ClearMediaHTTP::getSize(off64_t *size) {
-    if (mInitCheck != OK) {
-        return mInitCheck;
-    }
-
-    // Caching the returned size so that it stays valid even after a
-    // disconnect. NuCachedSource2 relies on this.
-
-    if (!mCachedSizeValid) {
-        mCachedSize = mHTTPConnection->getSize();
-        mCachedSizeValid = true;
-    }
-
-    *size = mCachedSize;
-
-    return *size < 0 ? *size : static_cast<status_t>(OK);
-}
-
-uint32_t ClearMediaHTTP::flags() {
-    return kWantsPrefetching | kIsHTTPBasedSource;
-}
-
-status_t ClearMediaHTTP::reconnectAtOffset(off64_t offset) {
-    return connect(mLastURI.c_str(), &mLastHeaders, offset);
-}
-
-
-String8 ClearMediaHTTP::getUri() {
-    if (mInitCheck != OK) {
-        return String8::empty();
-    }
-
-    String8 uri;
-    if (OK == mHTTPConnection->getUri(&uri)) {
-        return uri;
-    }
-    return String8(mLastURI.c_str());
-}
-
-String8 ClearMediaHTTP::getMIMEType() const {
-    if (mInitCheck != OK) {
-        return String8("application/octet-stream");
-    }
-
-    String8 mimeType;
-    status_t err = mHTTPConnection->getMIMEType(&mimeType);
-
-    if (err != OK) {
-        return String8("application/octet-stream");
-    }
-
-    return mimeType;
-}
-
-}  // namespace android
diff --git a/media/libdatasource/DataSourceFactory.cpp b/media/libdatasource/DataSourceFactory.cpp
index 8c772dd..bb6a08c 100644
--- a/media/libdatasource/DataSourceFactory.cpp
+++ b/media/libdatasource/DataSourceFactory.cpp
@@ -30,6 +30,19 @@
 namespace android {
 
 // static
+sp<DataSourceFactory> DataSourceFactory::sInstance;
+// static
+Mutex DataSourceFactory::sInstanceLock;
+
+// static
+sp<DataSourceFactory> DataSourceFactory::getInstance() {
+    Mutex::Autolock l(sInstanceLock);
+    if (!sInstance) {
+        sInstance = new DataSourceFactory();
+    }
+    return sInstance;
+}
+
 sp<DataSource> DataSourceFactory::CreateFromURI(
         const sp<MediaHTTPService> &httpService,
         const char *uri,
@@ -42,20 +55,16 @@
 
     sp<DataSource> source;
     if (!strncasecmp("file://", uri, 7)) {
-        source = new FileSource(uri + 7);
+        source = CreateFileSource(uri + 7);
     } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
         if (httpService == NULL) {
             ALOGE("Invalid http service!");
             return NULL;
         }
 
-        if (httpSource == NULL) {
-            sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
-            if (conn == NULL) {
-                ALOGE("Failed to make http connection from http service!");
-                return NULL;
-            }
-            httpSource = new MediaHTTP(conn);
+        sp<HTTPBase> mediaHTTP = httpSource;
+        if (mediaHTTP == NULL) {
+            mediaHTTP = static_cast<HTTPBase *>(CreateMediaHTTP(httpService).get());
         }
 
         String8 cacheConfig;
@@ -69,24 +78,24 @@
                     &disconnectAtHighwatermark);
         }
 
-        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
+        if (mediaHTTP->connect(uri, &nonCacheSpecificHeaders) != OK) {
             ALOGE("Failed to connect http source!");
             return NULL;
         }
 
         if (contentType != NULL) {
-            *contentType = httpSource->getMIMEType();
+            *contentType = mediaHTTP->getMIMEType();
         }
 
         source = NuCachedSource2::Create(
-                httpSource,
+                mediaHTTP,
                 cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
                 disconnectAtHighwatermark);
     } else if (!strncasecmp("data:", uri, 5)) {
         source = DataURISource::Create(uri);
     } else {
         // Assume it's a filename.
-        source = new FileSource(uri);
+        source = CreateFileSource(uri);
     }
 
     if (source == NULL || source->initCheck() != OK) {
@@ -108,10 +117,15 @@
 
     sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
     if (conn == NULL) {
+        ALOGE("Failed to make http connection from http service!");
         return NULL;
     } else {
         return new MediaHTTP(conn);
     }
 }
 
+sp<DataSource> DataSourceFactory::CreateFileSource(const char *uri) {
+    return new FileSource(uri);
+}
+
 }  // namespace android
diff --git a/media/libdatasource/FileSource.cpp b/media/libdatasource/FileSource.cpp
index 65780e3..bbf7dda 100644
--- a/media/libdatasource/FileSource.cpp
+++ b/media/libdatasource/FileSource.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -20,45 +20,84 @@
 
 #include <datasource/FileSource.h>
 #include <media/stagefright/foundation/ADebug.h>
-#include <private/android_filesystem_config.h>
+#include <media/stagefright/FoundationUtils.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 
 namespace android {
 
 FileSource::FileSource(const char *filename)
-    : ClearFileSource(filename),
-      mDecryptHandle(NULL),
-      mDrmManagerClient(NULL),
-      mDrmBufOffset(0),
-      mDrmBufSize(0),
-      mDrmBuf(NULL){
+    : mFd(-1),
+      mOffset(0),
+      mLength(-1),
+      mName("<null>") {
+
+    if (filename) {
+        mName = String8::format("FileSource(%s)", filename);
+    }
+    ALOGV("%s", filename);
+    mFd = open(filename, O_LARGEFILE | O_RDONLY);
+
+    if (mFd >= 0) {
+        mLength = lseek64(mFd, 0, SEEK_END);
+    } else {
+        ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
+    }
 }
 
 FileSource::FileSource(int fd, int64_t offset, int64_t length)
-    : ClearFileSource(fd, offset, length),
-      mDecryptHandle(NULL),
-      mDrmManagerClient(NULL),
-      mDrmBufOffset(0),
-      mDrmBufSize(0),
-      mDrmBuf(NULL) {
+    : mFd(fd),
+      mOffset(offset),
+      mLength(length),
+      mName("<null>") {
+    ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
+    if (mOffset < 0) {
+        mOffset = 0;
+    }
+    if (mLength < 0) {
+        mLength = 0;
+    }
+    if (mLength > INT64_MAX - mOffset) {
+        mLength = INT64_MAX - mOffset;
+    }
+    struct stat s;
+    if (fstat(fd, &s) == 0) {
+        if (mOffset > s.st_size) {
+            mOffset = s.st_size;
+            mLength = 0;
+        }
+        if (mOffset + mLength > s.st_size) {
+            mLength = s.st_size - mOffset;
+        }
+    }
+    if (mOffset != offset || mLength != length) {
+        ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
+                (long long) offset, (long long) length,
+                (long long) mOffset, (long long) mLength);
+    }
+
+    mName = String8::format(
+            "FileSource(fd(%s), %lld, %lld)",
+            nameForFd(fd).c_str(),
+            (long long) mOffset,
+            (long long) mLength);
+
 }
 
 FileSource::~FileSource() {
-    if (mDrmBuf != NULL) {
-        delete[] mDrmBuf;
-        mDrmBuf = NULL;
+    if (mFd >= 0) {
+        ::close(mFd);
+        mFd = -1;
     }
+}
 
-    if (mDecryptHandle != NULL) {
-        // To release mDecryptHandle
-        CHECK(mDrmManagerClient);
-        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
-        mDecryptHandle = NULL;
-    }
-
-    if (mDrmManagerClient != NULL) {
-        delete mDrmManagerClient;
-        mDrmManagerClient = NULL;
-    }
+status_t FileSource::initCheck() const {
+    return mFd >= 0 ? OK : NO_INIT;
 }
 
 ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
@@ -67,7 +106,6 @@
     }
 
     Mutex::Autolock autoLock(mLock);
-
     if (mLength >= 0) {
         if (offset >= mLength) {
             return 0;  // read beyond EOF.
@@ -77,79 +115,29 @@
             size = numAvailable;
         }
     }
-
-    if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
-            == mDecryptHandle->decryptApiType) {
-        return readAtDRM_l(offset, data, size);
-   } else {
-        return readAt_l(offset, data, size);
-    }
+    return readAt_l(offset, data, size);
 }
 
-sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) {
-    if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
-    if (mDrmManagerClient == NULL) {
-        mDrmManagerClient = new DrmManagerClient();
+ssize_t FileSource::readAt_l(off64_t offset, void *data, size_t size) {
+    off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
+    if (result == -1) {
+        ALOGE("seek to %lld failed", (long long)(offset + mOffset));
+        return UNKNOWN_ERROR;
     }
 
-    if (mDrmManagerClient == NULL) {
-        return NULL;
-    }
-
-    if (mDecryptHandle == NULL) {
-        mDecryptHandle = mDrmManagerClient->openDecryptSession(
-                mFd, mOffset, mLength, mime);
-    }
-
-    if (mDecryptHandle == NULL) {
-        delete mDrmManagerClient;
-        mDrmManagerClient = NULL;
-    }
-
-    return mDecryptHandle;
+    return ::read(mFd, data, size);
 }
 
-ssize_t FileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
-    size_t DRM_CACHE_SIZE = 1024;
-    if (mDrmBuf == NULL) {
-        mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
+status_t FileSource::getSize(off64_t *size) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFd < 0) {
+        return NO_INIT;
     }
 
-    if (mDrmBuf != NULL && mDrmBufSize > 0 && (offset + mOffset) >= mDrmBufOffset
-            && (offset + mOffset + size) <= static_cast<size_t>(mDrmBufOffset + mDrmBufSize)) {
-        /* Use buffered data */
-        memcpy(data, (void*)(mDrmBuf+(offset+mOffset-mDrmBufOffset)), size);
-        return size;
-    } else if (size <= DRM_CACHE_SIZE) {
-        /* Buffer new data */
-        mDrmBufOffset =  offset + mOffset;
-        mDrmBufSize = mDrmManagerClient->pread(mDecryptHandle, mDrmBuf,
-                DRM_CACHE_SIZE, offset + mOffset);
-        if (mDrmBufSize > 0) {
-            int64_t dataRead = 0;
-            dataRead = size > static_cast<size_t>(mDrmBufSize) ? mDrmBufSize : size;
-            memcpy(data, (void*)mDrmBuf, dataRead);
-            return dataRead;
-        } else {
-            return mDrmBufSize;
-        }
-    } else {
-        /* Too big chunk to cache. Call DRM directly */
-        return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset);
-    }
-}
+    *size = mLength;
 
-/* static */
-bool FileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
-    std::unique_ptr<DrmManagerClient> drmClient(new DrmManagerClient());
-    sp<DecryptHandle> decryptHandle =
-            drmClient->openDecryptSession(fd, offset, length, mime);
-    bool requiresDrm = false;
-    if (decryptHandle != nullptr) {
-        requiresDrm = decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED;
-        drmClient->closeDecryptSession(decryptHandle);
-    }
-    return requiresDrm;
+    return OK;
 }
 
 }  // namespace android
diff --git a/media/libdatasource/MediaHTTP.cpp b/media/libdatasource/MediaHTTP.cpp
index e57510d..58c1ce8 100644
--- a/media/libdatasource/MediaHTTP.cpp
+++ b/media/libdatasource/MediaHTTP.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -20,7 +20,6 @@
 
 #include <datasource/MediaHTTP.h>
 
-#include <binder/IServiceManager.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/FoundationUtils.h>
@@ -30,45 +29,156 @@
 namespace android {
 
 MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
-    : ClearMediaHTTP(conn),
-      mDrmManagerClient(NULL) {
+    : mInitCheck((conn != NULL) ? OK : NO_INIT),
+      mHTTPConnection(conn),
+      mCachedSizeValid(false),
+      mCachedSize(0ll) {
 }
 
 MediaHTTP::~MediaHTTP() {
-    clearDRMState_l();
 }
 
-// DRM...
-
-sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
-    if (mDrmManagerClient == NULL) {
-        mDrmManagerClient = new DrmManagerClient();
+status_t MediaHTTP::connect(
+        const char *uri,
+        const KeyedVector<String8, String8> *headers,
+        off64_t /* offset */) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
     }
 
-    if (mDrmManagerClient == NULL) {
-        return NULL;
+    KeyedVector<String8, String8> extHeaders;
+    if (headers != NULL) {
+        extHeaders = *headers;
     }
 
-    if (mDecryptHandle == NULL) {
-        mDecryptHandle = mDrmManagerClient->openDecryptSession(
-                String8(mLastURI.c_str()), mime);
+    if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
+        extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
     }
 
-    if (mDecryptHandle == NULL) {
-        delete mDrmManagerClient;
-        mDrmManagerClient = NULL;
+    mLastURI = uri;
+    // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+    // as part of the above assignment. Ensure no accidental later use.
+    uri = NULL;
+
+    bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
+
+    mLastHeaders = extHeaders;
+
+    mCachedSizeValid = false;
+
+    if (success) {
+        AString sanitized = uriDebugString(mLastURI);
+        mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
     }
 
-    return mDecryptHandle;
+    return success ? OK : UNKNOWN_ERROR;
 }
 
-void MediaHTTP::clearDRMState_l() {
-    if (mDecryptHandle != NULL) {
-        // To release mDecryptHandle
-        CHECK(mDrmManagerClient);
-        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
-        mDecryptHandle = NULL;
+void MediaHTTP::close() {
+    disconnect();
+}
+
+void MediaHTTP::disconnect() {
+    mName = String8("MediaHTTP(<disconnected>)");
+    if (mInitCheck != OK) {
+        return;
     }
+
+    mHTTPConnection->disconnect();
+}
+
+status_t MediaHTTP::initCheck() const {
+    return mInitCheck;
+}
+
+ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    int64_t startTimeUs = ALooper::GetNowUs();
+
+    size_t numBytesRead = 0;
+    while (numBytesRead < size) {
+        size_t copy = size - numBytesRead;
+
+        if (copy > 64 * 1024) {
+            // limit the buffer sizes transferred across binder boundaries
+            // to avoid spurious transaction failures.
+            copy = 64 * 1024;
+        }
+
+        ssize_t n = mHTTPConnection->readAt(
+                offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
+
+        if (n < 0) {
+            return n;
+        } else if (n == 0) {
+            break;
+        }
+
+        numBytesRead += n;
+    }
+
+    int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+    addBandwidthMeasurement(numBytesRead, delayUs);
+
+    return numBytesRead;
+}
+
+status_t MediaHTTP::getSize(off64_t *size) {
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    // Caching the returned size so that it stays valid even after a
+    // disconnect. NuCachedSource2 relies on this.
+
+    if (!mCachedSizeValid) {
+        mCachedSize = mHTTPConnection->getSize();
+        mCachedSizeValid = true;
+    }
+
+    *size = mCachedSize;
+
+    return *size < 0 ? *size : static_cast<status_t>(OK);
+}
+
+uint32_t MediaHTTP::flags() {
+    return kWantsPrefetching | kIsHTTPBasedSource;
+}
+
+status_t MediaHTTP::reconnectAtOffset(off64_t offset) {
+    return connect(mLastURI.c_str(), &mLastHeaders, offset);
+}
+
+
+String8 MediaHTTP::getUri() {
+    if (mInitCheck != OK) {
+        return String8::empty();
+    }
+
+    String8 uri;
+    if (OK == mHTTPConnection->getUri(&uri)) {
+        return uri;
+    }
+    return String8(mLastURI.c_str());
+}
+
+String8 MediaHTTP::getMIMEType() const {
+    if (mInitCheck != OK) {
+        return String8("application/octet-stream");
+    }
+
+    String8 mimeType;
+    status_t err = mHTTPConnection->getMIMEType(&mimeType);
+
+    if (err != OK) {
+        return String8("application/octet-stream");
+    }
+
+    return mimeType;
 }
 
 }  // namespace android
diff --git a/media/libdatasource/include/datasource/ClearFileSource.h b/media/libdatasource/include/datasource/ClearFileSource.h
deleted file mode 100644
index be83748..0000000
--- a/media/libdatasource/include/datasource/ClearFileSource.h
+++ /dev/null
@@ -1,68 +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.
- */
-
-#ifndef CLEAR_FILE_SOURCE_H_
-
-#define CLEAR_FILE_SOURCE_H_
-
-#include <stdio.h>
-
-#include <media/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class ClearFileSource : public DataSource {
-public:
-    ClearFileSource(const char *filename);
-    // ClearFileSource takes ownership and will close the fd
-    ClearFileSource(int fd, int64_t offset, int64_t length);
-
-    virtual status_t initCheck() const;
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
-    virtual status_t getSize(off64_t *size);
-
-    virtual uint32_t flags() {
-        return kIsLocalFileSource;
-    }
-
-    virtual String8 toString() {
-        return mName;
-    }
-
-protected:
-    virtual ~ClearFileSource();
-    virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
-
-    int mFd;
-    int64_t mOffset;
-    int64_t mLength;
-    Mutex mLock;
-
-private:
-    String8 mName;
-
-    ClearFileSource(const ClearFileSource &);
-    ClearFileSource &operator=(const ClearFileSource &);
-};
-
-}  // namespace android
-
-#endif  // CLEAR_FILE_SOURCE_H_
-
diff --git a/media/libdatasource/include/datasource/ClearMediaHTTP.h b/media/libdatasource/include/datasource/ClearMediaHTTP.h
deleted file mode 100644
index 5440a3a..0000000
--- a/media/libdatasource/include/datasource/ClearMediaHTTP.h
+++ /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.
- */
-
-#ifndef CLEAR_MEDIA_HTTP_H_
-
-#define CLEAR_MEDIA_HTTP_H_
-
-#include <media/stagefright/foundation/AString.h>
-
-#include "HTTPBase.h"
-
-namespace android {
-
-struct MediaHTTPConnection;
-
-struct ClearMediaHTTP : public HTTPBase {
-    ClearMediaHTTP(const sp<MediaHTTPConnection> &conn);
-
-    virtual status_t connect(
-            const char *uri,
-            const KeyedVector<String8, String8> *headers,
-            off64_t offset);
-
-    virtual void close();
-
-    virtual void disconnect();
-
-    virtual status_t initCheck() const;
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
-    virtual status_t getSize(off64_t *size);
-
-    virtual uint32_t flags();
-
-    virtual status_t reconnectAtOffset(off64_t offset);
-
-protected:
-    virtual ~ClearMediaHTTP();
-
-    virtual String8 getUri();
-    virtual String8 getMIMEType() const;
-
-    AString mLastURI;
-
-private:
-    status_t mInitCheck;
-    sp<MediaHTTPConnection> mHTTPConnection;
-
-    KeyedVector<String8, String8> mLastHeaders;
-
-    bool mCachedSizeValid;
-    off64_t mCachedSize;
-
-    DISALLOW_EVIL_CONSTRUCTORS(ClearMediaHTTP);
-};
-
-}  // namespace android
-
-#endif  // CLEAR_MEDIA_HTTP_H_
diff --git a/media/libdatasource/include/datasource/DataSourceFactory.h b/media/libdatasource/include/datasource/DataSourceFactory.h
index 6e313d3..194abe2 100644
--- a/media/libdatasource/include/datasource/DataSourceFactory.h
+++ b/media/libdatasource/include/datasource/DataSourceFactory.h
@@ -29,17 +29,27 @@
 class String8;
 struct HTTPBase;
 
-class DataSourceFactory {
+class DataSourceFactory : public RefBase {
 public:
-    static sp<DataSource> CreateFromURI(
+    static sp<DataSourceFactory> getInstance();
+    sp<DataSource> CreateFromURI(
             const sp<MediaHTTPService> &httpService,
             const char *uri,
             const KeyedVector<String8, String8> *headers = NULL,
             String8 *contentType = NULL,
             HTTPBase *httpSource = NULL);
 
-    static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
-    static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+    virtual sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+    sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+
+protected:
+    virtual sp<DataSource> CreateFileSource(const char *uri);
+    DataSourceFactory() {};
+    virtual ~DataSourceFactory() {};
+
+private:
+    static sp<DataSourceFactory> sInstance;
+    static Mutex sInstanceLock;
 };
 
 }  // namespace android
diff --git a/media/libdatasource/include/datasource/FileSource.h b/media/libdatasource/include/datasource/FileSource.h
index 9249842..dee0c33 100644
--- a/media/libdatasource/include/datasource/FileSource.h
+++ b/media/libdatasource/include/datasource/FileSource.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -20,37 +20,43 @@
 
 #include <stdio.h>
 
-#include <datasource/ClearFileSource.h>
+#include <media/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/threads.h>
-#include <drm/DrmManagerClient.h>
 
 namespace android {
 
-class FileSource : public ClearFileSource {
+class FileSource : public DataSource {
 public:
     FileSource(const char *filename);
     // FileSource takes ownership and will close the fd
     FileSource(int fd, int64_t offset, int64_t length);
 
+    virtual status_t initCheck() const;
+
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
 
-    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
+    virtual status_t getSize(off64_t *size);
 
-    static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
+    virtual uint32_t flags() {
+        return kIsLocalFileSource;
+    }
+
+    virtual String8 toString() {
+        return mName;
+    }
 
 protected:
     virtual ~FileSource();
+    virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
+
+    int mFd;
+    int64_t mOffset;
+    int64_t mLength;
+    Mutex mLock;
 
 private:
-    /*for DRM*/
-    sp<DecryptHandle> mDecryptHandle;
-    DrmManagerClient *mDrmManagerClient;
-    int64_t mDrmBufOffset;
-    ssize_t mDrmBufSize;
-    unsigned char *mDrmBuf;
-
-    ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
+    String8 mName;
 
     FileSource(const FileSource &);
     FileSource &operator=(const FileSource &);
diff --git a/media/libdatasource/include/datasource/MediaHTTP.h b/media/libdatasource/include/datasource/MediaHTTP.h
index 60252ce..a8d203b 100644
--- a/media/libdatasource/include/datasource/MediaHTTP.h
+++ b/media/libdatasource/include/datasource/MediaHTTP.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * 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.
@@ -18,26 +18,52 @@
 
 #define MEDIA_HTTP_H_
 
-#include <datasource/ClearMediaHTTP.h>
 #include <media/stagefright/foundation/AString.h>
 
+#include "HTTPBase.h"
+
 namespace android {
 
 struct MediaHTTPConnection;
 
-struct MediaHTTP : public ClearMediaHTTP {
+struct MediaHTTP : public HTTPBase {
     MediaHTTP(const sp<MediaHTTPConnection> &conn);
 
+    virtual status_t connect(
+            const char *uri,
+            const KeyedVector<String8, String8> *headers,
+            off64_t offset);
+
+    virtual void close();
+
+    virtual void disconnect();
+
+    virtual status_t initCheck() const;
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual status_t getSize(off64_t *size);
+
+    virtual uint32_t flags();
+
+    virtual status_t reconnectAtOffset(off64_t offset);
+
 protected:
     virtual ~MediaHTTP();
 
-    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
+    virtual String8 getUri();
+    virtual String8 getMIMEType() const;
+
+    AString mLastURI;
 
 private:
-    sp<DecryptHandle> mDecryptHandle;
-    DrmManagerClient *mDrmManagerClient;
+    status_t mInitCheck;
+    sp<MediaHTTPConnection> mHTTPConnection;
 
-    void clearDRMState_l();
+    KeyedVector<String8, String8> mLastHeaders;
+
+    bool mCachedSizeValid;
+    off64_t mCachedSize;
 
     DISALLOW_EVIL_CONSTRUCTORS(MediaHTTP);
 };
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 4e99cb2..ac88448 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,29 @@
     ],
 }
 
-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",
+    ],
+    api_dir: "api/resourcemanager",
+    versions: ["1"],
+}
+
 cc_library_shared {
     name: "libmedia_omx",
     vendor_available: true,
@@ -63,7 +52,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 +115,6 @@
     },
 }
 
-
 cc_library_shared {
     name: "libmedia_omx_client",
 
@@ -197,6 +184,7 @@
     ],
 
     header_libs: [
+        "libmedia_headers",
         "media_ndk_headers",
     ],
 
@@ -277,16 +265,12 @@
         "IMediaSource.cpp",
         "IRemoteDisplay.cpp",
         "IRemoteDisplayClient.cpp",
-        "IResourceManagerClient.cpp",
-        "IResourceManagerService.cpp",
         "IStreamSource.cpp",
         "MediaUtils.cpp",
         "Metadata.cpp",
         "mediarecorder.cpp",
         "IMediaMetadataRetriever.cpp",
         "mediametadataretriever.cpp",
-        "MidiDeviceInfo.cpp",
-        "JetPlayer.cpp",
         "MediaScanner.cpp",
         "MediaScannerClient.cpp",
         "CharacterEncodingDetector.cpp",
@@ -294,7 +278,6 @@
         "MediaProfiles.cpp",
         "MediaResource.cpp",
         "MediaResourcePolicy.cpp",
-        "Visualizer.cpp",
         "StringArray.cpp",
         "NdkMediaFormatPriv.cpp",
         "NdkMediaErrorPriv.cpp",
@@ -330,7 +313,6 @@
         "libstagefright_foundation",
         "libgui",
         "libdl",
-        "libaudioutils",
         "libaudioclient",
         "libmedia_codeclist",
         "libmedia_omx",
@@ -345,8 +327,12 @@
     ],
 
     static_libs: [
-        "libc_malloc_debug_backtrace",  // for memory heap analysis
-        "libmedia_midiiowrapper",
+        "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/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/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
deleted file mode 100644
index 0d3c1ba..0000000
--- a/media/libmedia/JetPlayer.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (C) 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_NDEBUG 0
-#define LOG_TAG "JetPlayer-C"
-
-#include <utils/Log.h>
-#include <media/JetPlayer.h>
-
-
-namespace android
-{
-
-static const int MIX_NUM_BUFFERS = 4;
-static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
-        mEventCallback(NULL),
-        mJavaJetPlayerRef(javaJetPlayer),
-        mTid(-1),
-        mRender(false),
-        mPaused(false),
-        mMaxTracks(maxTracks),
-        mEasData(NULL),
-        mIoWrapper(NULL),
-        mTrackBufferSize(trackBufferSize)
-{
-    ALOGV("JetPlayer constructor");
-    mPreviousJetStatus.currentUserID = -1;
-    mPreviousJetStatus.segmentRepeatCount = -1;
-    mPreviousJetStatus.numQueuedSegments = -1;
-    mPreviousJetStatus.paused = true;
-}
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::~JetPlayer()
-{
-    ALOGV("~JetPlayer");
-    release();
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::init()
-{
-    //Mutex::Autolock lock(&mMutex);
-
-    EAS_RESULT result;
-
-    // retrieve the EAS library settings
-    if (pLibConfig == NULL)
-        pLibConfig = EAS_Config();
-    if (pLibConfig == NULL) {
-        ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
-        return EAS_FAILURE;
-    }
-
-    // init the EAS library
-    result = EAS_Init(&mEasData);
-    if (result != EAS_SUCCESS) {
-        ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
-        mState = EAS_STATE_ERROR;
-        return result;
-    }
-    // init the JET library with the default app event controller range
-    result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
-    if (result != EAS_SUCCESS) {
-        ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
-        mState = EAS_STATE_ERROR;
-        return result;
-    }
-
-    // create the output AudioTrack
-    mAudioTrack = new AudioTrack();
-    status_t status = mAudioTrack->set(AUDIO_STREAM_MUSIC,  //TODO parameterize this
-            pLibConfig->sampleRate,
-            AUDIO_FORMAT_PCM_16_BIT,
-            audio_channel_out_mask_from_count(pLibConfig->numChannels),
-            (size_t) mTrackBufferSize,
-            AUDIO_OUTPUT_FLAG_NONE);
-    if (status != OK) {
-        ALOGE("JetPlayer::init(): Error initializing JET library; AudioTrack error %d", status);
-        mAudioTrack.clear();
-        mState = EAS_STATE_ERROR;
-        return EAS_FAILURE;
-    }
-
-    // create render and playback thread
-    {
-        Mutex::Autolock l(mMutex);
-        ALOGV("JetPlayer::init(): trying to start render thread");
-        mThread = new JetPlayerThread(this);
-        mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
-        mCondition.wait(mMutex);
-    }
-    if (mTid > 0) {
-        // render thread started, we're ready
-        ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
-        mState = EAS_STATE_READY;
-    } else {
-        ALOGE("JetPlayer::init(): failed to start render thread.");
-        mState = EAS_STATE_ERROR;
-        return EAS_FAILURE;
-    }
-
-    return EAS_SUCCESS;
-}
-
-void JetPlayer::setEventCallback(jetevent_callback eventCallback)
-{
-    Mutex::Autolock l(mMutex);
-    mEventCallback = eventCallback;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::release()
-{
-    ALOGV("JetPlayer::release()");
-    Mutex::Autolock lock(mMutex);
-    mPaused = true;
-    mRender = false;
-    if (mEasData) {
-        JET_Pause(mEasData);
-        JET_CloseFile(mEasData);
-        JET_Shutdown(mEasData);
-        EAS_Shutdown(mEasData);
-    }
-    delete mIoWrapper;
-    mIoWrapper = NULL;
-    if (mAudioTrack != 0) {
-        mAudioTrack->stop();
-        mAudioTrack->flush();
-        mAudioTrack.clear();
-    }
-    if (mAudioBuffer) {
-        delete mAudioBuffer;
-        mAudioBuffer = NULL;
-    }
-    mEasData = NULL;
-
-    return EAS_SUCCESS;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::render() {
-    EAS_RESULT result = EAS_FAILURE;
-    EAS_I32 count;
-    int temp;
-    bool audioStarted = false;
-
-    ALOGV("JetPlayer::render(): entering");
-
-    // allocate render buffer
-    mAudioBuffer =
-        new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
-
-    // signal main thread that we started
-    {
-        Mutex::Autolock l(mMutex);
-        mTid = gettid();
-        ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
-        mCondition.signal();
-    }
-
-    while (1) {
-
-        mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
-
-        if (mEasData == NULL) {
-            mMutex.unlock();
-            ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
-            goto threadExit;
-        }
-
-        // nothing to render, wait for client thread to wake us up
-        while (!mRender)
-        {
-            ALOGV("JetPlayer::render(): signal wait");
-            if (audioStarted) {
-                mAudioTrack->pause();
-                // we have to restart the playback once we start rendering again
-                audioStarted = false;
-            }
-            mCondition.wait(mMutex);
-            ALOGV("JetPlayer::render(): signal rx'd");
-        }
-
-        // render midi data into the input buffer
-        int num_output = 0;
-        EAS_PCM* p = mAudioBuffer;
-        for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
-            result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
-            if (result != EAS_SUCCESS) {
-                ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
-            }
-            p += count * pLibConfig->numChannels;
-            num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
-
-            // send events that were generated (if any) to the event callback
-            fireEventsFromJetQueue();
-        }
-
-        // update playback state
-        //ALOGV("JetPlayer::render(): updating state");
-        JET_Status(mEasData, &mJetStatus);
-        fireUpdateOnStatusChange();
-        mPaused = mJetStatus.paused;
-
-        mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
-
-        // check audio output track
-        if (mAudioTrack == NULL) {
-            ALOGE("JetPlayer::render(): output AudioTrack was not created");
-            goto threadExit;
-        }
-
-        // Write data to the audio hardware
-        //ALOGV("JetPlayer::render(): writing to audio output");
-        if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
-            ALOGE("JetPlayer::render(): Error in writing:%d",temp);
-            return temp;
-        }
-
-        // start audio output if necessary
-        if (!audioStarted) {
-            ALOGV("JetPlayer::render(): starting audio playback");
-            mAudioTrack->start();
-            audioStarted = true;
-        }
-
-    }//while (1)
-
-threadExit:
-    if (mAudioTrack != NULL) {
-        mAudioTrack->stop();
-        mAudioTrack->flush();
-    }
-    delete [] mAudioBuffer;
-    mAudioBuffer = NULL;
-    mMutex.lock();
-    mTid = -1;
-    mCondition.signal();
-    mMutex.unlock();
-    return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up an update if any of the status fields has changed
-// precondition: mMutex locked
-void JetPlayer::fireUpdateOnStatusChange()
-{
-    if ( (mJetStatus.currentUserID      != mPreviousJetStatus.currentUserID)
-       ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
-        if (mEventCallback)  {
-            mEventCallback(
-                JetPlayer::JET_USERID_UPDATE,
-                mJetStatus.currentUserID,
-                mJetStatus.segmentRepeatCount,
-                mJavaJetPlayerRef);
-        }
-        mPreviousJetStatus.currentUserID      = mJetStatus.currentUserID;
-        mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
-    }
-
-    if (mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
-        if (mEventCallback)  {
-            mEventCallback(
-                JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
-                mJetStatus.numQueuedSegments,
-                -1,
-                mJavaJetPlayerRef);
-        }
-        mPreviousJetStatus.numQueuedSegments  = mJetStatus.numQueuedSegments;
-    }
-
-    if (mJetStatus.paused != mPreviousJetStatus.paused) {
-        if (mEventCallback)  {
-            mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
-                mJetStatus.paused,
-                -1,
-                mJavaJetPlayerRef);
-        }
-        mPreviousJetStatus.paused = mJetStatus.paused;
-    }
-
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up all the JET events in the JET engine queue (until the queue is empty)
-// precondition: mMutex locked
-void JetPlayer::fireEventsFromJetQueue()
-{
-    if (!mEventCallback) {
-        // no callback, just empty the event queue
-        while (JET_GetEvent(mEasData, NULL, NULL)) { }
-        return;
-    }
-
-    EAS_U32 rawEvent;
-    while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
-        mEventCallback(
-            JetPlayer::JET_EVENT,
-            rawEvent,
-            -1,
-            mJavaJetPlayerRef);
-    }
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFile(const char* path)
-{
-    ALOGV("JetPlayer::loadFromFile(): path=%s", path);
-
-    Mutex::Autolock lock(mMutex);
-
-    delete mIoWrapper;
-    mIoWrapper = new MidiIoWrapper(path);
-
-    EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
-    if (result != EAS_SUCCESS)
-        mState = EAS_STATE_ERROR;
-    else
-        mState = EAS_STATE_OPEN;
-    return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
-{
-    ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
-
-    Mutex::Autolock lock(mMutex);
-
-    delete mIoWrapper;
-    mIoWrapper = new MidiIoWrapper(fd, offset, length);
-
-    EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
-    if (result != EAS_SUCCESS)
-        mState = EAS_STATE_ERROR;
-    else
-        mState = EAS_STATE_OPEN;
-    return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::closeFile()
-{
-    Mutex::Autolock lock(mMutex);
-    return JET_CloseFile(mEasData);
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::play()
-{
-    ALOGV("JetPlayer::play(): entering");
-    Mutex::Autolock lock(mMutex);
-
-    EAS_RESULT result = JET_Play(mEasData);
-
-    mPaused = false;
-    mRender = true;
-
-    JET_Status(mEasData, &mJetStatus);
-    this->dumpJetStatus(&mJetStatus);
-
-    fireUpdateOnStatusChange();
-
-    // wake up render thread
-    ALOGV("JetPlayer::play(): wakeup render thread");
-    mCondition.signal();
-
-    return result;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::pause()
-{
-    Mutex::Autolock lock(mMutex);
-    mPaused = true;
-    EAS_RESULT result = JET_Pause(mEasData);
-
-    mRender = false;
-
-    JET_Status(mEasData, &mJetStatus);
-    this->dumpJetStatus(&mJetStatus);
-    fireUpdateOnStatusChange();
-
-
-    return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
-        EAS_U32 muteFlags, EAS_U8 userID)
-{
-    ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
-        segmentNum, libNum, repeatCount, transpose);
-    Mutex::Autolock lock(mMutex);
-    return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
-            userID);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
-{
-    Mutex::Autolock lock(mMutex);
-    return JET_SetMuteFlags(mEasData, muteFlags, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
-{
-    Mutex::Autolock lock(mMutex);
-    return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::triggerClip(int clipId)
-{
-    ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
-    Mutex::Autolock lock(mMutex);
-    return JET_TriggerClip(mEasData, clipId);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::clearQueue()
-{
-    ALOGV("JetPlayer::clearQueue");
-    Mutex::Autolock lock(mMutex);
-    return JET_Clear_Queue(mEasData);
-}
-
-//-------------------------------------------------------------------------------------------------
-void JetPlayer::dump()
-{
-}
-
-void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
-{
-    if (pJetStatus!=NULL)
-        ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
-                "paused=%d",
-                pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
-                pJetStatus->numQueuedSegments, pJetStatus->paused);
-    else
-        ALOGE(">> JET player status is NULL");
-}
-
-
-} // end namespace android
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index 8626009..fe86d27 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -23,39 +23,51 @@
 
 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) {}
-
-MediaResource::MediaResource(Type type, const std::vector<uint8_t> &id, uint64_t value)
-        : mType(type),
-          mSubType(kUnspecifiedSubType),
-          mValue(value),
-          mId(id) {}
-
-void MediaResource::readFromParcel(const Parcel &parcel) {
-    mType = static_cast<Type>(parcel.readInt32());
-    mSubType = static_cast<SubType>(parcel.readInt32());
-    mValue = parcel.readUint64();
-    parcel.readByteVector(&mId);
+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);
-    parcel->writeByteVector(mId);
+MediaResource::MediaResource(Type type, SubType subType, int64_t value) {
+    this->type = type;
+    this->subType = subType;
+    this->value = value;
+}
+
+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) {
@@ -66,24 +78,14 @@
     return str;
 }
 
-String8 MediaResource::toString() const {
+String8 toString(const MediaResourceParcel& resource) {
     String8 str;
-    str.appendFormat("%s/%s:[%s]:%llu",
-        asString(mType), asString(mSubType),
-        bytesToHexString(mId).c_str(),
-        (unsigned long long)mValue);
+
+    str.appendFormat("%s/%s:[%s]:%lld",
+            asString(resource.type), asString(resource.subType),
+            bytesToHexString(resource.id).c_str(),
+            (long long)resource.value);
     return str;
 }
 
-bool MediaResource::operator==(const MediaResource &other) const {
-    return (other.mType == mType)
-      && (other.mSubType == mSubType)
-      && (other.mValue == mValue)
-      && (other.mId == mId);
-}
-
-bool MediaResource::operator!=(const MediaResource &other) const {
-    return !(*this == other);
-}
-
 }; // 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/MidiDeviceInfo.cpp b/media/libmedia/MidiDeviceInfo.cpp
deleted file mode 100644
index 7588e00..0000000
--- a/media/libmedia/MidiDeviceInfo.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2016 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 "MidiDeviceInfo"
-
-#include <media/MidiDeviceInfo.h>
-
-#include <binder/Parcel.h>
-#include <log/log.h>
-#include <utils/Errors.h>
-#include <utils/String16.h>
-
-namespace android {
-namespace media {
-namespace midi {
-
-// The constant values need to be kept in sync with MidiDeviceInfo.java.
-// static
-const char* const MidiDeviceInfo::PROPERTY_NAME = "name";
-const char* const MidiDeviceInfo::PROPERTY_MANUFACTURER = "manufacturer";
-const char* const MidiDeviceInfo::PROPERTY_PRODUCT = "product";
-const char* const MidiDeviceInfo::PROPERTY_VERSION = "version";
-const char* const MidiDeviceInfo::PROPERTY_SERIAL_NUMBER = "serial_number";
-const char* const MidiDeviceInfo::PROPERTY_ALSA_CARD = "alsa_card";
-const char* const MidiDeviceInfo::PROPERTY_ALSA_DEVICE = "alsa_device";
-
-String16 MidiDeviceInfo::getProperty(const char* propertyName) {
-    String16 value;
-    if (mProperties.getString(String16(propertyName), &value)) {
-        return value;
-    } else {
-        return String16();
-    }
-}
-
-#define RETURN_IF_FAILED(calledOnce)                                     \
-    {                                                                    \
-        status_t returnStatus = calledOnce;                              \
-        if (returnStatus) {                                              \
-            ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
-            return returnStatus;                                         \
-         }                                                               \
-    }
-
-status_t MidiDeviceInfo::writeToParcel(Parcel* parcel) const {
-    // Needs to be kept in sync with code in MidiDeviceInfo.java
-    RETURN_IF_FAILED(parcel->writeInt32(mType));
-    RETURN_IF_FAILED(parcel->writeInt32(mId));
-    RETURN_IF_FAILED(parcel->writeInt32((int32_t)mInputPortNames.size()));
-    RETURN_IF_FAILED(parcel->writeInt32((int32_t)mOutputPortNames.size()));
-    RETURN_IF_FAILED(writeStringVector(parcel, mInputPortNames));
-    RETURN_IF_FAILED(writeStringVector(parcel, mOutputPortNames));
-    RETURN_IF_FAILED(parcel->writeInt32(mIsPrivate ? 1 : 0));
-    RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
-    // This corresponds to "extra" properties written by Java code
-    RETURN_IF_FAILED(mProperties.writeToParcel(parcel));
-    return OK;
-}
-
-status_t MidiDeviceInfo::readFromParcel(const Parcel* parcel) {
-    // Needs to be kept in sync with code in MidiDeviceInfo.java
-    RETURN_IF_FAILED(parcel->readInt32(&mType));
-    RETURN_IF_FAILED(parcel->readInt32(&mId));
-    int32_t inputPortCount;
-    RETURN_IF_FAILED(parcel->readInt32(&inputPortCount));
-    int32_t outputPortCount;
-    RETURN_IF_FAILED(parcel->readInt32(&outputPortCount));
-    RETURN_IF_FAILED(readStringVector(parcel, &mInputPortNames, inputPortCount));
-    RETURN_IF_FAILED(readStringVector(parcel, &mOutputPortNames, outputPortCount));
-    int32_t isPrivate;
-    RETURN_IF_FAILED(parcel->readInt32(&isPrivate));
-    mIsPrivate = isPrivate == 1;
-    RETURN_IF_FAILED(mProperties.readFromParcel(parcel));
-    // Ignore "extra" properties as they may contain Java Parcelables
-    return OK;
-}
-
-status_t MidiDeviceInfo::readStringVector(
-        const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength) {
-    std::unique_ptr<std::vector<std::unique_ptr<String16>>> v;
-    status_t result = parcel->readString16Vector(&v);
-    if (result != OK) return result;
-    vectorPtr->clear();
-    if (v.get() != nullptr) {
-        for (const auto& iter : *v) {
-            if (iter.get() != nullptr) {
-                vectorPtr->push_back(*iter);
-            } else {
-                vectorPtr->push_back(String16());
-            }
-        }
-    } else {
-        vectorPtr->resize(defaultLength);
-    }
-    return OK;
-}
-
-status_t MidiDeviceInfo::writeStringVector(Parcel* parcel, const Vector<String16>& vector) const {
-    std::vector<String16> v;
-    for (size_t i = 0; i < vector.size(); ++i) {
-        v.push_back(vector[i]);
-    }
-    return parcel->writeString16Vector(v);
-}
-
-// Vector does not define operator==
-static inline bool areVectorsEqual(const Vector<String16>& lhs, const Vector<String16>& rhs) {
-    if (lhs.size() != rhs.size()) return false;
-    for (size_t i = 0; i < lhs.size(); ++i) {
-        if (lhs[i] != rhs[i]) return false;
-    }
-    return true;
-}
-
-bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
-    return (lhs.mType == rhs.mType && lhs.mId == rhs.mId &&
-            areVectorsEqual(lhs.mInputPortNames, rhs.mInputPortNames) &&
-            areVectorsEqual(lhs.mOutputPortNames, rhs.mOutputPortNames) &&
-            lhs.mProperties == rhs.mProperties &&
-            lhs.mIsPrivate == rhs.mIsPrivate);
-}
-
-}  // namespace midi
-}  // namespace media
-}  // namespace android
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
deleted file mode 100644
index 2bf0802..0000000
--- a/media/libmedia/Visualizer.cpp
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
-**
-** Copyright 2010, 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 "Visualizer"
-#include <utils/Log.h>
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include <media/Visualizer.h>
-#include <audio_utils/fixedfft.h>
-#include <utils/Thread.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-Visualizer::Visualizer (const String16& opPackageName,
-         int32_t priority,
-         effect_callback_t cbf,
-         void* user,
-         audio_session_t sessionId)
-    :   AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId),
-        mCaptureRate(CAPTURE_RATE_DEF),
-        mCaptureSize(CAPTURE_SIZE_DEF),
-        mSampleRate(44100000),
-        mScalingMode(VISUALIZER_SCALING_MODE_NORMALIZED),
-        mMeasurementMode(MEASUREMENT_MODE_NONE),
-        mCaptureCallBack(NULL),
-        mCaptureCbkUser(NULL)
-{
-    initCaptureSize();
-}
-
-Visualizer::~Visualizer()
-{
-    ALOGV("Visualizer::~Visualizer()");
-    setEnabled(false);
-    setCaptureCallBack(NULL, NULL, 0, 0);
-}
-
-void Visualizer::release()
-{
-    ALOGV("Visualizer::release()");
-    setEnabled(false);
-    Mutex::Autolock _l(mCaptureLock);
-
-    mCaptureThread.clear();
-    mCaptureCallBack = NULL;
-    mCaptureCbkUser = NULL;
-    mCaptureFlags = 0;
-    mCaptureRate = 0;
-}
-
-status_t Visualizer::setEnabled(bool enabled)
-{
-    Mutex::Autolock _l(mCaptureLock);
-
-    sp<CaptureThread> t = mCaptureThread;
-    if (t != 0) {
-        if (enabled) {
-            if (t->exitPending()) {
-                mCaptureLock.unlock();
-                if (t->requestExitAndWait() == WOULD_BLOCK) {
-                    mCaptureLock.lock();
-                    ALOGE("Visualizer::enable() called from thread");
-                    return INVALID_OPERATION;
-                }
-                mCaptureLock.lock();
-            }
-        }
-        t->mLock.lock();
-    }
-
-    status_t status = AudioEffect::setEnabled(enabled);
-
-    if (t != 0) {
-        if (enabled && status == NO_ERROR) {
-            t->run("Visualizer");
-        } else {
-            t->requestExit();
-        }
-    }
-
-    if (t != 0) {
-        t->mLock.unlock();
-    }
-
-    return status;
-}
-
-status_t Visualizer::setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags,
-        uint32_t rate)
-{
-    if (rate > CAPTURE_RATE_MAX) {
-        return BAD_VALUE;
-    }
-    Mutex::Autolock _l(mCaptureLock);
-
-    if (mEnabled) {
-        return INVALID_OPERATION;
-    }
-
-    if (mCaptureThread != 0) {
-        mCaptureLock.unlock();
-        mCaptureThread->requestExitAndWait();
-        mCaptureLock.lock();
-    }
-
-    mCaptureThread.clear();
-    mCaptureCallBack = cbk;
-    mCaptureCbkUser = user;
-    mCaptureFlags = flags;
-    mCaptureRate = rate;
-
-    if (cbk != NULL) {
-        mCaptureThread = new CaptureThread(this, rate, ((flags & CAPTURE_CALL_JAVA) != 0));
-    }
-    ALOGV("setCaptureCallBack() rate: %d thread %p flags 0x%08x",
-            rate, mCaptureThread.get(), mCaptureFlags);
-    return NO_ERROR;
-}
-
-status_t Visualizer::setCaptureSize(uint32_t size)
-{
-    if (size > VISUALIZER_CAPTURE_SIZE_MAX ||
-        size < VISUALIZER_CAPTURE_SIZE_MIN ||
-        popcount(size) != 1) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock _l(mCaptureLock);
-    if (mEnabled) {
-        return INVALID_OPERATION;
-    }
-
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
-    *((int32_t *)p->data + 1)= size;
-    status_t status = setParameter(p);
-
-    ALOGV("setCaptureSize size %d  status %d p->status %d", size, status, p->status);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-        if (status == NO_ERROR) {
-            mCaptureSize = size;
-        }
-    }
-
-    return status;
-}
-
-status_t Visualizer::setScalingMode(uint32_t mode) {
-    if ((mode != VISUALIZER_SCALING_MODE_NORMALIZED)
-            && (mode != VISUALIZER_SCALING_MODE_AS_PLAYED)) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock _l(mCaptureLock);
-
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_SCALING_MODE;
-    *((int32_t *)p->data + 1)= mode;
-    status_t status = setParameter(p);
-
-    ALOGV("setScalingMode mode %d  status %d p->status %d", mode, status, p->status);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-        if (status == NO_ERROR) {
-            mScalingMode = mode;
-        }
-    }
-
-    return status;
-}
-
-status_t Visualizer::setMeasurementMode(uint32_t mode) {
-    if ((mode != MEASUREMENT_MODE_NONE)
-            //Note: needs to be handled as a mask when more measurement modes are added
-            && ((mode & MEASUREMENT_MODE_PEAK_RMS) != mode)) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock _l(mCaptureLock);
-
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_MEASUREMENT_MODE;
-    *((int32_t *)p->data + 1)= mode;
-    status_t status = setParameter(p);
-
-    ALOGV("setMeasurementMode mode %d  status %d p->status %d", mode, status, p->status);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-        if (status == NO_ERROR) {
-            mMeasurementMode = mode;
-        }
-    }
-    return status;
-}
-
-status_t Visualizer::getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements) {
-    if (mMeasurementMode == MEASUREMENT_MODE_NONE) {
-        ALOGE("Cannot retrieve int measurements, no measurement mode set");
-        return INVALID_OPERATION;
-    }
-    if (!(mMeasurementMode & type)) {
-        // measurement type has not been set on this Visualizer
-        ALOGE("Cannot retrieve int measurements, requested measurement mode 0x%x not set(0x%x)",
-                type, mMeasurementMode);
-        return INVALID_OPERATION;
-    }
-    // only peak+RMS measurement supported
-    if ((type != MEASUREMENT_MODE_PEAK_RMS)
-            // for peak+RMS measurement, the results are 2 int32_t values
-            || (number != 2)) {
-        ALOGE("Cannot retrieve int measurements, MEASUREMENT_MODE_PEAK_RMS returns 2 ints, not %d",
-                        number);
-        return BAD_VALUE;
-    }
-
-    status_t status = NO_ERROR;
-    if (mEnabled) {
-        uint32_t replySize = number * sizeof(int32_t);
-        status = command(VISUALIZER_CMD_MEASURE,
-                sizeof(uint32_t)  /*cmdSize*/,
-                &type /*cmdData*/,
-                &replySize, measurements);
-        ALOGV("getMeasurements() command returned %d", status);
-        if ((status == NO_ERROR) && (replySize == 0)) {
-            status = NOT_ENOUGH_DATA;
-        }
-    } else {
-        ALOGV("getMeasurements() disabled");
-        return INVALID_OPERATION;
-    }
-    return status;
-}
-
-status_t Visualizer::getWaveForm(uint8_t *waveform)
-{
-    if (waveform == NULL) {
-        return BAD_VALUE;
-    }
-    if (mCaptureSize == 0) {
-        return NO_INIT;
-    }
-
-    status_t status = NO_ERROR;
-    if (mEnabled) {
-        uint32_t replySize = mCaptureSize;
-        status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
-        ALOGV("getWaveForm() command returned %d", status);
-        if ((status == NO_ERROR) && (replySize == 0)) {
-            status = NOT_ENOUGH_DATA;
-        }
-    } else {
-        ALOGV("getWaveForm() disabled");
-        memset(waveform, 0x80, mCaptureSize);
-    }
-    return status;
-}
-
-status_t Visualizer::getFft(uint8_t *fft)
-{
-    if (fft == NULL) {
-        return BAD_VALUE;
-    }
-    if (mCaptureSize == 0) {
-        return NO_INIT;
-    }
-
-    status_t status = NO_ERROR;
-    if (mEnabled) {
-        uint8_t buf[mCaptureSize];
-        status = getWaveForm(buf);
-        if (status == NO_ERROR) {
-            status = doFft(fft, buf);
-        }
-    } else {
-        memset(fft, 0, mCaptureSize);
-    }
-    return status;
-}
-
-status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
-{
-    int32_t workspace[mCaptureSize >> 1];
-    int32_t nonzero = 0;
-
-    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
-        workspace[i >> 1] =
-                ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
-        nonzero |= workspace[i >> 1];
-    }
-
-    if (nonzero) {
-        fixed_fft_real(mCaptureSize >> 1, workspace);
-    }
-
-    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
-        short tmp = workspace[i >> 1] >> 21;
-        while (tmp > 127 || tmp < -128) tmp >>= 1;
-        fft[i] = tmp;
-        tmp = workspace[i >> 1];
-        tmp >>= 5;
-        while (tmp > 127 || tmp < -128) tmp >>= 1;
-        fft[i + 1] = tmp;
-    }
-
-    return NO_ERROR;
-}
-
-void Visualizer::periodicCapture()
-{
-    Mutex::Autolock _l(mCaptureLock);
-    ALOGV("periodicCapture() %p mCaptureCallBack %p mCaptureFlags 0x%08x",
-            this, mCaptureCallBack, mCaptureFlags);
-    if (mCaptureCallBack != NULL &&
-        (mCaptureFlags & (CAPTURE_WAVEFORM|CAPTURE_FFT)) &&
-        mCaptureSize != 0) {
-        uint8_t waveform[mCaptureSize];
-        status_t status = getWaveForm(waveform);
-        if (status != NO_ERROR) {
-            return;
-        }
-        uint8_t fft[mCaptureSize];
-        if (mCaptureFlags & CAPTURE_FFT) {
-            status = doFft(fft, waveform);
-        }
-        if (status != NO_ERROR) {
-            return;
-        }
-        uint8_t *wavePtr = NULL;
-        uint8_t *fftPtr = NULL;
-        uint32_t waveSize = 0;
-        uint32_t fftSize = 0;
-        if (mCaptureFlags & CAPTURE_WAVEFORM) {
-            wavePtr = waveform;
-            waveSize = mCaptureSize;
-        }
-        if (mCaptureFlags & CAPTURE_FFT) {
-            fftPtr = fft;
-            fftSize = mCaptureSize;
-        }
-        mCaptureCallBack(mCaptureCbkUser, waveSize, wavePtr, fftSize, fftPtr, mSampleRate);
-    }
-}
-
-uint32_t Visualizer::initCaptureSize()
-{
-    uint32_t buf32[sizeof(effect_param_t) / sizeof(uint32_t) + 2];
-    effect_param_t *p = (effect_param_t *)buf32;
-
-    p->psize = sizeof(uint32_t);
-    p->vsize = sizeof(uint32_t);
-    *(int32_t *)p->data = VISUALIZER_PARAM_CAPTURE_SIZE;
-    status_t status = getParameter(p);
-
-    if (status == NO_ERROR) {
-        status = p->status;
-    }
-
-    uint32_t size = 0;
-    if (status == NO_ERROR) {
-        size = *((int32_t *)p->data + 1);
-    }
-    mCaptureSize = size;
-
-    ALOGV("initCaptureSize size %d status %d", mCaptureSize, status);
-
-    return size;
-}
-
-void Visualizer::controlStatusChanged(bool controlGranted) {
-    if (controlGranted) {
-        // this Visualizer instance regained control of the effect, reset the scaling mode
-        //   and capture size as has been cached through it.
-        ALOGV("controlStatusChanged(true) causes effect parameter reset:");
-        ALOGV("    scaling mode reset to %d", mScalingMode);
-        setScalingMode(mScalingMode);
-        ALOGV("    capture size reset to %d", mCaptureSize);
-        setCaptureSize(mCaptureSize);
-    }
-    AudioEffect::controlStatusChanged(controlGranted);
-}
-
-//-------------------------------------------------------------------------
-
-Visualizer::CaptureThread::CaptureThread(Visualizer* receiver, uint32_t captureRate,
-        bool bCanCallJava)
-    : Thread(bCanCallJava), mReceiver(receiver)
-{
-    mSleepTimeUs = 1000000000 / captureRate;
-    ALOGV("CaptureThread cstor %p captureRate %d mSleepTimeUs %d", this, captureRate, mSleepTimeUs);
-}
-
-bool Visualizer::CaptureThread::threadLoop()
-{
-    ALOGV("CaptureThread %p enter", this);
-    sp<Visualizer> receiver = mReceiver.promote();
-    if (receiver == NULL) {
-        return false;
-    }
-    while (!exitPending())
-    {
-        usleep(mSleepTimeUs);
-        receiver->periodicCapture();
-    }
-    ALOGV("CaptureThread %p exiting", this);
-    return false;
-}
-
-} // namespace android
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/api/resourcemanager/1/.hash b/media/libmedia/api/resourcemanager/1/.hash
new file mode 100644
index 0000000..e56d56b
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/1/.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/api/resourcemanager/1/android/media/IResourceManagerClient.aidl b/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerClient.aidl
new file mode 100644
index 0000000..20bfe72
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/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/api/resourcemanager/1/android/media/IResourceManagerService.aidl b/media/libmedia/api/resourcemanager/1/android/media/IResourceManagerService.aidl
new file mode 100644
index 0000000..53cf036
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/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/api/resourcemanager/1/android/media/MediaResourceParcel.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceParcel.aidl
new file mode 100644
index 0000000..47ea9bc
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/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/api/resourcemanager/1/android/media/MediaResourcePolicyParcel.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourcePolicyParcel.aidl
new file mode 100644
index 0000000..85d2588
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/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/api/resourcemanager/1/android/media/MediaResourceSubType.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceSubType.aidl
new file mode 100644
index 0000000..19b68af
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/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/api/resourcemanager/1/android/media/MediaResourceType.aidl b/media/libmedia/api/resourcemanager/1/android/media/MediaResourceType.aidl
new file mode 100644
index 0000000..6a123fc
--- /dev/null
+++ b/media/libmedia/api/resourcemanager/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/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/JetPlayer.h b/media/libmedia/include/media/JetPlayer.h
deleted file mode 100644
index bb569bc..0000000
--- a/media/libmedia/include/media/JetPlayer.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 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 JETPLAYER_H_
-#define JETPLAYER_H_
-
-#include <utils/threads.h>
-
-#include <libsonivox/jet.h>
-#include <libsonivox/eas_types.h>
-#include <media/AudioTrack.h>
-#include <media/MidiIoWrapper.h>
-
-
-namespace android {
-
-typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
-
-class JetPlayer {
-
-public:
-
-    // to keep in sync with the JetPlayer class constants
-    // defined in frameworks/base/media/java/android/media/JetPlayer.java
-    static const int JET_EVENT                   = 1;
-    static const int JET_USERID_UPDATE           = 2;
-    static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
-    static const int JET_PAUSE_UPDATE            = 4;
-
-    JetPlayer(void *javaJetPlayer,
-            int maxTracks = 32,
-            int trackBufferSize = 1200);
-    ~JetPlayer();
-    int init();
-    int release();
-
-    int loadFromFile(const char* url);
-    int loadFromFD(const int fd, const long long offset, const long long length);
-    int closeFile();
-    int play();
-    int pause();
-    int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
-            EAS_U32 muteFlags, EAS_U8 userID);
-    int setMuteFlags(EAS_U32 muteFlags, bool sync);
-    int setMuteFlag(int trackNum, bool muteFlag, bool sync);
-    int triggerClip(int clipId);
-    int clearQueue();
-
-    void setEventCallback(jetevent_callback callback);
-
-    int getMaxTracks() { return mMaxTracks; };
-
-
-private:
-    int                 render();
-    void                fireUpdateOnStatusChange();
-    void                fireEventsFromJetQueue();
-
-    JetPlayer() {} // no default constructor
-    void dump();
-    void dumpJetStatus(S_JET_STATUS* pJetStatus);
-
-    jetevent_callback   mEventCallback;
-
-    void*               mJavaJetPlayerRef;
-    Mutex               mMutex; // mutex to sync the render and playback thread with the JET calls
-    pid_t               mTid;
-    Condition           mCondition;
-    volatile bool       mRender;
-    bool                mPaused;
-
-    EAS_STATE           mState;
-    int*                mMemFailedVar;
-
-    int                 mMaxTracks; // max number of MIDI tracks, usually 32
-    EAS_DATA_HANDLE     mEasData;
-    MidiIoWrapper*      mIoWrapper;
-    EAS_PCM*            mAudioBuffer;// EAS renders the MIDI data into this buffer,
-    sp<AudioTrack>      mAudioTrack; // and we play it in this audio track
-    int                 mTrackBufferSize;
-    S_JET_STATUS        mJetStatus;
-    S_JET_STATUS        mPreviousJetStatus;
-
-    class JetPlayerThread : public Thread {
-    public:
-        JetPlayerThread(JetPlayer *player) : mPlayer(player) {
-        }
-
-    protected:
-        virtual ~JetPlayerThread() {}
-
-    private:
-        JetPlayer *mPlayer;
-
-        bool threadLoop() {
-            int result;
-            result = mPlayer->render();
-            return false;
-        }
-
-        JetPlayerThread(const JetPlayerThread &);
-        JetPlayerThread &operator=(const JetPlayerThread &);
-    };
-
-    sp<JetPlayerThread> mThread;
-
-}; // end class JetPlayer
-
-} // end namespace android
-
-
-
-#endif /*JETPLAYER_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/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index e9684f0..caf03b1 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -18,72 +18,55 @@
 #ifndef ANDROID_MEDIA_RESOURCE_H
 #define ANDROID_MEDIA_RESOURCE_H
 
-#include <binder/Parcel.h>
-#include <utils/String8.h>
-#include <vector>
+#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,
-        kDrmSession,
-    };
+    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);
-    MediaResource(Type type, const std::vector<uint8_t> &id, 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;
-    // for kDrmSession-type mId is the unique session id obtained via MediaDrm#openSession
-    std::vector<uint8_t> mId;
+    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";
-        case MediaResource::kDrmSession:     return "drm-session";
-        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/MidiDeviceInfo.h b/media/libmedia/include/media/MidiDeviceInfo.h
deleted file mode 100644
index 5b4a241..0000000
--- a/media/libmedia/include/media/MidiDeviceInfo.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 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_MEDIA_MIDI_DEVICE_INFO_H
-#define ANDROID_MEDIA_MIDI_DEVICE_INFO_H
-
-#include <binder/Parcelable.h>
-#include <binder/PersistableBundle.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace media {
-namespace midi {
-
-class MidiDeviceInfo : public Parcelable {
-public:
-    MidiDeviceInfo() = default;
-    virtual ~MidiDeviceInfo() = default;
-    MidiDeviceInfo(const MidiDeviceInfo& midiDeviceInfo) = default;
-
-    status_t writeToParcel(Parcel* parcel) const override;
-    status_t readFromParcel(const Parcel* parcel) override;
-
-    int getType() const { return mType; }
-    int getUid() const { return mId; }
-    bool isPrivate() const { return mIsPrivate; }
-    const Vector<String16>& getInputPortNames() const { return mInputPortNames; }
-    const Vector<String16>&  getOutputPortNames() const { return mOutputPortNames; }
-    String16 getProperty(const char* propertyName);
-
-    // The constants need to be kept in sync with MidiDeviceInfo.java
-    enum {
-        TYPE_USB = 1,
-        TYPE_VIRTUAL = 2,
-        TYPE_BLUETOOTH = 3,
-    };
-    static const char* const PROPERTY_NAME;
-    static const char* const PROPERTY_MANUFACTURER;
-    static const char* const PROPERTY_PRODUCT;
-    static const char* const PROPERTY_VERSION;
-    static const char* const PROPERTY_SERIAL_NUMBER;
-    static const char* const PROPERTY_ALSA_CARD;
-    static const char* const PROPERTY_ALSA_DEVICE;
-
-    friend bool operator==(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs);
-    friend bool operator!=(const MidiDeviceInfo& lhs, const MidiDeviceInfo& rhs) {
-        return !(lhs == rhs);
-    }
-
-private:
-    status_t readStringVector(
-            const Parcel* parcel, Vector<String16> *vectorPtr, size_t defaultLength);
-    status_t writeStringVector(Parcel* parcel, const Vector<String16>& vector) const;
-
-    int32_t mType;
-    int32_t mId;
-    Vector<String16> mInputPortNames;
-    Vector<String16> mOutputPortNames;
-    os::PersistableBundle mProperties;
-    bool mIsPrivate;
-};
-
-}  // namespace midi
-}  // namespace media
-}  // namespace android
-
-#endif  // ANDROID_MEDIA_MIDI_DEVICE_INFO_H
diff --git a/media/libmedia/include/media/Visualizer.h b/media/libmedia/include/media/Visualizer.h
deleted file mode 100644
index 8078e36..0000000
--- a/media/libmedia/include/media/Visualizer.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2010 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_MEDIA_VISUALIZER_H
-#define ANDROID_MEDIA_VISUALIZER_H
-
-#include <media/AudioEffect.h>
-#include <system/audio_effects/effect_visualizer.h>
-#include <utils/Thread.h>
-
-/**
- * The Visualizer class enables application to retrieve part of the currently playing audio for
- * visualization purpose. It is not an audio recording interface and only returns partial and low
- * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
- * of the visualizer requires the permission android.permission.RECORD_AUDIO.
- * The audio session ID passed to the constructor indicates which audio content should be
- * visualized:
- * - If the session is 0, the audio output mix is visualized
- * - If the session is not 0, the audio from a particular MediaPlayer or AudioTrack
- *   using this audio session is visualized
- * Two types of representation of audio content can be captured:
- * - Waveform data: consecutive 8-bit (unsigned) mono samples by using the getWaveForm() method
- * - Frequency data: 8-bit magnitude FFT by using the getFft() method
- *
- * The length of the capture can be retrieved or specified by calling respectively
- * getCaptureSize() and setCaptureSize() methods. Note that the size of the FFT
- * is half of the specified capture size but both sides of the spectrum are returned yielding in a
- * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
- * returned by getMinCaptureSize() and getMaxCaptureSize().
- * In addition to the polling capture mode, a callback mode is also available by installing a
- * callback function by use of the setCaptureCallBack() method. The rate at which the callback
- * is called as well as the type of data returned is specified.
- * Before capturing data, the Visualizer must be enabled by calling the setEnabled() method.
- * When data capture is not needed any more, the Visualizer should be disabled.
- */
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class Visualizer: public AudioEffect {
-public:
-
-    enum callback_flags {
-        CAPTURE_WAVEFORM = 0x00000001,  // capture callback returns a PCM wave form
-        CAPTURE_FFT = 0x00000002,       // apture callback returns a frequency representation
-        CAPTURE_CALL_JAVA = 0x00000004  // the callback thread can call java
-    };
-
-
-    /* Constructor.
-     * See AudioEffect constructor for details on parameters.
-     */
-                        Visualizer(const String16& opPackageName,
-                                   int32_t priority = 0,
-                                   effect_callback_t cbf = NULL,
-                                   void* user = NULL,
-                                   audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX);
-
-                        ~Visualizer();
-
-    virtual status_t    setEnabled(bool enabled);
-
-    // maximum capture size in samples
-    static uint32_t getMaxCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MAX; }
-    // minimum capture size in samples
-    static uint32_t getMinCaptureSize() { return VISUALIZER_CAPTURE_SIZE_MIN; }
-    // maximum capture rate in millihertz
-    static uint32_t getMaxCaptureRate() { return CAPTURE_RATE_MAX; }
-
-    // callback used to return periodic PCM or FFT captures to the application. Either one or both
-    // types of data are returned (PCM and FFT) according to flags indicated when installing the
-    // callback. When a type of data is not present, the corresponding size (waveformSize or
-    // fftSize) is 0.
-    typedef void (*capture_cbk_t)(void* user,
-                                    uint32_t waveformSize,
-                                    uint8_t *waveform,
-                                    uint32_t fftSize,
-                                    uint8_t *fft,
-                                    uint32_t samplingrate);
-
-    // install a callback to receive periodic captures. The capture rate is specified in milliHertz
-    // and the capture format is according to flags  (see callback_flags).
-    status_t setCaptureCallBack(capture_cbk_t cbk, void* user, uint32_t flags, uint32_t rate);
-
-    // set the capture size capture size must be a power of two in the range
-    // [VISUALIZER_CAPTURE_SIZE_MAX. VISUALIZER_CAPTURE_SIZE_MIN]
-    // must be called when the visualizer is not enabled
-    status_t setCaptureSize(uint32_t size);
-    uint32_t getCaptureSize() { return mCaptureSize; }
-
-    // returns the capture rate indicated when installing the callback
-    uint32_t getCaptureRate() { return mCaptureRate; }
-
-    // returns the sampling rate of the audio being captured
-    uint32_t getSamplingRate() { return mSampleRate; }
-
-    // set the way volume affects the captured data
-    // mode must one of VISUALIZER_SCALING_MODE_NORMALIZED,
-    //  VISUALIZER_SCALING_MODE_AS_PLAYED
-    status_t setScalingMode(uint32_t mode);
-    uint32_t getScalingMode() { return mScalingMode; }
-
-    // set which measurements are done on the audio buffers processed by the effect.
-    // valid measurements (mask): MEASUREMENT_MODE_PEAK_RMS
-    status_t setMeasurementMode(uint32_t mode);
-    uint32_t getMeasurementMode() { return mMeasurementMode; }
-
-    // return a set of int32_t measurements
-    status_t getIntMeasurements(uint32_t type, uint32_t number, int32_t *measurements);
-
-    // return a capture in PCM 8 bit unsigned format. The size of the capture is equal to
-    // getCaptureSize()
-    status_t getWaveForm(uint8_t *waveform);
-
-    // return a capture in FFT 8 bit signed format. The size of the capture is equal to
-    // getCaptureSize() but the length of the FFT is half of the size (both parts of the spectrum
-    // are returned
-    status_t getFft(uint8_t *fft);
-    void release();
-
-protected:
-    // from IEffectClient
-    virtual void controlStatusChanged(bool controlGranted);
-
-private:
-
-    static const uint32_t CAPTURE_RATE_MAX = 20000;
-    static const uint32_t CAPTURE_RATE_DEF = 10000;
-    static const uint32_t CAPTURE_SIZE_DEF = VISUALIZER_CAPTURE_SIZE_MAX;
-
-    /* internal class to handle the callback */
-    class CaptureThread : public Thread
-    {
-    public:
-        CaptureThread(Visualizer* visualizer, uint32_t captureRate, bool bCanCallJava = false);
-
-    private:
-        friend class Visualizer;
-        virtual bool        threadLoop();
-        wp<Visualizer> mReceiver;
-        Mutex       mLock;
-        uint32_t mSleepTimeUs;
-    };
-
-    status_t doFft(uint8_t *fft, uint8_t *waveform);
-    void periodicCapture();
-    uint32_t initCaptureSize();
-
-    Mutex mCaptureLock;
-    uint32_t mCaptureRate;
-    uint32_t mCaptureSize;
-    uint32_t mSampleRate;
-    uint32_t mScalingMode;
-    uint32_t mMeasurementMode;
-    capture_cbk_t mCaptureCallBack;
-    void *mCaptureCbkUser;
-    sp<CaptureThread> mCaptureThread;
-    uint32_t mCaptureFlags;
-};
-
-
-}; // namespace android
-
-#endif // ANDROID_MEDIA_VISUALIZER_H
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/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 100%
rename from media/libmedia/TypeConverter.cpp
rename to media/libmediahelper/TypeConverter.cpp
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libmediahelper/include/media/AudioParameter.h
similarity index 100%
rename from media/libaudioclient/include/media/AudioParameter.h
rename to media/libmediahelper/include/media/AudioParameter.h
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmediahelper/include/media/TypeConverter.h
similarity index 100%
rename from media/libmedia/include/media/TypeConverter.h
rename to media/libmediahelper/include/media/TypeConverter.h
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/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 b7856a6..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,26 +45,6 @@
 // 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);
-    return item;
-}
-
 MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
     MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
     return item;
@@ -74,34 +55,6 @@
     return handle;
 }
 
-// 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;
-}
-
 MediaAnalyticsItem::~MediaAnalyticsItem() {
     if (DEBUG_ALLOCATIONS) {
         ALOGD("Destroy  MediaAnalyticsItem @ %p", this);
@@ -114,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) {
@@ -143,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;
     }
@@ -158,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;
@@ -228,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;
@@ -320,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--;
         }
@@ -552,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) {
@@ -648,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;
@@ -662,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() {
@@ -795,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),
@@ -825,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);
@@ -846,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);
@@ -856,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) {
@@ -903,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;
@@ -928,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> &) {
@@ -959,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.
@@ -1046,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
@@ -1068,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;
         }
     }
 
@@ -1081,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 360ae0c..cf268e0 100644
--- a/media/libmediametrics/MediaMetrics.cpp
+++ b/media/libmediametrics/MediaMetrics.cpp
@@ -195,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/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 42a2f5b..5558211 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -19,6 +19,7 @@
 
 #include "MediaMetrics.h"
 
+#include <algorithm>
 #include <string>
 #include <sys/types.h>
 
@@ -34,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,
@@ -56,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,
@@ -84,17 +99,40 @@
             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 *);
@@ -102,67 +140,119 @@
         // 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.
@@ -184,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
@@ -212,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/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 6701017..5301f5c 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -7,6 +7,7 @@
         "MediaPlayerService.cpp",
         "MediaRecorderClient.cpp",
         "MetadataRetrieverClient.cpp",
+        "StagefrightMetadataRetriever.cpp",
         "StagefrightRecorder.cpp",
         "TestPlayerStub.cpp",
     ],
@@ -23,6 +24,7 @@
         "libcutils",
         "libdatasource",
         "libdl",
+        "libdrmframework",
         "libgui",
         "libhidlbase",
         "liblog",
@@ -46,6 +48,7 @@
     ],
 
     static_libs: [
+        "libplayerservice_datasource",
         "libstagefright_nuplayer",
         "libstagefright_rtsp",
         "libstagefright_timedtext",
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/libstagefright/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
similarity index 98%
rename from media/libstagefright/StagefrightMetadataRetriever.cpp
rename to media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 48aee18..41b6f72 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -22,11 +22,11 @@
 #include <utils/Log.h>
 #include <cutils/properties.h>
 
-#include "include/FrameDecoder.h"
-#include "include/StagefrightMetadataRetriever.h"
+#include "StagefrightMetadataRetriever.h"
+#include "FrameDecoder.h"
 
-#include <datasource/DataSourceFactory.h>
-#include <datasource/FileSource.h>
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -63,7 +63,8 @@
     ALOGV("setDataSource(%s)", uri);
 
     clearMetadata();
-    mSource = DataSourceFactory::CreateFromURI(httpService, uri, headers);
+    mSource = PlayerServiceDataSourceFactory::getInstance()->CreateFromURI(
+            httpService, uri, headers);
 
     if (mSource == NULL) {
         ALOGE("Unable to create data source for '%s'.", uri);
@@ -91,7 +92,7 @@
     ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
 
     clearMetadata();
-    mSource = new FileSource(fd, offset, length);
+    mSource = new PlayerServiceFileSource(fd, offset, length);
 
     status_t err;
     if ((err = mSource->initCheck()) != OK) {
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
similarity index 100%
rename from media/libstagefright/include/StagefrightMetadataRetriever.h
rename to media/libmediaplayerservice/StagefrightMetadataRetriever.h
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/datasource/Android.bp b/media/libmediaplayerservice/datasource/Android.bp
new file mode 100644
index 0000000..71fa50b
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/Android.bp
@@ -0,0 +1,43 @@
+cc_library_static {
+    name: "libplayerservice_datasource",
+
+    srcs: [
+        "PlayerServiceDataSourceFactory.cpp",
+        "PlayerServiceFileSource.cpp",
+        "PlayerServiceMediaHTTP.cpp",
+    ],
+
+    header_libs: [
+        "media_ndk_headers",
+        "libmedia_headers",
+    ],
+
+    shared_libs: [
+        "libdatasource",
+        "libdrmframework",
+        "liblog",
+        "libutils",
+    ],
+
+    local_include_dirs: [
+        "include",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp b/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp
new file mode 100644
index 0000000..ef946e9
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/PlayerServiceDataSourceFactory.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ * 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 "PlayerServuceDataSourceFactory"
+
+
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
+#include <datasource/PlayerServiceMediaHTTP.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+
+namespace android {
+
+// static
+sp<PlayerServiceDataSourceFactory> PlayerServiceDataSourceFactory::sInstance;
+// static
+Mutex PlayerServiceDataSourceFactory::sInstanceLock;
+
+// static
+sp<PlayerServiceDataSourceFactory> PlayerServiceDataSourceFactory::getInstance() {
+    Mutex::Autolock l(sInstanceLock);
+    if (!sInstance) {
+        sInstance = new PlayerServiceDataSourceFactory();
+    }
+    return sInstance;
+}
+
+sp<DataSource> PlayerServiceDataSourceFactory::CreateMediaHTTP(
+        const sp<MediaHTTPService> &httpService) {
+    if (httpService == NULL) {
+        return NULL;
+    }
+
+    sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+    if (conn == NULL) {
+        ALOGE("Failed to make http connection from http service!");
+        return NULL;
+    } else {
+        return new PlayerServiceMediaHTTP(conn);
+    }
+}
+
+sp<DataSource> PlayerServiceDataSourceFactory::CreateFileSource(const char *uri) {
+    return new PlayerServiceFileSource(uri);
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
new file mode 100644
index 0000000..1580891
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/PlayerServiceFileSource.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 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 "PlayerServiceFileSource"
+#include <utils/Log.h>
+
+#include <datasource/PlayerServiceFileSource.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+PlayerServiceFileSource::PlayerServiceFileSource(const char *filename)
+    : FileSource(filename),
+      mDecryptHandle(NULL),
+      mDrmManagerClient(NULL),
+      mDrmBufOffset(0),
+      mDrmBufSize(0),
+      mDrmBuf(NULL){
+}
+
+PlayerServiceFileSource::PlayerServiceFileSource(int fd, int64_t offset, int64_t length)
+    : FileSource(fd, offset, length),
+      mDecryptHandle(NULL),
+      mDrmManagerClient(NULL),
+      mDrmBufOffset(0),
+      mDrmBufSize(0),
+      mDrmBuf(NULL) {
+}
+
+PlayerServiceFileSource::~PlayerServiceFileSource() {
+    if (mDrmBuf != NULL) {
+        delete[] mDrmBuf;
+        mDrmBuf = NULL;
+    }
+
+    if (mDecryptHandle != NULL) {
+        // To release mDecryptHandle
+        CHECK(mDrmManagerClient);
+        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+        mDecryptHandle = NULL;
+    }
+
+    if (mDrmManagerClient != NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+}
+
+ssize_t PlayerServiceFileSource::readAt(off64_t offset, void *data, size_t size) {
+    if (mFd < 0) {
+        return NO_INIT;
+    }
+
+    Mutex::Autolock autoLock(mLock);
+
+    if (mLength >= 0) {
+        if (offset >= mLength) {
+            return 0;  // read beyond EOF.
+        }
+        uint64_t numAvailable = mLength - offset;
+        if ((uint64_t)size > numAvailable) {
+            size = numAvailable;
+        }
+    }
+
+    if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
+            == mDecryptHandle->decryptApiType) {
+        return readAtDRM_l(offset, data, size);
+   } else {
+        return readAt_l(offset, data, size);
+    }
+}
+
+sp<DecryptHandle> PlayerServiceFileSource::DrmInitialization(const char *mime) {
+    if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
+    if (mDrmManagerClient == NULL) {
+        mDrmManagerClient = new DrmManagerClient();
+    }
+
+    if (mDrmManagerClient == NULL) {
+        return NULL;
+    }
+
+    if (mDecryptHandle == NULL) {
+        mDecryptHandle = mDrmManagerClient->openDecryptSession(
+                mFd, mOffset, mLength, mime);
+    }
+
+    if (mDecryptHandle == NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+
+    return mDecryptHandle;
+}
+
+ssize_t PlayerServiceFileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
+    size_t DRM_CACHE_SIZE = 1024;
+    if (mDrmBuf == NULL) {
+        mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
+    }
+
+    if (mDrmBuf != NULL && mDrmBufSize > 0 && (offset + mOffset) >= mDrmBufOffset
+            && (offset + mOffset + size) <= static_cast<size_t>(mDrmBufOffset + mDrmBufSize)) {
+        /* Use buffered data */
+        memcpy(data, (void*)(mDrmBuf+(offset+mOffset-mDrmBufOffset)), size);
+        return size;
+    } else if (size <= DRM_CACHE_SIZE) {
+        /* Buffer new data */
+        mDrmBufOffset =  offset + mOffset;
+        mDrmBufSize = mDrmManagerClient->pread(mDecryptHandle, mDrmBuf,
+                DRM_CACHE_SIZE, offset + mOffset);
+        if (mDrmBufSize > 0) {
+            int64_t dataRead = 0;
+            dataRead = size > static_cast<size_t>(mDrmBufSize) ? mDrmBufSize : size;
+            memcpy(data, (void*)mDrmBuf, dataRead);
+            return dataRead;
+        } else {
+            return mDrmBufSize;
+        }
+    } else {
+        /* Too big chunk to cache. Call DRM directly */
+        return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset);
+    }
+}
+
+/* static */
+bool PlayerServiceFileSource::requiresDrm(int fd, int64_t offset, int64_t length, const char *mime) {
+    std::unique_ptr<DrmManagerClient> drmClient(new DrmManagerClient());
+    sp<DecryptHandle> decryptHandle =
+            drmClient->openDecryptSession(fd, offset, length, mime);
+    bool requiresDrm = false;
+    if (decryptHandle != nullptr) {
+        requiresDrm = decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED;
+        drmClient->closeDecryptSession(decryptHandle);
+    }
+    return requiresDrm;
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
new file mode 100644
index 0000000..0124720
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/PlayerServiceMediaHTTP.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "PlayerServiceMediaHTTP"
+#include <utils/Log.h>
+
+#include <datasource/PlayerServiceMediaHTTP.h>
+
+#include <binder/IServiceManager.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/FoundationUtils.h>
+
+#include <media/MediaHTTPConnection.h>
+
+namespace android {
+
+PlayerServiceMediaHTTP::PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn)
+    : MediaHTTP(conn),
+      mDrmManagerClient(NULL) {
+}
+
+PlayerServiceMediaHTTP::~PlayerServiceMediaHTTP() {
+    clearDRMState_l();
+}
+
+// DRM...
+
+sp<DecryptHandle> PlayerServiceMediaHTTP::DrmInitialization(const char* mime) {
+    if (mDrmManagerClient == NULL) {
+        mDrmManagerClient = new DrmManagerClient();
+    }
+
+    if (mDrmManagerClient == NULL) {
+        return NULL;
+    }
+
+    if (mDecryptHandle == NULL) {
+        mDecryptHandle = mDrmManagerClient->openDecryptSession(
+                String8(mLastURI.c_str()), mime);
+    }
+
+    if (mDecryptHandle == NULL) {
+        delete mDrmManagerClient;
+        mDrmManagerClient = NULL;
+    }
+
+    return mDecryptHandle;
+}
+
+void PlayerServiceMediaHTTP::clearDRMState_l() {
+    if (mDecryptHandle != NULL) {
+        // To release mDecryptHandle
+        CHECK(mDrmManagerClient);
+        mDrmManagerClient->closeDecryptSession(mDecryptHandle);
+        mDecryptHandle = NULL;
+    }
+}
+
+}  // namespace android
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h
new file mode 100644
index 0000000..7d58c5c
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceDataSourceFactory.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ * 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 PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
+
+#define PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
+
+#include <datasource/DataSourceFactory.h>
+#include <media/DataSource.h>
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class PlayerServiceDataSourceFactory : public DataSourceFactory {
+public:
+    static sp<PlayerServiceDataSourceFactory> getInstance();
+    virtual sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+
+protected:
+    virtual sp<DataSource> CreateFileSource(const char *uri);
+
+private:
+    static sp<PlayerServiceDataSourceFactory> sInstance;
+    static Mutex sInstanceLock;
+    PlayerServiceDataSourceFactory() {};
+};
+
+}  // namespace android
+
+#endif  // PLAYER_SERVICE_DATA_SOURCE_FACTORY_H_
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
new file mode 100644
index 0000000..08a013e
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceFileSource.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2009 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 PLAYER_SERVICE_FILE_SOURCE_H_
+
+#define PLAYER_SERVICE_FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+#include <drm/DrmManagerClient.h>
+
+namespace android {
+
+// FileSource implementation which works on MediaPlayerService.
+// Supports OMA(forword-lock) files.
+class PlayerServiceFileSource : public FileSource {
+public:
+    PlayerServiceFileSource(const char *filename);
+    // PlayerServiceFileSource takes ownership and will close the fd
+    PlayerServiceFileSource(int fd, int64_t offset, int64_t length);
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
+
+    static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
+
+protected:
+    virtual ~PlayerServiceFileSource();
+
+private:
+    /*for DRM*/
+    sp<DecryptHandle> mDecryptHandle;
+    DrmManagerClient *mDrmManagerClient;
+    int64_t mDrmBufOffset;
+    ssize_t mDrmBufSize;
+    unsigned char *mDrmBuf;
+
+    ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
+
+    PlayerServiceFileSource(const PlayerServiceFileSource &);
+    PlayerServiceFileSource &operator=(const PlayerServiceFileSource &);
+};
+
+}  // namespace android
+
+#endif  // PLAYER_SERVICE_FILE_SOURCE_H_
+
diff --git a/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
new file mode 100644
index 0000000..0032cd7
--- /dev/null
+++ b/media/libmediaplayerservice/datasource/include/datasource/PlayerServiceMediaHTTP.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#ifndef PLAYER_SERVICE_MEDIA_HTTP_H_
+
+#define PLAYER_SERVICE_MEDIA_HTTP_H_
+
+#include <datasource/MediaHTTP.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+struct MediaHTTPConnection;
+
+// MediaHTTP implementation which works on MediaPlayerService.
+// Supports OMA(forword-lock) stream.
+struct PlayerServiceMediaHTTP : public MediaHTTP {
+    PlayerServiceMediaHTTP(const sp<MediaHTTPConnection> &conn);
+
+protected:
+    virtual ~PlayerServiceMediaHTTP();
+
+    virtual sp<DecryptHandle> DrmInitialization(const char* mime);
+
+private:
+    sp<DecryptHandle> mDecryptHandle;
+    DrmManagerClient *mDrmManagerClient;
+
+    void clearDRMState_l();
+
+    DISALLOW_EVIL_CONSTRUCTORS(PlayerServiceMediaHTTP);
+};
+
+}  // namespace android
+
+#endif  // PLAYER_SERVICE_MEDIA_HTTP_H_
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index 19c8e76..c8f48a2 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -54,6 +54,10 @@
         "libpowermanager",
     ],
 
+    static_libs: [
+        "libplayerservice_datasource",
+    ],
+
     name: "libstagefright_nuplayer",
 
     sanitize: {
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index e26f1e6..00e3443 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -23,8 +23,8 @@
 #include "AnotherPacketSource.h"
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
-#include <datasource/DataSourceFactory.h>
-#include <datasource/FileSource.h>
+#include <datasource/PlayerServiceDataSourceFactory.h>
+#include <datasource/PlayerServiceFileSource.h>
 #include <datasource/HTTPBase.h>
 #include <datasource/NuCachedSource2.h>
 #include <media/DataSource.h>
@@ -385,7 +385,8 @@
             if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
                 sp<DataSource> httpSource;
                 mDisconnectLock.unlock();
-                httpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
+                httpSource = PlayerServiceDataSourceFactory::getInstance()
+                        ->CreateMediaHTTP(mHTTPService);
                 if (httpSource == NULL) {
                     ALOGE("Failed to create http source!");
                     notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -401,9 +402,9 @@
             mLock.unlock();
             mDisconnectLock.unlock();
             // This might take long time if connection has some issue.
-            sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
-                   mHTTPService, uri, &mUriHeaders, &contentType,
-                   static_cast<HTTPBase *>(mHttpSource.get()));
+            sp<DataSource> dataSource = PlayerServiceDataSourceFactory::getInstance()
+                    ->CreateFromURI(mHTTPService, uri, &mUriHeaders, &contentType,
+                            static_cast<HTTPBase *>(mHttpSource.get()));
             mDisconnectLock.lock();
             mLock.lock();
             if (!mDisconnected) {
@@ -411,7 +412,8 @@
             }
         } else {
             if (property_get_bool("media.stagefright.extractremote", true) &&
-                    !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) {
+                    !PlayerServiceFileSource::requiresDrm(
+                            mFd, mOffset, mLength, nullptr /* mime */)) {
                 sp<IBinder> binder =
                         defaultServiceManager()->getService(String16("media.extractor"));
                 if (binder != nullptr) {
@@ -438,7 +440,7 @@
             }
             if (mDataSource == nullptr) {
                 ALOGD("FileSource local");
-                mDataSource = new FileSource(mFd, mOffset, mLength);
+                mDataSource = new PlayerServiceFileSource(mFd, mOffset, mLength);
             }
             // TODO: close should always be done on mFd, see the lines following
             // CreateDataSourceFromIDataSource above,
@@ -782,7 +784,7 @@
         return;
     }
 
-    int64_t nextSubTimeUs;
+    int64_t nextSubTimeUs = 0;
     readBuffer(type, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
 
     sp<ABuffer> buffer;
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/tests/DrmSessionManager_test.cpp b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
index 58e4bee..262fe32 100644
--- a/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
+++ b/media/libmediaplayerservice/tests/DrmSessionManager_test.cpp
@@ -20,8 +20,8 @@
 
 #include <gtest/gtest.h>
 
-#include <media/IResourceManagerService.h>
-#include <media/IResourceManagerClient.h>
+#include <android/media/BnResourceManagerClient.h>
+#include <android/media/IResourceManagerService.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/ProcessInfoInterface.h>
 #include <mediadrm/DrmHal.h>
@@ -35,6 +35,10 @@
 
 namespace android {
 
+using ::android::binder::Status;
+using ::android::media::BnResourceManagerClient;
+using ::android::media::ResourceManagerService;
+
 static Vector<uint8_t> toAndroidVector(const std::vector<uint8_t> &vec) {
     Vector<uint8_t> aVec;
     for (auto b : vec) {
@@ -70,19 +74,21 @@
 
     virtual ~FakeDrm() {}
 
-    virtual bool reclaimResource() {
+    Status reclaimResource(bool* _aidl_return) {
         mReclaimed = true;
         mDrmSessionManager->removeSession(mSessionId);
-        return true;
+        *_aidl_return = true;
+        return Status::ok();
     }
 
-    virtual String8 getName() {
+    Status getName(::std::string* _aidl_return) {
         String8 name("FakeDrm[");
         for (size_t i = 0; i < mSessionId.size(); ++i) {
             name.appendFormat("%02x", mSessionId[i]);
         }
         name.append("]");
-        return name;
+        *_aidl_return = name;
+        return Status::ok();
     }
 
     bool isReclaimed() const {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 0ca20b9..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;
@@ -2436,7 +2436,7 @@
         }
         rate = (OMX_U32)(rateFloat * 65536.0f + 0.5f);
     } else {
-        if (rateFloat > UINT_MAX) {
+        if (rateFloat > (float)UINT_MAX) {
             return BAD_VALUE;
         }
         rate = (OMX_U32)(rateFloat);
@@ -3342,6 +3342,7 @@
     { MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
     { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
     { MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, OMX_VIDEO_CodingImageHEIC },
+    { MEDIA_MIMETYPE_VIDEO_AV1, OMX_VIDEO_CodingAV1 },
 };
 
 static status_t GetVideoCodingTypeFromMime(
@@ -6906,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);
@@ -6993,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)",
@@ -7010,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();
@@ -7044,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(
@@ -7564,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);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index c02b276..a48faca 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -102,6 +102,10 @@
         "include",
     ],
 
+    header_libs: [
+        "libmedia_helper_headers",
+    ],
+
     cflags: [
         "-Wno-multichar",
         "-Werror",
@@ -118,6 +122,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",
 
@@ -127,7 +178,6 @@
         "ACodecBufferChannel.cpp",
         "AHierarchicalStateMachine.cpp",
         "AMRWriter.cpp",
-        "AudioPlayer.cpp",
         "AudioSource.cpp",
         "BufferImpl.cpp",
         "CallbackDataSource.cpp",
@@ -162,7 +212,6 @@
         "SimpleDecodingSource.cpp",
         "SkipCutBuffer.cpp",
         "StagefrightMediaScanner.cpp",
-        "StagefrightMetadataRetriever.cpp",
         "StagefrightPluginLoader.cpp",
         "SurfaceUtils.cpp",
         "ThrottledSource.cpp",
@@ -172,6 +221,7 @@
     ],
 
     shared_libs: [
+        "libstagefright_framecapture_utils",
         "libaudioutils",
         "libbase",
         "libbinder",
@@ -213,7 +263,6 @@
         "libogg",
         "libwebm",
         "libstagefright_id3",
-        "libFLAC",
     ],
 
     header_libs:[
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 03415d5..d75b317 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -18,10 +18,10 @@
 #define LOG_TAG "FrameDecoder"
 
 #include "include/FrameDecoder.h"
+#include "include/FrameCaptureLayer.h"
 #include <binder/MemoryBase.h>
 #include <binder/MemoryHeapBase.h>
 #include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
 #include <inttypes.h>
 #include <mediadrm/ICrypto.h>
 #include <media/IMediaSource.h>
@@ -31,6 +31,7 @@
 #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>
@@ -512,7 +513,7 @@
     }
 
     if (isHDR(videoFormat)) {
-        *window = initSurfaceControl();
+        *window = initSurface();
         if (*window == NULL) {
             ALOGE("Failed to init surface control for HDR, fallback to non-hdr");
         } else {
@@ -589,7 +590,7 @@
     }
 
     if (!outputFormat->findInt32("stride", &stride)) {
-        if (mSurfaceControl == NULL) {
+        if (mCaptureLayer == NULL) {
             ALOGE("format must have stride for byte buffer mode: %s",
                     outputFormat->debugString().c_str());
             return ERROR_MALFORMED;
@@ -613,7 +614,7 @@
                 0,
                 0,
                 dstBpp(),
-                mSurfaceControl != nullptr /*allocRotated*/);
+                mCaptureLayer != nullptr /*allocRotated*/);
         mFrame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
 
         setFrame(frameMem);
@@ -621,8 +622,8 @@
 
     mFrame->mDurationUs = durationUs;
 
-    if (mSurfaceControl != nullptr) {
-        return captureSurfaceControl();
+    if (mCaptureLayer != nullptr) {
+        return captureSurface();
     }
 
     ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
@@ -655,70 +656,26 @@
     return ERROR_UNSUPPORTED;
 }
 
-sp<Surface> VideoFrameDecoder::initSurfaceControl() {
-    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
-    if (client->initCheck() != NO_ERROR) {
-        ALOGE("failed to get SurfaceComposerClient");
-        return NULL;
+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;
 
-    // create a container layer to hold the capture layer, so that we can
-    // use full frame drop. If without the container, the crop will be set
-    // to display size.
-    sp<SurfaceControl> parent = client->createSurface(
-            String8("parent"),
-            0 /* width */, 0 /* height */,
-            PIXEL_FORMAT_RGBA_8888,
-            ISurfaceComposerClient::eFXSurfaceContainer );
-
-    if (!parent) {
-        ALOGE("failed to get surface control parent");
-        return NULL;
-    }
-
-    // create the surface with unknown size 1x1 for now, real size will
-    // be set before the capture when we have output format info.
-    sp<SurfaceControl> surfaceControl = client->createSurface(
-            String8("thumbnail"),
-            1 /* width */, 1 /* height */,
-            PIXEL_FORMAT_RGBA_8888,
-            ISurfaceComposerClient::eFXSurfaceBufferQueue,
-            parent.get());
-
-    if (!surfaceControl) {
-        ALOGE("failed to get surface control");
-        return NULL;
-    }
-
-    SurfaceComposerClient::Transaction t;
-    t.hide(parent)
-            .show(surfaceControl)
-            .apply(true);
-
-    mSurfaceControl = surfaceControl;
-    mParent = parent;
-
-    return surfaceControl->getSurface();
+    return captureLayer->getSurface();
 }
 
-status_t VideoFrameDecoder::captureSurfaceControl() {
-    // set the layer size to the output size before the capture
-    SurfaceComposerClient::Transaction()
-        .setSize(mSurfaceControl, mFrame->mWidth, mFrame->mHeight)
-        .apply(true);
-
+status_t VideoFrameDecoder::captureSurface() {
     sp<GraphicBuffer> outBuffer;
-    status_t err = ScreenshotClient::captureChildLayers(
-            mParent->getHandle(),
-            ui::Dataspace::V0_SRGB,
-            captureFormat(),
-            Rect(0, 0, mFrame->mWidth, mFrame->mHeight),
-            {},
-            1.0f /*frameScale*/,
-            &outBuffer);
+    status_t err = mCaptureLayer->capture(
+            captureFormat(), Rect(0, 0, mFrame->mWidth, mFrame->mHeight), &outBuffer);
 
     if (err != OK) {
-        ALOGE("failed to captureLayers: err %d", err);
+        ALOGE("failed to capture layer (err %d)", err);
         return err;
     }
 
@@ -917,12 +874,6 @@
     }
     converter.setSrcColorSpace(standard, range, transfer);
 
-    int32_t dstLeft, dstTop, dstRight, dstBottom;
-    dstLeft = mTilesDecoded % mGridCols * width;
-    dstTop = mTilesDecoded / mGridCols * height;
-    dstRight = dstLeft + width - 1;
-    dstBottom = dstTop + height - 1;
-
     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;
@@ -930,15 +881,25 @@
         crop_bottom = height - 1;
     }
 
+    int32_t crop_width, crop_height;
+    crop_width = crop_right - crop_left + 1;
+    crop_height = crop_bottom - crop_top + 1;
+
+    int32_t dstLeft, dstTop, dstRight, dstBottom;
+    dstLeft = mTilesDecoded % mGridCols * crop_width;
+    dstTop = mTilesDecoded / mGridCols * crop_height;
+    dstRight = dstLeft + crop_width - 1;
+    dstBottom = dstTop + crop_height - 1;
+
     // apply crop on bottom-right
     // TODO: need to move this into the color converter itself.
     if (dstRight >= mWidth) {
-        crop_right = mWidth - dstLeft - 1;
-        dstRight = dstLeft + crop_right;
+        crop_right = crop_left + mWidth - dstLeft - 1;
+        dstRight = mWidth - 1;
     }
     if (dstBottom >= mHeight) {
-        crop_bottom = mHeight - dstTop - 1;
-        dstBottom = dstTop + crop_bottom;
+        crop_bottom = crop_top + mHeight - dstTop - 1;
+        dstBottom = mHeight - 1;
     }
 
     *done = (++mTilesDecoded >= mTargetTiles);
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 4f9bc6d..24608a7 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -281,7 +281,7 @@
             it = mTimers.erase(it);
         } else {
             if (mPlaybackRate != 0.0
-                && (double)diffMediaUs < INT64_MAX * (double)mPlaybackRate) {
+                && (double)diffMediaUs < (double)INT64_MAX * (double)mPlaybackRate) {
                 int64_t targetRealUs = diffMediaUs / (double)mPlaybackRate;
                 if (targetRealUs < nextLapseRealUs) {
                     nextLapseRealUs = targetRealUs;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 77eace9..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);
 
@@ -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());
         });
     }
 
@@ -992,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.
@@ -1108,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.
@@ -1241,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);
 }
 
@@ -1260,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.
@@ -1710,8 +1734,7 @@
             totalPixel = width * height;
         }
         if (totalPixel >= 1920 * 1080) {
-            addResource(MediaResource::kCpuBoost,
-                    MediaResource::kUnspecifiedSubType, 1);
+            addResource(MediaResource::CpuBoostResource());
             mCpuBoostRequested = true;
         }
     }
@@ -2056,20 +2079,17 @@
                     }
                     mOwnerName = owner;
 
-                    MediaResource::Type resourceType;
                     if (mComponentName.endsWith(".secure")) {
                         mFlags |= kFlagIsSecure;
-                        resourceType = MediaResource::kSecureCodec;
                         mediametrics_setInt32(mMetricsHandle, kCodecSecure, 1);
                     } else {
                         mFlags &= ~kFlagIsSecure;
-                        resourceType = MediaResource::kNonSecureCodec;
                         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);
@@ -2190,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);
@@ -3132,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/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index b89dcdf..66fb4b0 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -82,7 +82,7 @@
     }
 
     sp<DataSource> dataSource =
-        DataSourceFactory::CreateFromURI(httpService, path, headers);
+        DataSourceFactory::getInstance()->CreateFromURI(httpService, path, headers);
 
     if (dataSource == NULL) {
         return -ENOENT;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ac4d087..bd2e0a3 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1874,7 +1874,7 @@
     if (msg->findInt32("frame-rate", &fps) && fps > 0) {
         meta->setInt32(kKeyFrameRate, fps);
     } else if (msg->findFloat("frame-rate", &fpsFloat)
-            && fpsFloat >= 1 && 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);
     }
@@ -1909,25 +1909,24 @@
             meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
         } else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
             if (msg->findBuffer("csd-2", &csd2)) {
-                meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
-
-                size_t dvcc_size = 1024;
-                uint8_t dvcc[dvcc_size];
-                memcpy(dvcc, csd2->data(), dvcc_size);
-                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);
+                //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 {
diff --git a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
index adb0dd4..f9d91b1 100644
--- a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
+++ b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
@@ -44,7 +44,7 @@
 #endif
 
 #include "pvmp3_audio_type_defs.h"
-#define Qfmt_31(a)   (Int32)((float)(a)*0x7FFFFFFF)
+#define Qfmt_31(a)   (Int32)((float)(a)*(float)0x7FFFFFFF)
 
 #define Qfmt15(x)   (Int16)((x)*((Int32)1<<15) + ((x)>=0?0.5F:-0.5F))
 
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
index af738ba..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)(0x7FFFFFFF / (float)18 - 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/mp3dec/src/pvmp3_dct_9.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
index bbb247d..9cd0e91 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
@@ -77,7 +77,7 @@
 ; Include all pre-processor statements here. Include conditional
 ; compile variables also.
 ----------------------------------------------------------------------------*/
-#define Qfmt31(a)   (int32)((a)*(0x7FFFFFFF))
+#define Qfmt31(a)   (int32)((a)*((float)0x7FFFFFFF))
 
 #define cos_pi_9    Qfmt31( 0.93969262078591f)
 #define cos_2pi_9   Qfmt31( 0.76604444311898f)
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/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 7183dbd..68f1de9 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -21,8 +21,8 @@
 #include "HTTPDownloader.h"
 #include "M3UParser.h"
 
-#include <datasource/ClearMediaHTTP.h>
-#include <datasource/ClearFileSource.h>
+#include <datasource/MediaHTTP.h>
+#include <datasource/FileSource.h>
 #include <media/DataSource.h>
 #include <media/MediaHTTPConnection.h>
 #include <media/MediaHTTPService.h>
@@ -38,7 +38,7 @@
 HTTPDownloader::HTTPDownloader(
         const sp<MediaHTTPService> &httpService,
         const KeyedVector<String8, String8> &headers) :
-    mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())),
+    mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())),
     mExtraHeaders(headers),
     mDisconnecting(false) {
 }
@@ -91,7 +91,7 @@
 
     if (reconnect) {
         if (!strncasecmp(url, "file://", 7)) {
-            mDataSource = new ClearFileSource(url + 7);
+            mDataSource = new FileSource(url + 7);
         } else if (strncasecmp(url, "http://", 7)
                 && strncasecmp(url, "https://", 8)) {
             return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index d9704a6..c8173cf 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -4,6 +4,7 @@
     srcs: ["ID3.cpp"],
 
     header_libs: [
+        "libmedia_headers",
         "media_ndk_headers",
     ],
 
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 8e42fcf..353c957 100644
--- a/media/libstagefright/include/FrameDecoder.h
+++ b/media/libstagefright/include/FrameDecoder.h
@@ -33,7 +33,6 @@
 class IMediaSource;
 class MediaCodecBuffer;
 class Surface;
-class SurfaceControl;
 class VideoFrame;
 
 struct FrameRect {
@@ -101,6 +100,7 @@
 
     DISALLOW_EVIL_CONSTRUCTORS(FrameDecoder);
 };
+struct FrameCaptureLayer;
 
 struct VideoFrameDecoder : public FrameDecoder {
     VideoFrameDecoder(
@@ -133,8 +133,7 @@
             bool *done) override;
 
 private:
-    sp<SurfaceControl> mSurfaceControl;
-    sp<SurfaceControl> mParent;
+    sp<FrameCaptureLayer> mCaptureLayer;
     VideoFrame *mFrame;
     bool mIsAvcOrHevc;
     MediaSource::ReadOptions::SeekMode mSeekMode;
@@ -142,8 +141,8 @@
     List<int64_t> mSampleDurations;
     int64_t mDefaultSampleDurationUs;
 
-    sp<Surface> initSurfaceControl();
-    status_t captureSurfaceControl();
+    sp<Surface> initSurface();
+    status_t captureSurface();
 };
 
 struct ImageDecoder : public FrameDecoder {
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index f9055a4..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;
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/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 01d0325..78d00b1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -24,7 +24,6 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/MediaCodecInfo.h>
-#include <media/MediaResource.h>
 #include <media/MediaMetrics.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/FrameRenderTracker.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 {
@@ -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;
@@ -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/MediaErrors.h b/media/libstagefright/include/media/stagefright/MediaErrors.h
index 09639e2..6f48c5d 100644
--- a/media/libstagefright/include/media/stagefright/MediaErrors.h
+++ b/media/libstagefright/include/media/stagefright/MediaErrors.h
@@ -99,7 +99,13 @@
     ERROR_CAS_DEVICE_REVOKED                 = CAS_ERROR_BASE - 9,
     ERROR_CAS_RESOURCE_BUSY                  = CAS_ERROR_BASE - 10,
     ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = CAS_ERROR_BASE - 11,
-    ERROR_CAS_LAST_USED_ERRORCODE            = CAS_ERROR_BASE - 11,
+    ERROR_CAS_NEED_ACTIVATION                = CAS_ERROR_BASE - 12,
+    ERROR_CAS_NEED_PAIRING                   = CAS_ERROR_BASE - 13,
+    ERROR_CAS_NO_CARD                        = CAS_ERROR_BASE - 14,
+    ERROR_CAS_CARD_MUTE                      = CAS_ERROR_BASE - 15,
+    ERROR_CAS_CARD_INVALID                   = CAS_ERROR_BASE - 16,
+    ERROR_CAS_BLACKOUT                       = CAS_ERROR_BASE - 17,
+    ERROR_CAS_LAST_USED_ERRORCODE            = CAS_ERROR_BASE - 17,
 
     ERROR_CAS_VENDOR_MAX                     = CAS_ERROR_BASE - 500,
     ERROR_CAS_VENDOR_MIN                     = CAS_ERROR_BASE - 999,
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/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/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/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index ee01d6c..6848a83 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -278,7 +278,7 @@
 
 static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
     sp<DataSource> source =
-        DataSourceFactory::CreateFromURI(NULL /* httpService */, uri);
+        DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri);
 
     if (source == NULL) {
         return NULL;
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index cac1af9..bb66f4c 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -954,7 +954,7 @@
     CHECK_GE(space2, 0);
 
     method->setTo(request, 0, space1);
-    url->setTo(request, space1 + 1, space2 - space1);
+    url->setTo(request, space1 + 1, space2 - space1 - 1);
 }
 
 void ARTSPConnection::addAuthentication(AString *request) {
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index 5bd218d..e236267 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -22,7 +22,7 @@
 
 #include "ASessionDescription.h"
 
-#include <datasource/ClearMediaHTTP.h>
+#include <datasource/MediaHTTP.h>
 #include <media/MediaHTTPConnection.h>
 #include <media/MediaHTTPService.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -42,7 +42,7 @@
       mFlags(flags),
       mNetLooper(new ALooper),
       mCancelled(false),
-      mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())) {
+      mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) {
     mNetLooper->setName("sdp net");
     mNetLooper->start(false /* runOnCallingThread */,
                       false /* canCallJava */,
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 9f3e807..2cebe8f 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -34,6 +34,7 @@
     ],
 
     header_libs: [
+        "libmedia_headers",
         "media_ndk_headers",
     ],
 }
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 9783e9b..d905b8d 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -1269,7 +1269,7 @@
 void MediaCodecsXmlParser::Impl::State::addDetail(
         const std::string &key, const std::string &value) {
     CHECK(inType());
-    ALOGI("limit: %s = %s", key.c_str(), value.c_str());
+    ALOGV("limit: %s = %s", key.c_str(), value.c_str());
     const StringSet &variants = mVariantsStack.back();
     if (variants.empty()) {
         type()[key] = value;
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/ndk/Android.bp b/media/ndk/Android.bp
index 61f9014..032c5e2 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -90,7 +90,6 @@
         "libutils",
         "libcutils",
         "libnativewindow",
-        "libbinder",
         "libhidlbase",
         "libgui",
         "libui",
@@ -149,6 +148,10 @@
         "-Wall",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
     ],
 
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 f6892e6..c1d4686 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -202,7 +202,7 @@
         headers.add(key8, value8);
     }
 
-    sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+    sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromURI(service, uri, &headers);
     if (source == NULL) {
         ALOGE("AMediaDataSource_newUri source is null");
         return NULL;
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 842216c..b78373d 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -29,6 +29,7 @@
 
 #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>
@@ -71,12 +72,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 +104,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 +173,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 +259,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/NdkImage.h b/media/ndk/include/media/NdkImage.h
index 3e60de0..62b8624 100644
--- a/media/ndk/include/media/NdkImage.h
+++ b/media/ndk/include/media/NdkImage.h
@@ -570,6 +570,8 @@
  * return {@link AMEDIA_ERROR_INVALID_OBJECT}. Application still needs to call this method on those
  * {@link AImage} objects to fully delete the {@link AImage} object from memory.</p>
  *
+ * Available since API level 24.
+ *
  * @param image The {@link AImage} to be deleted.
  */
 void AImage_delete(AImage* image) __INTRODUCED_IN(24);
@@ -577,6 +579,8 @@
 /**
  * Query the width of the input {@link AImage}.
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param width the width of the image will be filled here if the method call succeeeds.
  *
@@ -591,6 +595,8 @@
 /**
  * Query the height of the input {@link AImage}.
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param height the height of the image will be filled here if the method call succeeeds.
  *
@@ -607,6 +613,8 @@
  *
  * <p>The format value will be one of AIMAGE_FORMAT_* enum value.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param format the format of the image will be filled here if the method call succeeeds.
  *
@@ -624,6 +632,8 @@
  * <p>The crop rectangle specifies the region of valid pixels in the image, using coordinates in the
  * largest-resolution plane.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param rect the cropped rectangle of the image will be filled here if the method call succeeeds.
  *
@@ -648,6 +658,8 @@
  * {@link ACameraCaptureSession_captureCallbacks#onCaptureCompleted} callback.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param timestampNs the timestamp of the image will be filled here if the method call succeeeds.
  *
@@ -665,6 +677,8 @@
  * <p>The number of plane of an {@link AImage} is determined by its format, which can be queried by
  * {@link AImage_getFormat} method.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param numPlanes the number of planes of the image will be filled here if the method call
  *         succeeeds.
@@ -687,6 +701,8 @@
  * being returned.
  * For formats where pixel stride is well defined, the pixel stride is always greater than 0.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
  * @param pixelStride the pixel stride of the image will be filled here if the method call succeeeds.
@@ -714,6 +730,8 @@
  * being returned.
  * For formats where row stride is well defined, the row stride is always greater than 0.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
  * @param rowStride the row stride of the image will be filled here if the method call succeeeds.
@@ -739,6 +757,8 @@
  * pointer from previous AImage_getPlaneData call becomes invalid. Do NOT use it after the
  * {@link AImage} or the parent {@link AImageReader} is deleted.</p>
  *
+ * Available since API level 24.
+ *
  * @param image the {@link AImage} of interest.
  * @param planeIdx the index of the plane. Must be less than the number of planes of input image.
  * @param data the data pointer of the image will be filled here if the method call succeeeds.
@@ -769,6 +789,8 @@
  * signal the release of the hardware buffer back to the {@link AImageReader}'s queue using
  * releaseFenceFd.</p>
  *
+ * Available since API level 26.
+ *
  * @param image The {@link AImage} to be deleted.
  * @param releaseFenceFd A sync fence fd defined in {@link sync.h}, which signals the release of
  *         underlying {@link AHardwareBuffer}.
@@ -794,6 +816,8 @@
  * {@link AImageReader_setBufferRemovedListener} to be notified when the buffer is no longer used
  * by {@link AImageReader}.</p>
  *
+ * Available since API level 26.
+ *
  * @param image the {@link AImage} of interest.
  * @param outBuffer The memory area pointed to by buffer will contain the acquired AHardwareBuffer
  *         handle.
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index e5d863c..600ffc9 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -67,6 +67,8 @@
  * The valid sizes and formats depend on the source of the image data.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param width The default width in pixels of the Images that this reader will produce.
  * @param height The default height in pixels of the Images that this reader will produce.
  * @param format The format of the Image that this reader will produce. This must be one of the
@@ -101,6 +103,8 @@
  * making any of data pointers obtained from {@link AImage_getPlaneData} invalid. Do NOT access
  * the reader object or any of those data pointers after this method returns.</p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader to be deleted.
  */
 void AImageReader_delete(AImageReader* reader) __INTRODUCED_IN(24);
@@ -108,6 +112,8 @@
 /**
  * Get a {@link ANativeWindow} that can be used to produce {@link AImage} for this image reader.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param window The output {@link ANativeWindow} will be filled here if the method call succeeds.
  *                The {@link ANativeWindow} is managed by this image reader. Do NOT call
@@ -126,6 +132,8 @@
  * {@link ANativeWindow}. If so, the actual width of the images can be found using
  * {@link AImage_getWidth}.</p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param width the default width of the reader will be filled here if the method call succeeeds.
  *
@@ -142,6 +150,8 @@
  * {@link ANativeWindow}. If so, the actual height of the images can be found using
  * {@link AImage_getHeight}.</p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param height the default height of the reader will be filled here if the method call succeeeds.
  *
@@ -154,6 +164,8 @@
 /**
  * Query the format of the {@link AImage} generated by this reader.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param format the fromat of the reader will be filled here if the method call succeeeds. The
  *                value will be one of the AIMAGE_FORMAT_* enum value defiend in {@link NdkImage.h}.
@@ -167,6 +179,8 @@
 /**
  * Query the maximum number of concurrently acquired {@link AImage}s of this reader.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param maxImages the maximum number of concurrently acquired images of the reader will be filled
  *                here if the method call succeeeds.
@@ -197,6 +211,8 @@
  * {@link AImage_delete}.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
  *
@@ -214,7 +230,6 @@
 media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) __INTRODUCED_IN(24);
 
 /**
-
  * Acquire the latest {@link AImage} from the image reader's queue, dropping older images.
  *
  * <p>
@@ -241,6 +256,8 @@
  * {@link AImage_delete}.
  * </p>
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param image the acquired {@link AImage} will be filled here if the method call succeeeds.
  *
@@ -290,6 +307,8 @@
  *
  * Calling this method will replace previously registered listeners.
  *
+ * Available since API level 24.
+ *
  * @param reader The image reader of interest.
  * @param listener The {@link AImageReader_ImageListener} to be registered. Set this to NULL if
  *                 the application no longer needs to listen to new images.
@@ -356,6 +375,9 @@
  *   {@link AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE}, or combined</td>
  * </tr>
  * </table>
+ *
+ * Available since API level 26.
+ *
  * @return <ul>
  *         <li>{@link AMEDIA_OK} if the method call succeeds.</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if reader is NULL, or one or more of width,
@@ -377,6 +399,8 @@
  * additional parameter for the sync fence. All other parameters and the return values are
  * identical to those passed to {@link AImageReader_acquireNextImage}.</p>
  *
+ * Available since API level 26.
+ *
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
@@ -397,6 +421,8 @@
  * additional parameter for the sync fence. All other parameters and the return values are
  * identical to those passed to {@link AImageReader_acquireLatestImage}.</p>
  *
+ * Available since API level 26.
+ *
  * @param acquireFenceFd A sync fence fd defined in {@link sync.h}, which is used to signal when the
  *         buffer is ready to consume. When synchronization fence is not needed, fence will be set
  *         to -1 and the {@link AImage} returned is ready for use immediately. Otherwise, user shall
@@ -408,6 +434,7 @@
  */
 media_status_t AImageReader_acquireLatestImageAsync(
         AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) __INTRODUCED_IN(26);
+
 /**
  * Signature of the callback which is called when {@link AImageReader} is about to remove a buffer.
  *
@@ -451,6 +478,8 @@
  *
  * <p>Note that calling this method will replace previously registered listeners.</p>
  *
+ * Available since API level 26.
+ *
  * @param reader The image reader of interest.
  * @param listener the {@link AImageReader_BufferRemovedListener} to be registered. Set this to
  * NULL if application no longer needs to listen to buffer removed events.
diff --git a/media/ndk/include/media/NdkMediaCodec.h b/media/ndk/include/media/NdkMediaCodec.h
index b3ee853..1823fbc 100644
--- a/media/ndk/include/media/NdkMediaCodec.h
+++ b/media/ndk/include/media/NdkMediaCodec.h
@@ -127,27 +127,37 @@
  * Create codec by name. Use this if you know the exact codec you want to use.
  * When configuring, you will need to specify whether to use the codec as an
  * encoder or decoder.
+ *
+ * Available since API level 21.
  */
 AMediaCodec* AMediaCodec_createCodecByName(const char *name) __INTRODUCED_IN(21);
 
 /**
  * Create codec by mime type. Most applications will use this, specifying a
  * mime type obtained from media extractor.
+ *
+ * Available since API level 21.
  */
 AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) __INTRODUCED_IN(21);
 
 /**
  * Create encoder by name.
+ *
+ * Available since API level 21.
  */
 AMediaCodec* AMediaCodec_createEncoderByType(const char *mime_type) __INTRODUCED_IN(21);
 
 /**
- * delete the codec and free its resources
+ * Delete the codec and free its resources.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_delete(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * Configure the codec. For decoding you would typically get the format from an extractor.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_configure(
         AMediaCodec*,
@@ -159,29 +169,39 @@
 /**
  * Start the codec. A codec must be configured before it can be started, and must be started
  * before buffers can be sent to it.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_start(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * Stop the codec.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_stop(AMediaCodec*) __INTRODUCED_IN(21);
 
 /*
  * Flush the codec's input and output. All indices previously returned from calls to
  * AMediaCodec_dequeueInputBuffer and AMediaCodec_dequeueOutputBuffer become invalid.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_flush(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * Get an input buffer. The specified buffer index must have been previously obtained from
  * dequeueInputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
  */
 uint8_t* AMediaCodec_getInputBuffer(AMediaCodec*, size_t idx, size_t *out_size) __INTRODUCED_IN(21);
 
 /**
  * Get an output buffer. The specified buffer index must have been previously obtained from
  * dequeueOutputBuffer, and not yet queued.
+ *
+ * Available since API level 21.
  */
 uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec*, size_t idx, size_t *out_size) __INTRODUCED_IN(21);
 
@@ -189,6 +209,8 @@
  * Get the index of the next available input buffer. An app will typically use this with
  * getInputBuffer() to get a pointer to the buffer, then copy the data to be encoded or decoded
  * into the buffer before passing it to the codec.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec*, int64_t timeoutUs) __INTRODUCED_IN(21);
 
@@ -218,6 +240,8 @@
 
 /**
  * Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_queueInputBuffer(AMediaCodec*, size_t idx,
                                             _off_t_compat offset, size_t size,
@@ -225,6 +249,8 @@
 
 /**
  * Send the specified buffer to the codec for processing.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_queueSecureInputBuffer(AMediaCodec*, size_t idx,
                                                   _off_t_compat offset,
@@ -235,15 +261,23 @@
 
 /**
  * Get the index of the next available buffer of processed data.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info,
         int64_t timeoutUs) __INTRODUCED_IN(21);
+
+/**
+ * Available since API level 21.
+ */
 AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*) __INTRODUCED_IN(21);
 
 /**
  * If you are done with a buffer, use this call to return the buffer to
  * the codec. If you previously specified a surface when configuring this
  * video decoder you can optionally render the buffer.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render) __INTRODUCED_IN(21);
 
@@ -256,6 +290,8 @@
  *  to ImageReader (software readable) output.
  *
  * For more details, see the Java documentation for MediaCodec.setOutputSurface.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_setOutputSurface(AMediaCodec*, ANativeWindow* surface) __INTRODUCED_IN(21);
 
@@ -266,6 +302,8 @@
  * this call will simply return the buffer to the codec.
  *
  * For more details, see the Java documentation for MediaCodec.releaseOutputBuffer.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodec_releaseOutputBufferAtTime(
         AMediaCodec *mData, size_t idx, int64_t timestampNs) __INTRODUCED_IN(21);
@@ -282,6 +320,8 @@
  * ANativeWindow_release() when done.
  *
  * For more details, see the Java documentation for MediaCodec.createInputSurface.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_createInputSurface(
         AMediaCodec *mData, ANativeWindow **surface) __INTRODUCED_IN(26);
@@ -298,6 +338,8 @@
  * ANativeWindow_release() when done.
  *
  * For more details, see the Java documentation for MediaCodec.createPersistentInputSurface.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_createPersistentInputSurface(
         ANativeWindow **surface) __INTRODUCED_IN(26);
@@ -311,6 +353,8 @@
  * AMediaCodec_configure(..); and before AMediaCodec_start() has been called.
  *
  * For more details, see the Java documentation for MediaCodec.setInputSurface.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_setInputSurface(
         AMediaCodec *mData, ANativeWindow *surface) __INTRODUCED_IN(26);
@@ -322,6 +366,8 @@
  * after AMediaCodec_start() has been called.
  *
  * NOTE: Some of these parameter changes may silently fail to apply.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_setParameters(
         AMediaCodec *mData, const AMediaFormat* params) __INTRODUCED_IN(26);
@@ -339,6 +385,8 @@
  * Returns AMEDIA_OK when completed succesfully.
  *
  * For more details, see the Java documentation for MediaCodec.signalEndOfInputStream.
+ *
+ * Available since API level 26.
  */
 media_status_t AMediaCodec_signalEndOfInputStream(AMediaCodec *mData) __INTRODUCED_IN(26);
 
@@ -349,6 +397,8 @@
 /**
  * Get format of the buffer. The specified buffer index must have been previously obtained from
  * dequeueOutputBuffer.
+ *
+ * Available since API level 28.
  */
 AMediaFormat* AMediaCodec_getBufferFormat(AMediaCodec*, size_t index) __INTRODUCED_IN(28);
 
@@ -356,11 +406,15 @@
  * Get the component name. If the codec was created by createDecoderByType
  * or createEncoderByType, what component is chosen is not known beforehand.
  * Caller shall call AMediaCodec_releaseName to free the returned pointer.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaCodec_getName(AMediaCodec*, char** out_name) __INTRODUCED_IN(28);
 
 /**
  * Free the memory pointed by name which is returned by AMediaCodec_getName.
+ *
+ * Available since API level 28.
  */
 void AMediaCodec_releaseName(AMediaCodec*, char* name) __INTRODUCED_IN(28);
 
@@ -382,6 +436,8 @@
  * All callbacks are fired on one NDK internal thread.
  * AMediaCodec_setAsyncNotifyCallback should not be called on the callback thread.
  * No heavy duty task should be performed on callback thread.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaCodec_setAsyncNotifyCallback(
         AMediaCodec*,
@@ -390,6 +446,8 @@
 
 /**
  * Release the crypto if applicable.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaCodec_releaseCrypto(AMediaCodec*) __INTRODUCED_IN(28);
 
@@ -397,12 +455,16 @@
  * Call this after AMediaCodec_configure() returns successfully to get the input
  * format accepted by the codec. Do this to determine what optional configuration
  * parameters were supported by the codec.
+ *
+ * Available since API level 28.
  */
 AMediaFormat* AMediaCodec_getInputFormat(AMediaCodec*) __INTRODUCED_IN(28);
 
 /**
  * Returns true if the codec cannot proceed further, but can be recovered by stopping,
  * configuring, and starting again.
+ *
+ * Available since API level 28.
  */
 bool AMediaCodecActionCode_isRecoverable(int32_t actionCode) __INTRODUCED_IN(28);
 
@@ -410,6 +472,8 @@
  * Returns true if the codec error is a transient issue, perhaps due to
  * resource constraints, and that the method (or encoding/decoding) may be
  * retried at a later time.
+ *
+ * Available since API level 28.
  */
 bool AMediaCodecActionCode_isTransient(int32_t actionCode) __INTRODUCED_IN(28);
 
@@ -440,6 +504,8 @@
  * numBytesOfClearData can be null to indicate that all data is encrypted.
  * This information encapsulates per-sample metadata as outlined in
  * ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base media file format files".
+ *
+ * Available since API level 21.
  */
 AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
         int numsubsamples,
@@ -450,13 +516,17 @@
         size_t *encryptedbytes) __INTRODUCED_IN(21);
 
 /**
- * delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
- * obtained from AMediaExtractor
+ * Delete an AMediaCodecCryptoInfo created previously with AMediaCodecCryptoInfo_new, or
+ * obtained from AMediaExtractor.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
 
 /**
- * Set the crypto pattern on an AMediaCryptoInfo object
+ * Set the crypto pattern on an AMediaCryptoInfo object.
+ *
+ * Available since API level 21.
  */
 void AMediaCodecCryptoInfo_setPattern(
         AMediaCodecCryptoInfo *info,
@@ -464,32 +534,44 @@
 
 /**
  * The number of subsamples that make up the buffer's contents.
+ *
+ * Available since API level 21.
  */
 size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
 
 /**
- * A 16-byte opaque key
+ * A 16-byte opaque key.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst) __INTRODUCED_IN(21);
 
 /**
- * A 16-byte initialization vector
+ * A 16-byte initialization vector.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst) __INTRODUCED_IN(21);
 
 /**
  * The type of encryption that has been applied,
  * one of AMEDIACODECRYPTOINFO_MODE_CLEAR or AMEDIACODECRYPTOINFO_MODE_AES_CTR.
+ *
+ * Available since API level 21.
  */
 cryptoinfo_mode_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*) __INTRODUCED_IN(21);
 
 /**
  * The number of leading unencrypted bytes in each subsample.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst) __INTRODUCED_IN(21);
 
 /**
  * The number of trailing encrypted bytes in each subsample.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst) __INTRODUCED_IN(21);
 
diff --git a/media/ndk/include/media/NdkMediaCrypto.h b/media/ndk/include/media/NdkMediaCrypto.h
index bcdf9a0..3fa07c7 100644
--- a/media/ndk/include/media/NdkMediaCrypto.h
+++ b/media/ndk/include/media/NdkMediaCrypto.h
@@ -49,12 +49,24 @@
 
 #if __ANDROID_API__ >= 21
 
+/**
+ * Available since API level 21.
+ */
 bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *initData, size_t initDataSize) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 void AMediaCrypto_delete(AMediaCrypto* crypto) __INTRODUCED_IN(21);
 
 #endif /* __ANDROID_API__ >= 21 */
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index 16b1eb3..0577df2 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -88,6 +88,8 @@
 /**
  * Create new media data source. Returns NULL if memory allocation
  * for the new data source object fails.
+ *
+ * Available since API level 28.
  */
 AMediaDataSource* AMediaDataSource_new() __INTRODUCED_IN(28);
 
@@ -116,6 +118,7 @@
  * ...
  * key_values[(numheaders - 1) * 2]:key_values[(numheaders - 1) * 2 + 1]
  *
+ * Available since API level 29.
  */
 AMediaDataSource* AMediaDataSource_newUri(const char *uri,
         int numheaders,
@@ -125,12 +128,16 @@
 
 /**
  * Delete a previously created media data source.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_delete(AMediaDataSource*) __INTRODUCED_IN(28);
 
 /**
  * Set an user provided opaque handle. This opaque handle is passed as
  * the first argument to the data source callbacks.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setUserdata(
         AMediaDataSource*, void *userdata) __INTRODUCED_IN(28);
@@ -145,6 +152,8 @@
  *
  * Please refer to the definition of AMediaDataSourceReadAt for
  * additional details.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setReadAt(
         AMediaDataSource*,
@@ -156,6 +165,8 @@
  *
  * Please refer to the definition of AMediaDataSourceGetSize for
  * additional details.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setGetSize(
         AMediaDataSource*,
@@ -167,6 +178,8 @@
  *
  * Please refer to the definition of AMediaDataSourceClose for
  * additional details.
+ *
+ * Available since API level 28.
  */
 void AMediaDataSource_setClose(
         AMediaDataSource*,
@@ -181,6 +194,8 @@
  *
  * Please refer to the definition of AMediaDataSourceClose for
  * additional details.
+ *
+ * Available since API level 29.
  */
 void AMediaDataSource_close(AMediaDataSource*) __INTRODUCED_IN(29);
 
@@ -191,6 +206,8 @@
  *
  * Please refer to the definition of AMediaDataSourceGetAvailableSize
  * for additional details.
+ *
+ * Available since API level 29.
  */
 void AMediaDataSource_setGetAvailableSize(
         AMediaDataSource*,
diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
index 2e438d9..31f5c7d 100644
--- a/media/ndk/include/media/NdkMediaDrm.h
+++ b/media/ndk/include/media/NdkMediaDrm.h
@@ -174,41 +174,53 @@
  * uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
  * mimeType is the MIME type of the media container, e.g. "video/mp4".  If mimeType
  * is not known or required, it can be provided as NULL.
+ *
+ * Available since API level 21.
  */
 bool AMediaDrm_isCryptoSchemeSupported(const uint8_t *uuid,
         const char *mimeType) __INTRODUCED_IN(21);
 
 /**
- * Create a MediaDrm instance from a UUID
+ * Create a MediaDrm instance from a UUID.
  * uuid identifies the universal unique ID of the crypto scheme. uuid must be 16 bytes.
+ *
+ * Available since API level 21.
  */
 AMediaDrm* AMediaDrm_createByUUID(const uint8_t *uuid) __INTRODUCED_IN(21);
 
 /**
- * Release a MediaDrm object
+ * Release a MediaDrm object.
+ *
+ * Available since API level 21.
  */
 void AMediaDrm_release(AMediaDrm *) __INTRODUCED_IN(21);
 
 /**
- * Register a callback to be invoked when an event occurs
+ * Register a callback to be invoked when an event occurs.
  *
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_setOnEventListener(AMediaDrm *,
         AMediaDrmEventListener listener) __INTRODUCED_IN(21);
 
 /**
- * Register a callback to be invoked when an expiration update event occurs
+ * Register a callback to be invoked when an expiration update event occurs.
  *
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
  */
 media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *,
         AMediaDrmExpirationUpdateListener listener) __INTRODUCED_IN(29);
 
 /**
- * Register a callback to be invoked when a key status change event occurs
+ * Register a callback to be invoked when a key status change event occurs.
  *
- * listener is the callback that will be invoked on event
+ * listener is the callback that will be invoked on event.
+ *
+ * Available since API level 29.
  */
 media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *,
         AMediaDrmKeysChangeListener listener) __INTRODUCED_IN(29);
@@ -216,8 +228,10 @@
 /**
  * Open a new session with the MediaDrm object.  A session ID is returned.
  *
- * returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed
- * returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use
+ * Returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed.
+ * Returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_openSession(AMediaDrm *,
         AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
@@ -225,6 +239,8 @@
 /**
  * Close a session on the MediaDrm object that was previously opened
  * with AMediaDrm_openSession.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_closeSession(AMediaDrm *,
         const AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
@@ -272,9 +288,11 @@
  *       MediaDrm object is released.
  *   2. keyRequestSize will be set to the size of the request
  *
- * returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
+ * Returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
  * problem with the device certificate.
-*/
+ *
+ * Available since API level 21.
+ */
 media_status_t AMediaDrm_getKeyRequest(AMediaDrm *, const AMediaDrmScope *scope,
         const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
         const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
@@ -295,8 +313,9 @@
  *
  * response points to the opaque response from the server
  * responseSize should be set to the size of the response in bytes
+ *
+ * Available since API level 21.
  */
-
 media_status_t AMediaDrm_provideKeyResponse(AMediaDrm *, const AMediaDrmScope *scope,
         const uint8_t *response, size_t responseSize,
         AMediaDrmKeySetId *keySetId) __INTRODUCED_IN(21);
@@ -305,8 +324,10 @@
  * Restore persisted offline keys into a new session.  keySetId identifies the
  * keys to load, obtained from a prior call to AMediaDrm_provideKeyResponse.
  *
- * sessionId is the session ID for the DRM session
- * keySetId identifies the saved key set to restore
+ * sessionId is the session ID for the DRM session.
+ * keySetId identifies the saved key set to restore.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_restoreKeys(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const AMediaDrmKeySetId *keySetId) __INTRODUCED_IN(21);
@@ -314,7 +335,9 @@
 /**
  * Remove the current keys from a session.
  *
- * keySetId identifies keys to remove
+ * keySetId identifies keys to remove.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_removeKeys(AMediaDrm *,
         const AMediaDrmSessionId *keySetId) __INTRODUCED_IN(21);
@@ -331,6 +354,8 @@
  * to the number of entries written to the array.  If the number of {key, value} pairs
  * to be returned is greater than *numPairs, MEDIADRM_SHORT_BUFFER will be returned
  * and numPairs will be set to the number of pairs available.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_queryKeyStatus(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         AMediaDrmKeyValue *keyValuePairs, size_t *numPairs) __INTRODUCED_IN(21);
@@ -350,6 +375,8 @@
  *    3. serverUrl will reference a NULL terminated string containing the URL
  *       the provisioning request should be sent to.  It will remain accessible until
  *       the next call to getProvisionRequest.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getProvisionRequest(AMediaDrm *, const uint8_t **provisionRequest,
         size_t *provisionRequestSize, const char **serverUrl) __INTRODUCED_IN(21);
@@ -363,8 +390,10 @@
  *   DRM engine plugin.
  * responseSize is the length of the provisioning response in bytes.
  *
- * returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
+ * Returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
  * server rejected the request
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *,
         const uint8_t *response, size_t responseSize) __INTRODUCED_IN(21);
@@ -390,6 +419,8 @@
  * If *numSecureStops is too small for the number of secure stops available,
  * MEDIADRM_SHORT_BUFFER will be returned and *numSecureStops will be set to the
  * number required.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getSecureStops(AMediaDrm *,
         AMediaDrmSecureStop *secureStops, size_t *numSecureStops) __INTRODUCED_IN(21);
@@ -399,6 +430,8 @@
  * the message, remove the SecureStops identified in the response.
  *
  * ssRelease is the server response indicating which secure stops to release
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_releaseSecureStops(AMediaDrm *,
         const AMediaDrmSecureStop *ssRelease) __INTRODUCED_IN(21);
@@ -432,6 +465,8 @@
  * On return, propertyValue will be set to point to the property value.  The
  * memory that the value resides in is owned by the NDK MediaDrm API and
  * will remain valid until the next call to AMediaDrm_getPropertyString.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getPropertyString(AMediaDrm *, const char *propertyName,
         const char **propertyValue) __INTRODUCED_IN(21);
@@ -447,18 +482,24 @@
  * On return, *propertyValue will be set to point to the property value.  The
  * memory that the value resides in is owned by the NDK MediaDrm API and
  * will remain valid until the next call to AMediaDrm_getPropertyByteArray.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *, const char *propertyName,
         AMediaDrmByteArray *propertyValue) __INTRODUCED_IN(21);
 
 /**
  * Set a DRM engine plugin String property value.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_setPropertyString(AMediaDrm *, const char *propertyName,
         const char *value) __INTRODUCED_IN(21);
 
 /**
  * Set a DRM engine plugin byte array property value.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *, const char *propertyName,
         const uint8_t *value, size_t valueSize) __INTRODUCED_IN(21);
@@ -487,6 +528,8 @@
  * ensure that the output buffer is large enough to accept dataSize bytes. The key
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_encrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
@@ -498,6 +541,8 @@
  * ensure that the output buffer is large enough to accept dataSize bytes.  The key
  * to use is identified by the 16 byte keyId.  The key must have been loaded into
  * the session using provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_decrypt(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
@@ -511,6 +556,8 @@
  * *signatureSize is set to the buffer size required.  The key to use is identified
  * by the 16 byte keyId.  The key must have been loaded into the session using
  * provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_sign(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
@@ -522,6 +569,8 @@
  * if the signature matches, otherwise MEDAIDRM_VERIFY_FAILED is returned. The key to
  * use is identified by the 16 byte keyId.  The key must have been loaded into the
  * session using provideKeyResponse.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaDrm_verify(AMediaDrm *, const AMediaDrmSessionId *sessionId,
         const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index e3d9fe6..14319c4 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -52,23 +52,31 @@
 #if __ANDROID_API__ >= 21
 
 /**
- * Create new media extractor
+ * Create new media extractor.
+ *
+ * Available since API level 21.
  */
 AMediaExtractor* AMediaExtractor_new() __INTRODUCED_IN(21);
 
 /**
- * Delete a previously created media extractor
+ * Delete a previously created media extractor.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_delete(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
- *  Set the file descriptor from which the extractor will read.
+ * Set the file descriptor from which the extractor will read.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_setDataSourceFd(AMediaExtractor*, int fd, off64_t offset,
         off64_t length) __INTRODUCED_IN(21);
 
 /**
  * Set the URI from which the extractor will read.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_setDataSource(AMediaExtractor*,
         const char *location) __INTRODUCED_IN(21);
@@ -77,6 +85,8 @@
 
 /**
  * Set the custom data source implementation from which the extractor will read.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor*,
         AMediaDataSource *src) __INTRODUCED_IN(28);
@@ -85,11 +95,15 @@
 
 /**
  * Return the number of tracks in the previously specified media file
+ *
+ * Available since API level 21.
  */
 size_t AMediaExtractor_getTrackCount(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Return the format of the specified track. The caller must free the returned format
+ *
+ * Available since API level 21.
  */
 AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
 
@@ -98,41 +112,55 @@
  * getSampleTime only retrieve information for the subset of tracks selected.
  * Selecting the same track multiple times has no effect, the track is
  * only selected once.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_selectTrack(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
 
 /**
  * Unselect the specified track. Subsequent calls to readSampleData, getSampleTrackIndex and
- * getSampleTime only retrieve information for the subset of tracks selected..
+ * getSampleTime only retrieve information for the subset of tracks selected.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_unselectTrack(AMediaExtractor*, size_t idx) __INTRODUCED_IN(21);
 
 /**
  * Read the current sample.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaExtractor_readSampleData(AMediaExtractor*,
         uint8_t *buffer, size_t capacity) __INTRODUCED_IN(21);
 
 /**
  * Read the current sample's flags.
+ *
+ * Available since API level 21.
  */
 uint32_t AMediaExtractor_getSampleFlags(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Returns the track index the current sample originates from (or -1
  * if no more samples are available)
+ *
+ * Available since API level 21.
  */
 int AMediaExtractor_getSampleTrackIndex(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Returns the current sample's presentation time in microseconds.
  * or -1 if no more samples are available.
+ *
+ * Available since API level 21.
  */
 int64_t AMediaExtractor_getSampleTime(AMediaExtractor*) __INTRODUCED_IN(21);
 
 /**
  * Advance to the next sample. Returns false if no more sample data
  * is available (end of stream).
+ *
+ * Available since API level 21.
  */
 bool AMediaExtractor_advance(AMediaExtractor*) __INTRODUCED_IN(21);
 
@@ -143,7 +171,7 @@
 } SeekMode;
 
 /**
- *
+ * Available since API level 21.
  */
 media_status_t AMediaExtractor_seekTo(AMediaExtractor*,
         int64_t seekPosUs, SeekMode mode) __INTRODUCED_IN(21);
@@ -167,10 +195,14 @@
 
 /**
  * Get the PSSH info if present.
+ *
+ * Available since API level 21.
  */
 PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor*) __INTRODUCED_IN(21);
 
-
+/**
+ * Available since API level 21.
+ */
 AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *) __INTRODUCED_IN(21);
 
 enum {
@@ -186,6 +218,8 @@
  *
  * This function will always return a format; however, the format could be empty
  * (no key-value pairs) if the media container does not provide format information.
+ *
+ * Available since API level 28.
  */
 AMediaFormat* AMediaExtractor_getFileFormat(AMediaExtractor*) __INTRODUCED_IN(28);
 
@@ -198,6 +232,7 @@
  * uint8_t *buf = new uint8_t[sampleSize];
  * AMediaExtractor_readSampleData(ex, buf, sampleSize);
  *
+ * Available since API level 28.
  */
 ssize_t AMediaExtractor_getSampleSize(AMediaExtractor*) __INTRODUCED_IN(28);
 
@@ -211,6 +246,8 @@
  * Returns -1 when the extractor is not reading from a network data source, or when the
  * cached duration cannot be calculated (bitrate, duration, and file size information
  * not available).
+ *
+ * Available since API level 28.
  */
 int64_t AMediaExtractor_getCachedDuration(AMediaExtractor *) __INTRODUCED_IN(28);
 
@@ -222,6 +259,8 @@
  * Returns AMEDIA_OK on success or AMEDIA_ERROR_* to indicate failure reason.
  * Existing key-value pairs in |fmt| would be removed if this API returns AMEDIA_OK.
  * The contents of |fmt| is undefined if this API returns AMEDIA_ERROR_*.
+ *
+ * Available since API level 28.
  */
 media_status_t AMediaExtractor_getSampleFormat(AMediaExtractor *ex,
         AMediaFormat *fmt) __INTRODUCED_IN(28);
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index fd43f36..41c2378 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -48,40 +48,78 @@
 
 #if __ANDROID_API__ >= 21
 
+/**
+ * Available since API level 21.
+ */
 AMediaFormat *AMediaFormat_new() __INTRODUCED_IN(21);
+
+/**
+ * Available since API level 21.
+ */
 media_status_t AMediaFormat_delete(AMediaFormat*) __INTRODUCED_IN(21);
 
 /**
  * Human readable representation of the format. The returned string is owned by the format,
  * and remains valid until the next call to toString, or until the format is deleted.
+ *
+ * Available since API level 21.
  */
 const char* AMediaFormat_toString(AMediaFormat*) __INTRODUCED_IN(21);
 
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getInt32(AMediaFormat*, const char *name, int32_t *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getInt64(AMediaFormat*, const char *name, int64_t *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getFloat(AMediaFormat*, const char *name, float *out) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 bool AMediaFormat_getSize(AMediaFormat*, const char *name, size_t *out) __INTRODUCED_IN(21);
 /**
  * The returned data is owned by the format and remains valid as long as the named entry
  * is part of the format.
+ *
+ * Available since API level 21.
  */
 bool AMediaFormat_getBuffer(AMediaFormat*, const char *name, void** data, size_t *size) __INTRODUCED_IN(21);
 /**
  * The returned string is owned by the format, and remains valid until the next call to getString,
  * or until the format is deleted.
+ *
+ * Available since API level 21.
  */
 bool AMediaFormat_getString(AMediaFormat*, const char *name, const char **out) __INTRODUCED_IN(21);
 
 
+/**
+ * Available since API level 21.
+ */
 void AMediaFormat_setInt32(AMediaFormat*, const char* name, int32_t value) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 void AMediaFormat_setInt64(AMediaFormat*, const char* name, int64_t value) __INTRODUCED_IN(21);
+/**
+ * Available since API level 21.
+ */
 void AMediaFormat_setFloat(AMediaFormat*, const char* name, float value) __INTRODUCED_IN(21);
 /**
  * The provided string is copied into the format.
+ *
+ * Available since API level 21.
  */
 void AMediaFormat_setString(AMediaFormat*, const char* name, const char* value) __INTRODUCED_IN(21);
 /**
  * The provided data is copied into the format.
+ *
+ * Available since API level 21.
  */
 void AMediaFormat_setBuffer(AMediaFormat*, const char* name, const void* data, size_t size) __INTRODUCED_IN(21);
 
@@ -155,24 +193,43 @@
 #endif /* __ANDROID_API__ >= 21 */
 
 #if __ANDROID_API__ >= 28
+/**
+ * Available since API level 28.
+ */
 bool AMediaFormat_getDouble(AMediaFormat*, const char *name, double *out) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
 bool AMediaFormat_getRect(AMediaFormat*, const char *name,
         int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) __INTRODUCED_IN(28);
 
+/**
+ * Available since API level 28.
+ */
 void AMediaFormat_setDouble(AMediaFormat*, const char* name, double value) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
 void AMediaFormat_setSize(AMediaFormat*, const char* name, size_t value) __INTRODUCED_IN(28);
+/**
+ * Available since API level 28.
+ */
 void AMediaFormat_setRect(AMediaFormat*, const char* name,
         int32_t left, int32_t top, int32_t right, int32_t bottom) __INTRODUCED_IN(28);
 #endif /* __ANDROID_API__ >= 28 */
 
 #if __ANDROID_API__ >= 29
 /**
- * remove all key/value pairs from the given AMediaFormat
+ * Remove all key/value pairs from the given AMediaFormat.
+ *
+ * Available since API level 29.
  */
 void AMediaFormat_clear(AMediaFormat*) __INTRODUCED_IN(29);
 
 /**
- * copy one AMediaFormat to another
+ * Copy one AMediaFormat to another.
+ *
+ * Available since API level 29.
  */
 media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) __INTRODUCED_IN(29);
 
diff --git a/media/ndk/include/media/NdkMediaMuxer.h b/media/ndk/include/media/NdkMediaMuxer.h
index 7393867..3fdeea4 100644
--- a/media/ndk/include/media/NdkMediaMuxer.h
+++ b/media/ndk/include/media/NdkMediaMuxer.h
@@ -56,12 +56,16 @@
 #if __ANDROID_API__ >= 21
 
 /**
- * Create new media muxer
+ * Create new media muxer.
+ *
+ * Available since API level 21.
  */
 AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) __INTRODUCED_IN(21);
 
 /**
- * Delete a previously created media muxer
+ * Delete a previously created media muxer.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_delete(AMediaMuxer*) __INTRODUCED_IN(21);
 
@@ -75,6 +79,8 @@
  * Both values are specified in degrees.
  * Latitude must be in the range [-90, 90].
  * Longitude must be in the range [-180, 180].
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_setLocation(AMediaMuxer*,
         float latitude, float longitude) __INTRODUCED_IN(21);
@@ -90,6 +96,8 @@
  * during playback.
  * The angle is specified in degrees, clockwise.
  * The supported angles are 0, 90, 180, and 270 degrees.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_setOrientationHint(AMediaMuxer*, int degrees) __INTRODUCED_IN(21);
 
@@ -97,18 +105,24 @@
  * Adds a track with the specified format.
  * Returns the index of the new track or a negative value in case of failure,
  * which can be interpreted as a media_status_t.
+ *
+ * Available since API level 21.
  */
 ssize_t AMediaMuxer_addTrack(AMediaMuxer*, const AMediaFormat* format) __INTRODUCED_IN(21);
 
 /**
  * Start the muxer. Should be called after AMediaMuxer_addTrack and
  * before AMediaMuxer_writeSampleData.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_start(AMediaMuxer*) __INTRODUCED_IN(21);
 
 /**
  * Stops the muxer.
  * Once the muxer stops, it can not be restarted.
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_stop(AMediaMuxer*) __INTRODUCED_IN(21);
 
@@ -118,6 +132,8 @@
  * the right tracks. Also, it needs to make sure the samples for each track
  * are written in chronological order (e.g. in the order they are provided
  * by the encoder.)
+ *
+ * Available since API level 21.
  */
 media_status_t AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
         size_t trackIdx, const uint8_t *data,
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
index 831944b..91b03f1 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/Android.bp
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -43,4 +43,8 @@
     srcs: ["src/main/**/*.java"],
 
     sdk_version: "system_current",
+
+    static_libs: [
+        "androidx.test.core",
+    ],
 }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
index b6ac7b5..24dbccc 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
+++ b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
@@ -1,3 +1,4 @@
 <resources>
     <string name="input_file_path">/data/local/tmp/MediaBenchmark/res/</string>
-</resources>
\ No newline at end of file
+    <string name="output_file_path">/data/local/tmp/MediaBenchmark/output/</string>
+</resources>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
new file mode 100644
index 0000000..be2633d
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Extractor;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class DecoderTest {
+    private static final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+    private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+    private static final String TAG = "DecoderTest";
+    private static final long PER_TEST_TIMEOUT_MS = 60000;
+    private static final boolean DEBUG = false;
+    private static final boolean WRITE_OUTPUT = false;
+    private String mInputFile;
+    private boolean mAsyncMode;
+
+    public DecoderTest(String inputFile, boolean asyncMode) {
+        this.mInputFile = inputFile;
+        this.mAsyncMode = asyncMode;
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> input() {
+        return Arrays.asList(new Object[][]{
+                //Audio Sync Test
+                {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", false},
+                {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false},
+                {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", false},
+                {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", false},
+                {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", false},
+                {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", false},
+                {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", false},
+                // Audio Async Test
+                {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", true},
+                {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", true},
+                {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", true},
+                {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", true},
+                {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", true},
+                {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", true},
+                {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", true},
+                // Video Sync Test
+                {"crowd_1920x1080_25fps_4000kbps_vp9.webm", false},
+                {"crowd_1920x1080_25fps_4000kbps_vp8.webm", false},
+                {"crowd_1920x1080_25fps_4000kbps_av1.webm", false},
+                {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", false},
+                {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", false},
+                {"crowd_352x288_25fps_6000kbps_h263.3gp", false},
+                {"crowd_1920x1080_25fps_6700kbps_h264.ts", false},
+                {"crowd_1920x1080_25fps_4000kbps_h265.mkv", false},
+                // Video Async Test
+                {"crowd_1920x1080_25fps_4000kbps_vp9.webm", true},
+                {"crowd_1920x1080_25fps_4000kbps_vp8.webm", true},
+                {"crowd_1920x1080_25fps_4000kbps_av1.webm", true},
+                {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", true},
+                {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", true},
+                {"crowd_352x288_25fps_6000kbps_h263.3gp", true},
+                {"crowd_1920x1080_25fps_6700kbps_h264.ts", true},
+                {"crowd_1920x1080_25fps_4000kbps_h265.mkv", true}});
+    }
+
+    @Test(timeout = PER_TEST_TIMEOUT_MS)
+    public void testDecoder() throws IOException {
+        File inputFile = new File(mInputFilePath + mInputFile);
+        if (inputFile.exists()) {
+            FileInputStream fileInput = new FileInputStream(inputFile);
+            FileDescriptor fileDescriptor = fileInput.getFD();
+            Extractor extractor = new Extractor();
+            int trackCount = extractor.setUpExtractor(fileDescriptor);
+            ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+            ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+            if (trackCount <= 0) {
+                Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
+                return;
+            }
+            for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+                extractor.selectExtractorTrack(currentTrack);
+                MediaFormat format = extractor.getFormat(currentTrack);
+                String mime = format.getString(MediaFormat.KEY_MIME);
+                ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+                if (mediaCodecs.size() <= 0) {
+                    Log.e(TAG,
+                            "No suitable codecs found for file: " + mInputFile
+                                    + " track : " + currentTrack + " mime: " + mime);
+                    continue;
+                }
+                // Get samples from extractor
+                int sampleSize;
+                do {
+                    sampleSize = extractor.getFrameSample();
+                    MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+                    MediaCodec.BufferInfo info = extractor.getBufferInfo();
+                    ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+                    dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+                    bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+                    inputBuffer.add(dataBuffer);
+                    frameInfo.add(bufInfo);
+                    if (DEBUG) {
+                        Log.d(TAG,
+                                "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = "
+                                        + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+                    }
+                } while (sampleSize > 0);
+                for (String codecName : mediaCodecs) {
+                    FileOutputStream decodeOutputStream = null;
+                    if (WRITE_OUTPUT) {
+                        if (!Paths.get(mOutputFilePath).toFile().exists()) {
+                            Files.createDirectories(Paths.get(mOutputFilePath));
+                        }
+                        File outFile = new File(mOutputFilePath + "decoder.out");
+                        if (outFile.exists()) {
+                            if (!outFile.delete()) {
+                                Log.e(TAG, " Unable to delete existing file" + outFile.toString());
+                            }
+                        }
+                        if (outFile.createNewFile()) {
+                            decodeOutputStream = new FileOutputStream(outFile);
+                        } else {
+                            Log.e(TAG, "Unable to create file: " + outFile.toString());
+                        }
+                    }
+                    Decoder decoder = new Decoder();
+                    decoder.setupDecoder(decodeOutputStream);
+                    int status =
+                            decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
+                    decoder.deInitCodec();
+                    if (status == 0) {
+                        decoder.dumpStatistics(
+                                mInputFile + " " + codecName, extractor.getClipDuration());
+                        Log.i(TAG,
+                                "Decoding Successful for file: " + mInputFile
+                                        + " with codec: " + codecName);
+                    } else {
+                        Log.e(TAG,
+                                "Decoder returned error " + status + " for file: " + mInputFile
+                                        + " with codec: " + codecName);
+                    }
+                    decoder.resetDecoder();
+                    if (decodeOutputStream != null) {
+                        decodeOutputStream.close();
+                    }
+                }
+                extractor.unselectExtractorTrack(currentTrack);
+                inputBuffer.clear();
+                frameInfo.clear();
+            }
+            extractor.deinitExtractor();
+            fileInput.close();
+        } else {
+            Log.w(TAG,
+                    "Warning: Test Skipped. Cannot find " + mInputFile + " in directory "
+                            + mInputFilePath);
+        }
+    }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
new file mode 100644
index 0000000..9db9c84
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Encoder;
+import com.android.media.benchmark.library.Extractor;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class EncoderTest {
+    private static final Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+    private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+    private static final String TAG = "EncoderTest";
+    private static final long PER_TEST_TIMEOUT_MS = 120000;
+    private static final boolean DEBUG = false;
+    private static final boolean WRITE_OUTPUT = false;
+    private static final int ENCODE_DEFAULT_FRAME_RATE = 25;
+    private static final int ENCODE_DEFAULT_BIT_RATE = 8000000 /* 8 Mbps */;
+    private static final int ENCODE_MIN_BIT_RATE = 600000 /* 600 Kbps */;
+
+    private String mInputFile;
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> inputFiles() {
+        return Arrays.asList(new Object[][]{
+                // Audio Test
+                {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4"},
+                {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp"},
+                {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp"},
+                {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4"},
+                {"bbb_48000hz_2ch_100kbps_opus_30sec.webm"},
+                // Video Test
+                {"crowd_1920x1080_25fps_4000kbps_vp8.webm"},
+                {"crowd_1920x1080_25fps_6700kbps_h264.ts"},
+                {"crowd_1920x1080_25fps_4000kbps_h265.mkv"},
+                {"crowd_1920x1080_25fps_4000kbps_vp9.webm"},
+                {"crowd_176x144_25fps_6000kbps_mpeg4.mp4"},
+                {"crowd_176x144_25fps_6000kbps_h263.3gp"}});
+    }
+
+    public EncoderTest(String inputFileName) {
+        this.mInputFile = inputFileName;
+    }
+
+    @Test(timeout = PER_TEST_TIMEOUT_MS)
+    public void sampleEncoderTest() throws Exception {
+        int status;
+        int frameSize;
+
+        //Parameters for video
+        int width = 0;
+        int height = 0;
+        int profile = 0;
+        int level = 0;
+        int frameRate = 0;
+
+        //Parameters for audio
+        int bitRate = 0;
+        int sampleRate = 0;
+        int numChannels = 0;
+
+        File inputFile = new File(mInputFilePath + mInputFile);
+        if (inputFile.exists()) {
+            FileInputStream fileInput = new FileInputStream(inputFile);
+            FileDescriptor fileDescriptor = fileInput.getFD();
+            Extractor extractor = new Extractor();
+            int trackCount = extractor.setUpExtractor(fileDescriptor);
+            if (trackCount <= 0) {
+                Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
+                return;
+            }
+            ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+            ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+            for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+                extractor.selectExtractorTrack(currentTrack);
+                MediaFormat format = extractor.getFormat(currentTrack);
+                // Get samples from extractor
+                int sampleSize;
+                do {
+                    sampleSize = extractor.getFrameSample();
+                    MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+                    MediaCodec.BufferInfo info = extractor.getBufferInfo();
+                    ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+                    dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+                    bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+                    inputBuffer.add(dataBuffer);
+                    frameInfo.add(bufInfo);
+                    if (DEBUG) {
+                        Log.d(TAG, "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = " +
+                                bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+                    }
+                } while (sampleSize > 0);
+
+                int tid = android.os.Process.myTid();
+                File decodedFile = new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+                FileOutputStream decodeOutputStream = new FileOutputStream(decodedFile);
+                Decoder decoder = new Decoder();
+                decoder.setupDecoder(decodeOutputStream);
+                status = decoder.decode(inputBuffer, frameInfo, false, format, "");
+                if (status == 0) {
+                    Log.i(TAG, "Decoding complete.");
+                } else {
+                    Log.e(TAG, "Decode returned error. Encoding did not take place." + status);
+                    return;
+                }
+                decoder.deInitCodec();
+                extractor.unselectExtractorTrack(currentTrack);
+                inputBuffer.clear();
+                frameInfo.clear();
+                if (decodeOutputStream != null) {
+                    decodeOutputStream.close();
+                }
+                String mime = format.getString(MediaFormat.KEY_MIME);
+                ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, true);
+                if (mediaCodecs.size() <= 0) {
+                    Log.e(TAG, "No suitable codecs found for file: " + mInputFile + " track : " +
+                            currentTrack + " mime: " + mime);
+                    return;
+                }
+                Boolean[] encodeMode = {true, false};
+                /* Encoding the decoder's output */
+                for (Boolean asyncMode : encodeMode) {
+                    for (String codecName : mediaCodecs) {
+                        FileOutputStream encodeOutputStream = null;
+                        if (WRITE_OUTPUT) {
+                            File outEncodeFile = new File(mOutputFilePath + "encoder.out");
+                            if (outEncodeFile.exists()) {
+                                if (!outEncodeFile.delete()) {
+                                    Log.e(TAG, "Unable to delete existing file" +
+                                            decodedFile.toString());
+                                }
+                            }
+                            if (outEncodeFile.createNewFile()) {
+                                encodeOutputStream = new FileOutputStream(outEncodeFile);
+                            } else {
+                                Log.e(TAG, "Unable to create file to write encoder output: " +
+                                        outEncodeFile.toString());
+                            }
+                        }
+                        File rawFile =
+                                new File(mContext.getFilesDir() + "/decoder_" + tid + ".out");
+                        if (rawFile.exists()) {
+                            if (DEBUG) {
+                                Log.i(TAG, "Path of decoded input file: " + rawFile.toString());
+                            }
+                            FileInputStream eleStream = new FileInputStream(rawFile);
+                            if (mime.startsWith("video/")) {
+                                width = format.getInteger(MediaFormat.KEY_WIDTH);
+                                height = format.getInteger(MediaFormat.KEY_HEIGHT);
+                                if (format.containsKey(MediaFormat.KEY_FRAME_RATE)) {
+                                    frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
+                                } else if (frameRate <= 0) {
+                                    frameRate = ENCODE_DEFAULT_FRAME_RATE;
+                                }
+                                if (format.containsKey(MediaFormat.KEY_BIT_RATE)) {
+                                    bitRate = format.getInteger(MediaFormat.KEY_BIT_RATE);
+                                } else if (bitRate <= 0) {
+                                    if (mime.contains("video/3gpp") ||
+                                            mime.contains("video/mp4v-es")) {
+                                        bitRate = ENCODE_MIN_BIT_RATE;
+                                    } else {
+                                        bitRate = ENCODE_DEFAULT_BIT_RATE;
+                                    }
+                                }
+                                if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+                                    profile = format.getInteger(MediaFormat.KEY_PROFILE);
+                                }
+                                if (format.containsKey(MediaFormat.KEY_PROFILE)) {
+                                    level = format.getInteger(MediaFormat.KEY_LEVEL);
+                                }
+                            } else {
+                                sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+                                numChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+                                bitRate = sampleRate * numChannels * 16;
+                            }
+                            /*Setup Encode Format*/
+                            MediaFormat encodeFormat;
+                            if (mime.startsWith("video/")) {
+                                frameSize = width * height * 3 / 2;
+                                encodeFormat = MediaFormat.createVideoFormat(mime, width, height);
+                                encodeFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+                                encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+                                encodeFormat.setInteger(MediaFormat.KEY_PROFILE, profile);
+                                encodeFormat.setInteger(MediaFormat.KEY_LEVEL, level);
+                                encodeFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
+                                encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, frameSize);
+                            } else {
+                                encodeFormat = MediaFormat
+                                        .createAudioFormat(mime, sampleRate, numChannels);
+                                encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+                                frameSize = 4096;
+                            }
+                            Encoder encoder = new Encoder();
+                            encoder.setupEncoder(encodeOutputStream, eleStream);
+                            status = encoder.encode(codecName, encodeFormat, mime, frameRate,
+                                    sampleRate, frameSize, asyncMode);
+                            encoder.deInitEncoder();
+                            if (status == 0) {
+                                encoder.dumpStatistics(mInputFile + "with " + codecName + " for " +
+                                        "aSyncMode = " + asyncMode, extractor.getClipDuration());
+                                Log.i(TAG, "Encoding complete for file: " + mInputFile +
+                                        " with codec: " + codecName + " for aSyncMode = " +
+                                        asyncMode);
+                            } else {
+                                Log.e(TAG,
+                                        codecName + " encoder returned error " + status + " for " +
+                                                "file:" + " " + mInputFile);
+                            }
+                            encoder.resetEncoder();
+                            eleStream.close();
+                            if (encodeOutputStream != null) {
+                                encodeOutputStream.close();
+                            }
+                        }
+                    }
+                }
+                //Cleanup temporary input file
+                if (decodedFile.exists()) {
+                    if (decodedFile.delete()) {
+                        Log.i(TAG, "Successfully deleted decoded file");
+                    } else {
+                        Log.e(TAG, "Unable to delete decoded file");
+                    }
+                }
+            }
+            extractor.deinitExtractor();
+            fileInput.close();
+        } else {
+            Log.w(TAG, "Warning: Test Skipped. Cannot find " + mInputFile + " in directory " +
+                    mInputFilePath);
+        }
+    }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
new file mode 100644
index 0000000..8c3080c
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/MuxerTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.media.benchmark.tests;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.Extractor;
+import com.android.media.benchmark.library.Muxer;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.util.Log;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Parameterized.class)
+public class MuxerTest {
+    private static Context mContext =
+            InstrumentationRegistry.getInstrumentation().getTargetContext();
+    private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+    private static final String TAG = "MuxerTest";
+    private static final Map<String, Integer> mMapFormat = new Hashtable<String, Integer>() {
+        {
+            put("mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
+            put("webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
+            put("3gpp", MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
+            put("ogg", MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG);
+        }
+    };
+    private String mInputFileName;
+    private String mFormat;
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> inputFiles() {
+        return Arrays.asList(new Object[][]{
+                /* Parameters: filename, format */
+                {"crowd_1920x1080_25fps_4000kbps_vp8.webm", "webm"},
+                {"crowd_1920x1080_25fps_4000kbps_vp9.webm", "webm"},
+                {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mp4"},
+                {"crowd_352x288_25fps_6000kbps_h263.3gp", "mp4"},
+                {"crowd_1920x1080_25fps_6700kbps_h264.ts", "mp4"},
+                {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "mp4"},
+                {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "3gpp"},
+                {"crowd_352x288_25fps_6000kbps_h263.3gp", "3gpp"},
+                {"crowd_1920x1080_25fps_6700kbps_h264.ts", "3gpp"},
+                {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "3gpp"},
+                {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "ogg"},
+                {"bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", "webm"},
+                {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "webm"},
+                {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "mp4"},
+                {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "mp4"},
+                {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "mp4"},
+                {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "3gpp"},
+                {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "3gpp"},
+                {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "3gpp"}});
+    }
+
+    public MuxerTest(String filename, String outputFormat) {
+        this.mInputFileName = filename;
+        this.mFormat = outputFormat;
+    }
+
+    @Test
+    public void sampleMuxerTest() throws IOException {
+        int status = -1;
+        File inputFile = new File(mInputFilePath + mInputFileName);
+        if (inputFile.exists()) {
+            FileInputStream fileInput = new FileInputStream(inputFile);
+            FileDescriptor fileDescriptor = fileInput.getFD();
+            ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+            ArrayList<MediaCodec.BufferInfo> inputBufferInfo = new ArrayList<>();
+            Extractor extractor = new Extractor();
+            int trackCount = extractor.setUpExtractor(fileDescriptor);
+            for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+                extractor.selectExtractorTrack(currentTrack);
+                while (true) {
+                    int sampleSize = extractor.getFrameSample();
+                    MediaCodec.BufferInfo bufferInfo = extractor.getBufferInfo();
+                    MediaCodec.BufferInfo tempBufferInfo = new MediaCodec.BufferInfo();
+                    tempBufferInfo
+                            .set(bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs,
+                                    bufferInfo.flags);
+                    inputBufferInfo.add(tempBufferInfo);
+                    ByteBuffer tempSampleBuffer = ByteBuffer.allocate(tempBufferInfo.size);
+                    tempSampleBuffer.put(extractor.getFrameBuffer().array(), 0, bufferInfo.size);
+                    inputBuffer.add(tempSampleBuffer);
+                    if (sampleSize < 0) {
+                        break;
+                    }
+                }
+                MediaFormat format = extractor.getFormat(currentTrack);
+                int outputFormat = mMapFormat.getOrDefault(mFormat, -1);
+                if (outputFormat != -1) {
+                    Muxer muxer = new Muxer();
+                    int trackIndex = muxer.setUpMuxer(mContext, outputFormat, format);
+                    status = muxer.mux(trackIndex, inputBuffer, inputBufferInfo);
+                    if (status != 0) {
+                        Log.e(TAG, "Cannot perform write operation for " + mInputFileName);
+                    }
+                    muxer.deInitMuxer();
+                    muxer.dumpStatistics(mInputFileName, extractor.getClipDuration());
+                    muxer.resetMuxer();
+                    extractor.unselectExtractorTrack(currentTrack);
+                    inputBufferInfo.clear();
+                    inputBuffer.clear();
+                } else {
+                    Log.e(TAG, "Test failed for " + mInputFileName + ". Returned invalid " +
+                            "output format for given " + mFormat + " format.");
+                }
+            }
+            extractor.deinitExtractor();
+            fileInput.close();
+        } else {
+            Log.w(TAG, "Warning: Test Skipped. Cannot find " + mInputFileName + " in directory " +
+                    mInputFilePath);
+        }
+        assertThat(status, is(equalTo(0)));
+    }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
new file mode 100644
index 0000000..08035c9
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
@@ -0,0 +1,39 @@
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.os.Build;
+
+import java.util.ArrayList;
+
+public class CodecUtils {
+    private CodecUtils() {}
+
+    /**
+     * Queries the MediaCodecList and returns codec names of supported codecs.
+     *
+     * @param mimeType  Mime type of input
+     * @param isEncoder Specifies encoder or decoder
+     * @return ArrayList of codec names
+     */
+    public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
+        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+        ArrayList<String> supportedCodecs = new ArrayList<>();
+        for (MediaCodecInfo codecInfo : codecInfos) {
+            if (isEncoder != codecInfo.isEncoder()) {
+                continue;
+            }
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) {
+                continue;
+            }
+            String[] types = codecInfo.getSupportedTypes();
+            for (String type : types) {
+                if (type.equalsIgnoreCase(mimeType)) {
+                    supportedCodecs.add(codecInfo.getName());
+                }
+            }
+        }
+        return supportedCodecs;
+    }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
new file mode 100644
index 0000000..2cd27c2
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Decoder {
+    private static final String TAG = "Decoder";
+    private static final boolean DEBUG = false;
+    private static final int kQueueDequeueTimeoutUs = 1000;
+
+    private final Object mLock = new Object();
+    private MediaCodec mCodec;
+    private ArrayList<BufferInfo> mInputBufferInfo;
+    private Stats mStats;
+
+    private boolean mSawInputEOS;
+    private boolean mSawOutputEOS;
+    private boolean mSignalledError;
+
+    private int mNumOutputFrame;
+    private int mIndex;
+
+    private ArrayList<ByteBuffer> mInputBuffer;
+    private FileOutputStream mOutputStream;
+
+    public Decoder() { mStats = new Stats(); }
+
+    /**
+     * Setup of decoder
+     *
+     * @param outputStream Will dump the output in this stream if not null.
+     */
+    public void setupDecoder(FileOutputStream outputStream) {
+        mSignalledError = false;
+        mOutputStream = outputStream;
+    }
+
+    private MediaCodec createCodec(String codecName, MediaFormat format) throws IOException {
+        String mime = format.getString(MediaFormat.KEY_MIME);
+        try {
+            MediaCodec codec;
+            if (codecName.isEmpty()) {
+                Log.i(TAG, "File mime type: " + mime);
+                if (mime != null) {
+                    codec = MediaCodec.createDecoderByType(mime);
+                    Log.i(TAG, "Decoder created for mime type " + mime);
+                    return codec;
+                } else {
+                    Log.e(TAG, "Mime type is null, please specify a mime type to create decoder");
+                    return null;
+                }
+            } else {
+                codec = MediaCodec.createByCodecName(codecName);
+                Log.i(TAG, "Decoder created with codec name: " + codecName + " mime: " + mime);
+                return codec;
+            }
+        } catch (IllegalArgumentException ex) {
+            ex.printStackTrace();
+            Log.e(TAG, "Failed to create decoder for " + codecName + " mime:" + mime);
+            return null;
+        }
+    }
+
+    /**
+     * Decodes the given input buffer,
+     * provided valid list of buffer info and format are passed as inputs.
+     *
+     * @param inputBuffer     Decode the provided list of ByteBuffers
+     * @param inputBufferInfo List of buffer info corresponding to provided input buffers
+     * @param asyncMode       Will run on async implementation if true
+     * @param format          For creating the decoder if codec name is empty and configuring it
+     * @param codecName       Will create the decoder with codecName
+     * @return 0 if decode was successful , -1 for fail, -2 for decoder not created
+     * @throws IOException if the codec cannot be created.
+     */
+    public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
+            @NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
+            @NonNull MediaFormat format, String codecName) throws IOException {
+        mInputBuffer = new ArrayList<>(inputBuffer.size());
+        mInputBuffer.addAll(inputBuffer);
+        mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
+        mInputBufferInfo.addAll(inputBufferInfo);
+        mSawInputEOS = false;
+        mSawOutputEOS = false;
+        mNumOutputFrame = 0;
+        mIndex = 0;
+        long sTime = mStats.getCurTime();
+        mCodec = createCodec(codecName, format);
+        if (mCodec == null) {
+            return -2;
+        }
+        if (asyncMode) {
+            mCodec.setCallback(new MediaCodec.Callback() {
+                @Override
+                public void onInputBufferAvailable(
+                        @NonNull MediaCodec mediaCodec, int inputBufferId) {
+                    try {
+                        mStats.addInputTime();
+                        onInputAvailable(inputBufferId, mediaCodec);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        Log.e(TAG, e.toString());
+                    }
+                }
+
+                @Override
+                public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+                        int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+                    mStats.addOutputTime();
+                    onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+                    if (mSawOutputEOS) {
+                        Log.i(TAG, "Saw output EOS");
+                        synchronized (mLock) { mLock.notify(); }
+                    }
+                }
+
+                @Override
+                public void onOutputFormatChanged(
+                        @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+                    Log.i(TAG, "Output format changed. Format: " + format.toString());
+                }
+
+                @Override
+                public void onError(
+                        @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+                    mSignalledError = true;
+                    Log.e(TAG, "Codec Error: " + e.toString());
+                    e.printStackTrace();
+                    synchronized (mLock) { mLock.notify(); }
+                }
+            });
+        }
+        int isEncoder = 0;
+        if (DEBUG) {
+            Log.d(TAG, "Media Format : " + format.toString());
+        }
+        mCodec.configure(format, null, null, isEncoder);
+        mCodec.start();
+        Log.i(TAG, "Codec started ");
+        long eTime = mStats.getCurTime();
+        mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+        mStats.setStartTime();
+        if (asyncMode) {
+            try {
+                synchronized (mLock) { mLock.wait(); }
+                if (mSignalledError) {
+                    return -1;
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        } else {
+            while (!mSawOutputEOS && !mSignalledError) {
+                /* Queue input data */
+                if (!mSawInputEOS) {
+                    int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+                    if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+                        Log.e(TAG,
+                                "MediaCodec.dequeueInputBuffer "
+                                        + " returned invalid index : " + inputBufferId);
+                        return -1;
+                    }
+                    mStats.addInputTime();
+                    onInputAvailable(inputBufferId, mCodec);
+                }
+                /* Dequeue output data */
+                BufferInfo outputBufferInfo = new BufferInfo();
+                int outputBufferId =
+                        mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+                if (outputBufferId < 0) {
+                    if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                        MediaFormat outFormat = mCodec.getOutputFormat();
+                        Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+                    } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+                        Log.i(TAG, "Ignoring deprecated flag: INFO_OUTPUT_BUFFERS_CHANGED");
+                    } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+                        Log.e(TAG,
+                                "MediaCodec.dequeueOutputBuffer"
+                                        + " returned invalid index " + outputBufferId);
+                        return -1;
+                    }
+                } else {
+                    mStats.addOutputTime();
+                    if (DEBUG) {
+                        Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+                    }
+                    onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+                }
+                if (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+                    Log.i(TAG, "Saw output EOS");
+                }
+            }
+        }
+        mInputBuffer.clear();
+        mInputBufferInfo.clear();
+        return 0;
+    }
+
+    /**
+     * Stops the codec and releases codec resources.
+     */
+    public void deInitCodec() {
+        long sTime = mStats.getCurTime();
+        if (mCodec != null) {
+            mCodec.stop();
+            mCodec.release();
+            mCodec = null;
+        }
+        long eTime = mStats.getCurTime();
+        mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+    }
+
+    /**
+     * Prints out the statistics in the information log
+     *
+     * @param inputReference The operation being performed, in this case decode
+     * @param durationUs     Duration of the clip in microseconds
+     */
+    public void dumpStatistics(String inputReference, long durationUs) {
+        String operation = "decode";
+        mStats.dumpStatistics(operation, inputReference, durationUs);
+    }
+
+    /**
+     * Resets the stats
+     */
+    public void resetDecoder() { mStats.reset(); }
+
+    private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
+        if ((inputBufferId >= 0) && !mSawInputEOS) {
+            ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
+            BufferInfo bufInfo = mInputBufferInfo.get(mIndex);
+            inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+            mIndex++;
+            if (bufInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+                mSawInputEOS = true;
+                Log.i(TAG, "Saw input EOS");
+            }
+            mStats.addFrameSize(bufInfo.size);
+            mediaCodec.queueInputBuffer(inputBufferId, bufInfo.offset, bufInfo.size,
+                    bufInfo.presentationTimeUs, bufInfo.flags);
+            if (DEBUG) {
+                Log.d(TAG,
+                        "Codec Input: "
+                                + "flag = " + bufInfo.flags + " timestamp = "
+                                + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+            }
+        }
+    }
+
+    private void onOutputAvailable(
+            MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
+        if (mSawOutputEOS || outputBufferId < 0) {
+            return;
+        }
+        mNumOutputFrame++;
+        if (DEBUG) {
+            Log.d(TAG,
+                    "In OutputBufferAvailable ,"
+                            + " output frame number = " + mNumOutputFrame);
+        }
+        if (mOutputStream != null) {
+            try {
+                ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+                byte[] bytesOutput = new byte[outputBuffer.remaining()];
+                outputBuffer.get(bytesOutput);
+                mOutputStream.write(bytesOutput);
+            } catch (IOException e) {
+                e.printStackTrace();
+                Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+            }
+        }
+        mediaCodec.releaseOutputBuffer(outputBufferId, false);
+        mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+    }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
new file mode 100644
index 0000000..03db294
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class Encoder {
+    private static final int ENCODE_DEFAULT_MAX_INPUT_SIZE = 3840;
+    private static final String TAG = "Encoder";
+    private static final boolean DEBUG = false;
+    private static final int kQueueDequeueTimeoutUs = 1000;
+
+    private final Object mLock = new Object();
+    private MediaCodec mCodec;
+    private String mMime;
+    private Stats mStats;
+
+    private int mOffset;
+    private int mFrameSize;
+    private int mNumInputFrame;
+    private int mNumFrames;
+    private int mFrameRate;
+    private int mSampleRate;
+    private long mInputBufferSize;
+
+    private boolean mSawInputEOS;
+    private boolean mSawOutputEOS;
+    private boolean mSignalledError;
+
+    private FileInputStream mInputStream;
+    private FileOutputStream mOutputStream;
+
+    public Encoder() {
+        mStats = new Stats();
+        mNumInputFrame = 0;
+        mSawInputEOS = false;
+        mSawOutputEOS = false;
+        mSignalledError = false;
+    }
+
+    /**
+     * Setup of encoder
+     *
+     * @param encoderOutputStream Will dump the encoder output in this stream if not null.
+     * @param fileInputStream     Will read the decoded output from this stream
+     */
+    public void setupEncoder(FileOutputStream encoderOutputStream,
+                             FileInputStream fileInputStream) {
+        this.mInputStream = fileInputStream;
+        this.mOutputStream = encoderOutputStream;
+    }
+
+    private MediaCodec createCodec(String codecName, String mime) throws IOException {
+        try {
+            MediaCodec codec;
+            if (codecName.isEmpty()) {
+                Log.i(TAG, "Mime type: " + mime);
+                if (mime != null) {
+                    codec = MediaCodec.createEncoderByType(mime);
+                    Log.i(TAG, "Encoder created for mime type " + mime);
+                    return codec;
+                } else {
+                    Log.e(TAG, "Mime type is null, please specify a mime type to create encoder");
+                    return null;
+                }
+            } else {
+                codec = MediaCodec.createByCodecName(codecName);
+                Log.i(TAG, "Encoder created with codec name: " + codecName + " and mime: " + mime);
+                return codec;
+            }
+        } catch (IllegalArgumentException ex) {
+            ex.printStackTrace();
+            Log.e(TAG, "Failed to create encoder for " + codecName + " mime: " + mime);
+            return null;
+        }
+    }
+
+    /**
+     * Encodes the given raw input file and measures the performance of encode operation,
+     * provided a valid list of parameters are passed as inputs.
+     *
+     * @param codecName    Will create the encoder with codecName
+     * @param mime         For creating encode format
+     * @param encodeFormat Format of the output data
+     * @param frameSize    Size of the frame
+     * @param asyncMode    Will run on async implementation if true
+     * @return 0 if encode was successful , -1 for fail, -2 for encoder not created
+     * @throws IOException If the codec cannot be created.
+     */
+    public int encode(String codecName, MediaFormat encodeFormat, String mime, int frameRate,
+                      int sampleRate, int frameSize, boolean asyncMode) throws IOException {
+        mInputBufferSize = mInputStream.getChannel().size();
+        mMime = mime;
+        mOffset = 0;
+        mFrameRate = frameRate;
+        mSampleRate = sampleRate;
+        long sTime = mStats.getCurTime();
+        mCodec = createCodec(codecName, mime);
+        if (mCodec == null) {
+            return -2;
+        }
+        /*Configure Codec*/
+        try {
+            mCodec.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+        } catch (IllegalArgumentException | IllegalStateException | MediaCodec.CryptoException e) {
+            Log.e(TAG, "Failed to configure " + mCodec.getName() + " encoder.");
+            e.printStackTrace();
+            return -2;
+        }
+        if (mMime.startsWith("video/")) {
+            mFrameSize = frameSize;
+        } else {
+            int maxInputSize = ENCODE_DEFAULT_MAX_INPUT_SIZE;
+            MediaFormat format = mCodec.getInputFormat();
+            if (format.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
+                maxInputSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
+            }
+            mFrameSize = frameSize;
+            if (mFrameSize > maxInputSize && maxInputSize > 0) {
+                mFrameSize = maxInputSize;
+            }
+        }
+        mNumFrames = (int) ((mInputBufferSize + mFrameSize - 1) / mFrameSize);
+        if (asyncMode) {
+            mCodec.setCallback(new MediaCodec.Callback() {
+                @Override
+                public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec,
+                                                   int inputBufferId) {
+                    try {
+                        mStats.addInputTime();
+                        onInputAvailable(mediaCodec, inputBufferId);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        Log.e(TAG, e.toString());
+                    }
+                }
+
+                @Override
+                public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+                                                    int outputBufferId,
+                                                    @NonNull MediaCodec.BufferInfo bufferInfo) {
+                    mStats.addOutputTime();
+                    onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+                    if (mSawOutputEOS) {
+                        Log.i(TAG, "Saw output EOS");
+                        synchronized (mLock) { mLock.notify(); }
+                    }
+                }
+
+                @Override
+                public void onError(@NonNull MediaCodec mediaCodec, @NonNull CodecException e) {
+                    mediaCodec.stop();
+                    mediaCodec.release();
+                    Log.e(TAG, "CodecError: " + e.toString());
+                    e.printStackTrace();
+                }
+
+                @Override
+                public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec,
+                                                  @NonNull MediaFormat format) {
+                    Log.i(TAG, "Output format changed. Format: " + format.toString());
+                }
+            });
+        }
+        mCodec.start();
+        long eTime = mStats.getCurTime();
+        mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+        mStats.setStartTime();
+        if (asyncMode) {
+            try {
+                synchronized (mLock) { mLock.wait(); }
+                if (mSignalledError) {
+                    return -1;
+                }
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        } else {
+            while (!mSawOutputEOS && !mSignalledError) {
+                /* Queue input data */
+                if (!mSawInputEOS) {
+                    int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+                    if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+                        Log.e(TAG, "MediaCodec.dequeueInputBuffer " + "returned invalid index : " +
+                                inputBufferId);
+                        return -1;
+                    }
+                    mStats.addInputTime();
+                    onInputAvailable(mCodec, inputBufferId);
+                }
+                /* Dequeue output data */
+                MediaCodec.BufferInfo outputBufferInfo = new MediaCodec.BufferInfo();
+                int outputBufferId =
+                        mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+                if (outputBufferId < 0) {
+                    if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+                        MediaFormat outFormat = mCodec.getOutputFormat();
+                        Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+                    } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+                        Log.e(TAG, "MediaCodec.dequeueOutputBuffer" + " returned invalid index " +
+                                outputBufferId);
+                        return -1;
+                    }
+                } else {
+                    mStats.addOutputTime();
+                    if (DEBUG) {
+                        Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+                    }
+                    onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+                }
+            }
+        }
+        return 0;
+    }
+
+    private void onOutputAvailable(MediaCodec mediaCodec, int outputBufferId,
+                                   MediaCodec.BufferInfo outputBufferInfo) {
+        if (mSawOutputEOS || outputBufferId < 0) {
+            if (mSawOutputEOS) {
+                Log.i(TAG, "Saw output EOS");
+            }
+            return;
+        }
+        ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+        if (mOutputStream != null) {
+            try {
+
+                byte[] bytesOutput = new byte[outputBuffer.remaining()];
+                outputBuffer.get(bytesOutput);
+                mOutputStream.write(bytesOutput);
+            } catch (IOException e) {
+                e.printStackTrace();
+                Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+                return;
+            }
+        }
+        mStats.addFrameSize(outputBuffer.remaining());
+        mediaCodec.releaseOutputBuffer(outputBufferId, false);
+        mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+    }
+
+    private void onInputAvailable(MediaCodec mediaCodec, int inputBufferId) throws IOException {
+        if (mSawOutputEOS || inputBufferId < 0) {
+            if (mSawOutputEOS) {
+                Log.i(TAG, "Saw input EOS");
+            }
+            return;
+        }
+        if (mInputBufferSize < mOffset) {
+            Log.e(TAG, "Out of bound access of input buffer");
+            mSignalledError = true;
+            return;
+        }
+        ByteBuffer inputBuffer = mCodec.getInputBuffer(inputBufferId);
+        if (inputBuffer == null) {
+            mSignalledError = true;
+            return;
+        }
+        int bufSize = inputBuffer.capacity();
+        int bytesRead = mFrameSize;
+        if (mInputBufferSize - mOffset < mFrameSize) {
+            bytesRead = (int) (mInputBufferSize - mOffset);
+        }
+        if (bufSize < bytesRead) {
+            mSignalledError = true;
+            return;
+        }
+        byte[] inputArray = new byte[bytesRead];
+        mInputStream.read(inputArray, 0, bytesRead);
+        inputBuffer.put(inputArray);
+        int flag = 0;
+        if (mNumInputFrame >= mNumFrames - 1 || bytesRead == 0) {
+            Log.i(TAG, "Sending EOS on input last frame");
+            mSawInputEOS = true;
+            flag = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+        }
+        int presentationTimeUs;
+        if (mMime.startsWith("video/")) {
+            presentationTimeUs = mNumInputFrame * (1000000 / mFrameRate);
+        } else {
+            presentationTimeUs = mNumInputFrame * mFrameSize * 1000000 / mSampleRate;
+        }
+        mediaCodec.queueInputBuffer(inputBufferId, 0, bytesRead, presentationTimeUs, flag);
+        mNumInputFrame++;
+        mOffset += bytesRead;
+    }
+
+    /**
+     * Stops the codec and releases codec resources.
+     */
+    public void deInitEncoder() {
+        long sTime = mStats.getCurTime();
+        if (mCodec != null) {
+            mCodec.stop();
+            mCodec.release();
+            mCodec = null;
+        }
+        long eTime = mStats.getCurTime();
+        mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+    }
+
+    /**
+     * Prints out the statistics in the information log
+     *
+     * @param inputReference The operation being performed, in this case encode
+     * @param durationUs     Duration of the clip in microseconds
+     */
+    public void dumpStatistics(String inputReference, long durationUs) {
+        String operation = "encode";
+        mStats.dumpStatistics(operation, inputReference, durationUs);
+    }
+
+    /**
+     * Resets the stats
+     */
+    public void resetEncoder() {
+        mOffset = 0;
+        mInputBufferSize = 0;
+        mNumInputFrame = 0;
+        mSawInputEOS = false;
+        mSawOutputEOS = false;
+        mSignalledError = false;
+        mStats.reset();
+    }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
new file mode 100644
index 0000000..49eaa1c
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.media.benchmark.library;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Muxer {
+    private Stats mStats;
+    private MediaMuxer mMuxer;
+
+    /**
+     * Creates a Media Muxer for the specified path
+     *
+     * @param context      App context to specify the output file path
+     * @param outputFormat Format of the output media file
+     * @param trackFormat  Format of the current track
+     * @return Returns the track index of the newly added track, -1 otherwise
+     */
+    public int setUpMuxer(Context context, int outputFormat, MediaFormat trackFormat) {
+        try {
+            mStats = new Stats();
+            long sTime = mStats.getCurTime();
+            mMuxer = new MediaMuxer(context.getFilesDir().getPath() + "/mux.out.", outputFormat);
+            int trackIndex = mMuxer.addTrack(trackFormat);
+            mMuxer.start();
+            long eTime = mStats.getCurTime();
+            long timeTaken = mStats.getTimeDiff(sTime, eTime);
+            mStats.setInitTime(timeTaken);
+            return trackIndex;
+        } catch (IllegalArgumentException | IOException e) {
+            e.printStackTrace();
+            return -1;
+        }
+    }
+
+    /**
+     * Performs the Mux operation
+     *
+     * @param trackIndex           Track index of the sample
+     * @param inputExtractedBuffer Buffer containing encoded samples
+     * @param inputBufferInfo      Buffer information related to these samples
+     * @return Returns Status as 0 if write operation is successful, -1 otherwise
+     */
+    public int mux(int trackIndex, ArrayList<ByteBuffer> inputExtractedBuffer,
+                   ArrayList<MediaCodec.BufferInfo> inputBufferInfo) {
+        mStats.setStartTime();
+        for (int sampleCount = 0; sampleCount < inputExtractedBuffer.size(); sampleCount++) {
+            try {
+                mMuxer.writeSampleData(trackIndex, inputExtractedBuffer.get(sampleCount),
+                        inputBufferInfo.get(sampleCount));
+                mStats.addOutputTime();
+                mStats.addFrameSize(inputBufferInfo.get(sampleCount).size);
+            } catch (IllegalArgumentException | IllegalStateException e) {
+                e.printStackTrace();
+                return -1;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Stops the muxer and free up the resources
+     */
+    public void deInitMuxer() {
+        long sTime = mStats.getCurTime();
+        mMuxer.stop();
+        mMuxer.release();
+        long eTime = mStats.getCurTime();
+        long timeTaken = mStats.getTimeDiff(sTime, eTime);
+        mStats.setDeInitTime(timeTaken);
+    }
+
+    /**
+     * Resets the stats
+     */
+    public void resetMuxer() {
+        mStats.reset();
+    }
+
+    /**
+     * Write the benchmark logs for the given input file
+     *
+     * @param inputReference Name of the input file
+     * @param clipDuration   Duration of the given inputReference file
+     */
+    public void dumpStatistics(String inputReference, long clipDuration) {
+        String operation = "mux";
+        mStats.dumpStatistics(operation, inputReference, clipDuration);
+    }
+}
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 5dd83dd..487ddb8 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -9,9 +9,11 @@
 ```
 mmm frameworks/av/media/tests/benchmark/
 ```
-To run the test suite for measuring performance of the native layer, follow the following steps:
+
 # NDK
 
+To run the test suite for measuring performance of the native layer, follow the following steps:
+
 The binaries will be created in the following path : ${OUT}/data/nativetest64/
 
 adb push $(OUT)/data/nativetest64/* /data/local/tmp/
@@ -96,3 +98,25 @@
 ```
 adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.ExtractorTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
 ```
+
+## Decoder
+
+The test decodes input stream and benchmarks the decoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.DecoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Muxer
+
+The test muxes elementary stream and benchmarks different writers available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.MuxerTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Encoder
+
+The test encodes input stream and benchmarks the encoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.EncoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+
+```
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index 527f588..1da0102 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -15,10 +15,10 @@
  */
 
 cc_library_static {
-    name: "libbenchmark_common",
+    name: "libmediabenchmark_common",
     defaults: [
-        "libbenchmark-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: [
@@ -32,23 +32,19 @@
 }
 
 cc_defaults {
-    name: "libbenchmark_common-defaults",
+    name: "libmediabenchmark_common-defaults",
 
     defaults: [
-        "libbenchmark-defaults",
+        "libmediabenchmark-defaults",
     ],
 
     static_libs: [
-        "libbenchmark_common",
+        "libmediabenchmark_common",
     ],
 }
 
 cc_defaults {
-    name: "libbenchmark-defaults",
-
-    header_libs: [
-        "media_ndk_headers",
-    ],
+    name: "libmediabenchmark-defaults",
 
     shared_libs: [
         "libmediandk",
@@ -65,7 +61,7 @@
 // public dependency for native implementation
 // to be used by code under media/benchmark/* only
 cc_defaults {
-    name: "libbenchmark_soft_sanitize_all-defaults",
+    name: "libmediabenchmark_soft_sanitize_all-defaults",
 
     sanitize: {
         misc_undefined: [
@@ -73,6 +69,5 @@
             "signed-integer-overflow",
         ],
         cfi: true,
-        address: true,
     }
 }
diff --git a/media/tests/benchmark/src/native/decoder/Android.bp b/media/tests/benchmark/src/native/decoder/Android.bp
index f2d3db5..b6286d4 100644
--- a/media/tests/benchmark/src/native/decoder/Android.bp
+++ b/media/tests/benchmark/src/native/decoder/Android.bp
@@ -15,15 +15,15 @@
  */
 
 cc_library_static {
-    name: "libbenchmark_decoder",
+    name: "libmediabenchmark_decoder",
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["Decoder.cpp"],
 
-    static_libs: ["libbenchmark_extractor"],
+    static_libs: ["libmediabenchmark_extractor"],
 
     export_include_dirs: ["."],
 
diff --git a/media/tests/benchmark/src/native/encoder/Android.bp b/media/tests/benchmark/src/native/encoder/Android.bp
index c14c319..239f378 100644
--- a/media/tests/benchmark/src/native/encoder/Android.bp
+++ b/media/tests/benchmark/src/native/encoder/Android.bp
@@ -15,16 +15,16 @@
  */
 
 cc_library_static {
-    name: "libbenchmark_encoder",
+    name: "libmediabenchmark_encoder",
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["Encoder.cpp"],
 
-    static_libs: ["libbenchmark_extractor",
-                  "libbenchmark_decoder",
+    static_libs: ["libmediabenchmark_extractor",
+                  "libmediabenchmark_decoder",
     ],
 
     export_include_dirs: ["."],
diff --git a/media/tests/benchmark/src/native/extractor/Android.bp b/media/tests/benchmark/src/native/extractor/Android.bp
index 2fbe4e8..dfd0d49 100644
--- a/media/tests/benchmark/src/native/extractor/Android.bp
+++ b/media/tests/benchmark/src/native/extractor/Android.bp
@@ -15,10 +15,10 @@
  */
 
 cc_library_static {
-    name: "libbenchmark_extractor",
+    name: "libmediabenchmark_extractor",
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["Extractor.cpp"],
diff --git a/media/tests/benchmark/src/native/muxer/Android.bp b/media/tests/benchmark/src/native/muxer/Android.bp
index 6ef2a2e..f669d4a 100644
--- a/media/tests/benchmark/src/native/muxer/Android.bp
+++ b/media/tests/benchmark/src/native/muxer/Android.bp
@@ -15,15 +15,15 @@
  */
 
 cc_library_static {
-    name: "libbenchmark_muxer",
+    name: "libmediabenchmark_muxer",
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["Muxer.cpp"],
 
-    static_libs: ["libbenchmark_extractor"],
+    static_libs: ["libmediabenchmark_extractor"],
 
     export_include_dirs: ["."],
 
diff --git a/media/tests/benchmark/tests/Android.bp b/media/tests/benchmark/tests/Android.bp
index fc21ef7..24fd68c 100644
--- a/media/tests/benchmark/tests/Android.bp
+++ b/media/tests/benchmark/tests/Android.bp
@@ -18,28 +18,28 @@
     name: "extractorTest",
     gtest: true,
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["ExtractorTest.cpp"],
 
-    static_libs: ["libbenchmark_extractor"]
+    static_libs: ["libmediabenchmark_extractor"]
 }
 
 cc_test {
     name: "decoderTest",
     gtest: true,
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["DecoderTest.cpp"],
 
     static_libs: [
-        "libbenchmark_extractor",
-        "libbenchmark_decoder",
+        "libmediabenchmark_extractor",
+        "libmediabenchmark_decoder",
     ],
 }
 
@@ -47,15 +47,15 @@
     name: "muxerTest",
     gtest: true,
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["MuxerTest.cpp"],
 
     static_libs: [
-        "libbenchmark_extractor",
-        "libbenchmark_muxer",
+        "libmediabenchmark_extractor",
+        "libmediabenchmark_muxer",
     ],
 }
 
@@ -63,15 +63,15 @@
     name: "encoderTest",
     gtest: true,
     defaults: [
-        "libbenchmark_common-defaults",
-        "libbenchmark_soft_sanitize_all-defaults",
+        "libmediabenchmark_common-defaults",
+        "libmediabenchmark_soft_sanitize_all-defaults",
     ],
 
     srcs: ["EncoderTest.cpp"],
 
     static_libs: [
-        "libbenchmark_extractor",
-        "libbenchmark_decoder",
-        "libbenchmark_encoder",
+        "libmediabenchmark_extractor",
+        "libmediabenchmark_decoder",
+        "libmediabenchmark_encoder",
     ],
 }
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 6cb42d6..242178f 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -72,24 +72,7 @@
         vector<AMediaCodecBufferInfo> frameInfo;
         AMediaCodecBufferInfo info;
         uint32_t inputBufferOffset = 0;
-        int32_t idx = 0;
 
-        // Get CSD data
-        while (1) {
-            void *csdBuffer = extractor->getCSDSample(info, idx);
-            if (!csdBuffer || !info.size) break;
-
-            // copy the meta data and buffer to be passed to decoder
-            if (inputBufferOffset + info.size > kMaxBufferSize) {
-                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
-                free(inputBuffer);
-                return;
-            }
-            memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
-            frameInfo.push_back(info);
-            inputBufferOffset += info.size;
-            idx++;
-        }
         // Get frame data
         while (1) {
             status = extractor->getFrameSample(info);
@@ -135,6 +118,7 @@
                           make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
                           make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
                           make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", false),
+                          make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
                           make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
 
 INSTANTIATE_TEST_SUITE_P(
@@ -144,6 +128,7 @@
                           make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
                           make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
                           make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", true),
+                          make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
                           make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
 
 INSTANTIATE_TEST_SUITE_P(VideDecoderSyncTest, DecoderTest,
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index 574083d..9f42c64 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -72,24 +72,6 @@
         vector<AMediaCodecBufferInfo> frameInfo;
         AMediaCodecBufferInfo info;
         uint32_t inputBufferOffset = 0;
-        int32_t idx = 0;
-
-        // Get CSD data
-        while (1) {
-            void *csdBuffer = extractor->getCSDSample(info, idx);
-            if (!csdBuffer || !info.size) break;
-
-            // copy the meta data and buffer to be passed to decoder
-            if (inputBufferOffset + info.size > kMaxBufferSize) {
-                cout << "[   WARN   ] Test Skipped. Memory allocated not sufficient\n";
-                free(inputBuffer);
-                return;
-            }
-            memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
-            frameInfo.push_back(info);
-            inputBufferOffset += info.size;
-            idx++;
-        }
 
         // Get frame data
         while (1) {
@@ -189,6 +171,7 @@
         ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", false),
                           make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
                           make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
+                          make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
                           make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
 
 INSTANTIATE_TEST_SUITE_P(
@@ -196,6 +179,7 @@
         ::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", true),
                           make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
                           make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
+                          make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
                           make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
 
 INSTANTIATE_TEST_SUITE_P(VideEncoderSyncTest, EncoderTest,
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index c0967d9..8a9039c 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -48,6 +48,7 @@
 
     header_libs: [
         "bionic_libc_platform_headers",
+        "libmedia_headers",
     ],
 
     local_include_dirs: ["include"],
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 990f318..971ae9f 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.
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index e1089d5..2595761 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;
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 65261da..9d80425 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -381,7 +381,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
@@ -396,7 +396,7 @@
             sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
             uint32_t supportedDevices;
             if (dev->getSupportedDevices(&supportedDevices) == OK &&
-                    (supportedDevices & devices) == devices) {
+                    (supportedDevices & deviceType) == deviceType) {
                 return audioHwDevice;
             }
         }
@@ -1573,7 +1573,7 @@
     proposed.format = format;
 
     sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
-    size_t frames;
+    size_t frames = 0;
     for (;;) {
         // Note: config is currently a const parameter for get_input_buffer_size()
         // but we use a copy from proposed in case config changes from the call.
@@ -2304,13 +2304,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;
     }
@@ -2351,7 +2351,7 @@
     status_t status = outHwDev->openOutputStream(
             &outputStream,
             *output,
-            devices,
+            deviceType,
             flags,
             config,
             address.string());
@@ -2362,7 +2362,7 @@
         if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
             sp<MmapPlaybackThread> thread =
                     new MmapPlaybackThread(this, *output, outHwDev, outputStream,
-                                          devices, AUDIO_DEVICE_NONE, mSystemReady);
+                                           deviceType, AUDIO_DEVICE_NONE, mSystemReady);
             mMmapThreads.add(*output, thread);
             ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
                   *output, thread.get());
@@ -2370,17 +2370,18 @@
         } 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, deviceType, 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, deviceType, 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, deviceType, mSystemReady);
                 ALOGV("openOutput_l() created mixer output: ID %d thread %p",
                       *output, thread.get());
             }
@@ -2396,27 +2397,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();
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index bbf8a29..65be06d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -67,11 +67,11 @@
 #include <media/AudioBufferProvider.h>
 #include <media/AudioMixer.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>
 
@@ -175,8 +175,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);
 
@@ -372,7 +371,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 +677,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);
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/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/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 41a71d5..23c2209 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1898,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",
@@ -1906,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
@@ -2071,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 35126ad..82bc6ac 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 {
@@ -296,8 +298,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/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index c3a02f9..7c8ce83 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -22,6 +22,8 @@
 #include <utils/Log.h>
 #include <math.h>
 
+#include "policy.h"
+
 namespace android {
 
 /**
@@ -85,43 +87,14 @@
      */
     static audio_devices_t getDeviceForVolume(const android::DeviceTypeSet& deviceTypes)
     {
-        audio_devices_t deviceType = 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.
-            deviceType = AUDIO_DEVICE_OUT_SPEAKER;
-        } else if (deviceTypes.size() > 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 (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER) != 0) {
-                deviceType = AUDIO_DEVICE_OUT_SPEAKER;
-            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPEAKER_SAFE) != 0) {
-                deviceType = AUDIO_DEVICE_OUT_SPEAKER_SAFE;
-            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_HDMI_ARC) != 0) {
-                deviceType = AUDIO_DEVICE_OUT_HDMI_ARC;
-            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_AUX_LINE) != 0) {
-                deviceType = AUDIO_DEVICE_OUT_AUX_LINE;
-            } else if (deviceTypes.count(AUDIO_DEVICE_OUT_SPDIF) != 0) {
-                deviceType = AUDIO_DEVICE_OUT_SPDIF;
-            } else {
-                std::vector<audio_devices_t> a2dpDevices = android::Intersection(
-                        deviceTypes, android::getAudioDeviceOutAllA2dpSet());
-                if (a2dpDevices.size() > 1) {
-                    ALOGW("getDeviceForVolume() invalid device combination: %s",
-                          android::dumpDeviceTypes(deviceTypes).c_str());
-                }
-                if (!a2dpDevices.empty()) {
-                    deviceType = a2dpDevices[0];
-                }
-            }
-        } else {
-            deviceType = *(deviceTypes.begin());
+            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 (deviceType == AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
             deviceType = AUDIO_DEVICE_OUT_SPEAKER;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 630efc1..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>;
@@ -199,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/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/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 158215d..7faf90e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -130,6 +130,14 @@
     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);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 4ff69ee..dd51658 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -467,8 +467,11 @@
                                        audio_io_handle_t *output)
 {
     mDevices = devices;
-    const String8& address = devices.getFirstValidAddress();
-    DeviceTypeSet deviceTypes = 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) {
@@ -500,25 +503,19 @@
     ALOGV("opening output for device %s profile %p name %s",
           mDevices.toString().c_str(), mProfile.get(), mProfile->getName().c_str());
 
-    // FIXME: Stop using device types as bit mask when the interface updated.
-    audio_devices_t deviceType = deviceTypesToBitMask(deviceTypes);
     status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
                                                    output,
                                                    &lConfig,
-                                                   &deviceType,
-                                                   address,
+                                                   device,
                                                    &mLatency,
                                                    mFlags);
-    deviceTypes = deviceTypesFromBitMask(deviceType);
-    LOG_ALWAYS_FATAL_IF(mDevices.types() != deviceTypes,
-                        "%s openOutput returned device %s when given device %s",
-                        __FUNCTION__, dumpDeviceTypes(mDevices.types()).c_str(),
-                        dumpDeviceTypes(deviceTypes).c_str());
 
     if (status == NO_ERROR) {
         LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
-                            "%s openOutput returned output handle %d for device %s",
-                            __FUNCTION__, *output, dumpDeviceTypes(deviceTypes).c_str());
+                            "%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;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 6f8ea36..20c0a24 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -455,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;
             }
@@ -522,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/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 4e8c01c..993c3a1 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -76,7 +76,7 @@
         return false;
     }
 
-    return (mDeviceType == other->mDeviceType) && (mAddress == other->mAddress) &&
+    return mDeviceTypeAddr.equals(other->mDeviceTypeAddr) &&
            checkEqual(mEncodedFormats, other->mEncodedFormats);
 }
 
@@ -135,7 +135,7 @@
 
 void DeviceDescriptor::toAudioPort(struct audio_port *port) const
 {
-    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceType);
+    ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
     DeviceDescriptorBase::toAudioPort(port);
     port->ext.device.hw_module = getModuleHandle();
 }
@@ -328,6 +328,24 @@
     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);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 72221a8..45b0ec7 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1093,8 +1093,9 @@
     }
 
     audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+        .channel_mask = config->channel_mask,
         .format = config->format,
-        .channel_mask = config->channel_mask };
+    };
     *portId = PolicyAudioPort::getNextUniqueId();
 
     sp<TrackClientDescriptor> clientDesc =
@@ -3057,13 +3058,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;
             }
         }
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 389f861..875f51d 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -377,8 +377,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 +390,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;
     }
@@ -494,7 +497,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;
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 7dfc205..c8d7d0c 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -422,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;
@@ -442,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()) {
@@ -473,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;
@@ -490,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
@@ -556,6 +565,14 @@
                     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->portId,
                       allowCapture ? apmStatFromAmState(mUidPolicy->getUidState(current->uid)) :
@@ -960,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);
     }
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 939df2c..17e0437 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -371,7 +371,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 +623,7 @@
         virtual status_t openOutput(audio_module_handle_t module,
                                     audio_io_handle_t *output,
                                     audio_config_t *config,
-                                    audio_devices_t *devices,
-                                    const String8& address,
+                                    const sp<DeviceDescriptorBase>& device,
                                     uint32_t *latencyMs,
                                     audio_output_flags_t flags);
         // creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index afe6f20..c2a92d7 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -34,8 +34,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 {
         if (module >= mNextModuleHandle) {
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/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a02178e..c10adbb 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2855,7 +2855,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);
@@ -3448,10 +3448,21 @@
         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, &deviceKind]
+    state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3]
             (const String8& cameraId, StatusInternal status) {
 
             if (status != StatusInternal::ENUMERATING) {
@@ -3473,9 +3484,11 @@
             Mutex::Autolock lock(mStatusListenerLock);
 
             for (auto& listener : mListenerList) {
-                if (shouldSkipStatusUpdates(deviceKind, listener->isVendorListener(),
-                        listener->getListenerPid(), listener->getListenerUid())) {
-                    ALOGV("Skipping camera discovery callback for system-only camera %s",
+                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;
                 }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8765fbf..829a3ee 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -574,7 +574,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);
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/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index d93d26f..08fb153 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -2032,6 +2032,15 @@
         }
     }
 
+    for (size_t i = 0; i < mCompositeStreamMap.size(); i++) {
+        auto ret = mCompositeStreamMap.valueAt(i)->deleteInternalStreams();
+        if (ret != OK) {
+            ALOGE("%s: Failed removing composite stream  %s (%d)", __FUNCTION__,
+                    strerror(-ret), ret);
+        }
+    }
+    mCompositeStreamMap.clear();
+
     Camera2ClientBase::detachDevice();
 }
 
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index e33bbad..bf4d1c8 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -31,7 +31,6 @@
 #include <mediadrm/ICrypto.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/MediaCodecConstants.h>
 
@@ -61,12 +60,13 @@
         mUseGrid(false),
         mAppSegmentStreamId(-1),
         mAppSegmentSurfaceId(-1),
-        mAppSegmentBufferAcquired(false),
         mMainImageStreamId(-1),
         mMainImageSurfaceId(-1),
         mYuvBufferAcquired(false),
         mProducerListener(new ProducerListener()),
-        mOutputBufferCounter(0),
+        mDequeuedOutputBufferCnt(0),
+        mLockedAppSegmentBufferCnt(0),
+        mCodecOutputCounter(0),
         mGridTimestampUs(0) {
 }
 
@@ -132,7 +132,7 @@
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
-    mAppSegmentConsumer = new CpuConsumer(consumer, 1);
+    mAppSegmentConsumer = new CpuConsumer(consumer, kMaxAcquiredAppSegment);
     mAppSegmentConsumer->setFrameAvailableListener(this);
     mAppSegmentConsumer->setName(String8("Camera3-HeicComposite-AppSegmentStream"));
     mAppSegmentSurface = new Surface(producer);
@@ -231,6 +231,8 @@
     if (bufferInfo.mError) return;
 
     mCodecOutputBufferTimestamps.push(bufferInfo.mTimestamp);
+    ALOGV("%s: [%" PRId64 "]: Adding codecOutputBufferTimestamp (%zu timestamps in total)",
+            __FUNCTION__, bufferInfo.mTimestamp, mCodecOutputBufferTimestamps.size());
 }
 
 // We need to get the settings early to handle the case where the codec output
@@ -361,6 +363,8 @@
             mCodecOutputBuffers.push_back(outputBufferInfo);
             mInputReadyCondition.signal();
         } else {
+            ALOGV("%s: Releasing output buffer: size %d flags: 0x%x ", __FUNCTION__,
+                outputBufferInfo.size, outputBufferInfo.flags);
             mCodec->releaseOutputBuffer(outputBufferInfo.index);
         }
     } else {
@@ -414,8 +418,10 @@
         mNumOutputTiles = 1;
     }
 
-    ALOGV("%s: mNumOutputTiles is %zu", __FUNCTION__, mNumOutputTiles);
     mFormat = newFormat;
+
+    ALOGV("%s: mNumOutputTiles is %zu", __FUNCTION__, mNumOutputTiles);
+    mInputReadyCondition.signal();
 }
 
 void HeicCompositeStream::onHeicCodecError() {
@@ -459,9 +465,8 @@
 
     // Cannot use SourceSurface buffer count since it could be codec's 512*512 tile
     // buffer count.
-    int maxProducerBuffers = 1;
     if ((res = native_window_set_buffer_count(
-                    anwConsumer, maxProducerBuffers + maxConsumerBuffers)) != OK) {
+                    anwConsumer, kMaxOutputSurfaceProducerCount + maxConsumerBuffers)) != OK) {
         ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mMainImageStreamId);
         return res;
     }
@@ -505,6 +510,8 @@
     }
 
     if (mSettingsByFrameNumber.find(resultExtras.frameNumber) != mSettingsByFrameNumber.end()) {
+        ALOGV("%s: [%" PRId64 "]: frameNumber %" PRId64, __FUNCTION__,
+                timestamp, resultExtras.frameNumber);
         mFrameNumberMap.emplace(resultExtras.frameNumber, timestamp);
         mSettingsByTimestamp[timestamp] = mSettingsByFrameNumber[resultExtras.frameNumber];
         mSettingsByFrameNumber.erase(resultExtras.frameNumber);
@@ -520,12 +527,12 @@
         mSettingsByTimestamp.erase(it);
     }
 
-    while (!mInputAppSegmentBuffers.empty() && !mAppSegmentBufferAcquired) {
+    while (!mInputAppSegmentBuffers.empty()) {
         CpuConsumer::LockedBuffer imgBuffer;
         auto it = mInputAppSegmentBuffers.begin();
         auto res = mAppSegmentConsumer->lockNextBuffer(&imgBuffer);
         if (res == NOT_ENOUGH_DATA) {
-            // Canot not lock any more buffers.
+            // Can not lock any more buffers.
             break;
         } else if ((res != OK) || (*it != imgBuffer.timestamp)) {
             if (res != OK) {
@@ -535,6 +542,7 @@
                 ALOGE("%s: Expecting JPEG_APP_SEGMENTS buffer with time stamp: %" PRId64
                         " received buffer with time stamp: %" PRId64, __FUNCTION__,
                         *it, imgBuffer.timestamp);
+                mAppSegmentConsumer->unlockBuffer(imgBuffer);
             }
             mPendingInputFrames[*it].error = true;
             mInputAppSegmentBuffers.erase(it);
@@ -546,7 +554,7 @@
             mAppSegmentConsumer->unlockBuffer(imgBuffer);
         } else {
             mPendingInputFrames[imgBuffer.timestamp].appSegmentBuffer = imgBuffer;
-            mAppSegmentBufferAcquired = true;
+            mLockedAppSegmentBufferCnt++;
         }
         mInputAppSegmentBuffers.erase(it);
     }
@@ -556,7 +564,7 @@
         auto it = mInputYuvBuffers.begin();
         auto res = mMainImageConsumer->lockNextBuffer(&imgBuffer);
         if (res == NOT_ENOUGH_DATA) {
-            // Canot not lock any more buffers.
+            // Can not lock any more buffers.
             break;
         } else if (res != OK) {
             ALOGE("%s: Error locking YUV_888 image buffer: %s (%d)", __FUNCTION__,
@@ -589,17 +597,20 @@
         // to look up timestamp.
         int64_t bufferTime = -1;
         if (mCodecOutputBufferTimestamps.empty()) {
-            ALOGE("%s: Failed to find buffer timestamp for codec output buffer!", __FUNCTION__);
+            ALOGV("%s: Failed to find buffer timestamp for codec output buffer!", __FUNCTION__);
+            break;
         } else {
             // Direct mapping between camera timestamp (in ns) and codec timestamp (in us).
             bufferTime = mCodecOutputBufferTimestamps.front();
-            mOutputBufferCounter++;
-            if (mOutputBufferCounter == mNumOutputTiles) {
+            mCodecOutputCounter++;
+            if (mCodecOutputCounter == mNumOutputTiles) {
                 mCodecOutputBufferTimestamps.pop();
-                mOutputBufferCounter = 0;
+                mCodecOutputCounter = 0;
             }
 
             mPendingInputFrames[bufferTime].codecOutputBuffers.push_back(*it);
+            ALOGV("%s: [%" PRId64 "]: Pushing codecOutputBuffers (time %" PRId64 " us)",
+                    __FUNCTION__, bufferTime, it->timeUs);
         }
         mCodecOutputBuffers.erase(it);
     }
@@ -607,6 +618,7 @@
     while (!mFrameNumberMap.empty()) {
         auto it = mFrameNumberMap.begin();
         mPendingInputFrames[it->second].frameNumber = it->first;
+        ALOGV("%s: [%" PRId64 "]: frameNumber is %" PRId64, __FUNCTION__, it->second, it->first);
         mFrameNumberMap.erase(it);
     }
 
@@ -675,16 +687,29 @@
     }
 
     bool newInputAvailable = false;
-    for (const auto& it : mPendingInputFrames) {
+    for (auto& it : mPendingInputFrames) {
+        // New input is considered to be available only if:
+        // 1. input buffers are ready, or
+        // 2. App segment and muxer is created, or
+        // 3. A codec output tile is ready, and an output buffer is available.
+        // This makes sure that muxer gets created only when an output tile is
+        // generated, because right now we only handle 1 HEIC output buffer at a
+        // time (max dequeued buffer count is 1).
         bool appSegmentReady = (it.second.appSegmentBuffer.data != nullptr) &&
-                !it.second.appSegmentWritten && it.second.result != nullptr;
+                !it.second.appSegmentWritten && it.second.result != nullptr &&
+                it.second.muxer != nullptr;
         bool codecOutputReady = !it.second.codecOutputBuffers.empty();
         bool codecInputReady = (it.second.yuvBuffer.data != nullptr) &&
                 (!it.second.codecInputBuffers.empty());
+        bool hasOutputBuffer = it.second.muxer != nullptr ||
+                (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
         if ((!it.second.error) &&
                 (it.first < *currentTs) &&
-                (appSegmentReady || codecOutputReady || codecInputReady)) {
+                (appSegmentReady || (codecOutputReady && hasOutputBuffer) || codecInputReady)) {
             *currentTs = it.first;
+            if (it.second.format == nullptr && mFormat != nullptr) {
+                it.second.format = mFormat->dup();
+            }
             newInputAvailable = true;
             break;
         }
@@ -716,15 +741,17 @@
     status_t res = OK;
 
     bool appSegmentReady = inputFrame.appSegmentBuffer.data != nullptr &&
-            !inputFrame.appSegmentWritten && inputFrame.result != nullptr;
+            !inputFrame.appSegmentWritten && inputFrame.result != nullptr &&
+            inputFrame.muxer != nullptr;
     bool codecOutputReady = inputFrame.codecOutputBuffers.size() > 0;
     bool codecInputReady = inputFrame.yuvBuffer.data != nullptr &&
-           !inputFrame.codecInputBuffers.empty();
+            !inputFrame.codecInputBuffers.empty();
+    bool hasOutputBuffer = inputFrame.muxer != nullptr ||
+            (mDequeuedOutputBufferCnt < kMaxOutputSurfaceProducerCount);
 
-    if (!appSegmentReady && !codecOutputReady && !codecInputReady) {
-        ALOGW("%s: No valid appSegmentBuffer/codec input/outputBuffer available!", __FUNCTION__);
-        return OK;
-    }
+    ALOGV("%s: [%" PRId64 "]: appSegmentReady %d, codecOutputReady %d, codecInputReady %d,"
+            " dequeuedOutputBuffer %d", __FUNCTION__, timestamp, appSegmentReady,
+            codecOutputReady, codecInputReady, mDequeuedOutputBufferCnt);
 
     // Handle inputs for Hevc tiling
     if (codecInputReady) {
@@ -736,7 +763,13 @@
         }
     }
 
-    // Initialize and start muxer if not yet done so
+    if (!(codecOutputReady && hasOutputBuffer) && !appSegmentReady) {
+        return OK;
+    }
+
+    // Initialize and start muxer if not yet done so. In this case,
+    // codecOutputReady must be true. Otherwise, appSegmentReady is guaranteed
+    // to be false, and the function must have returned early.
     if (inputFrame.muxer == nullptr) {
         res = startMuxerForInputFrame(timestamp, inputFrame);
         if (res != OK) {
@@ -747,7 +780,7 @@
     }
 
     // Write JPEG APP segments data to the muxer.
-    if (appSegmentReady && inputFrame.muxer != nullptr) {
+    if (appSegmentReady) {
         res = processAppSegment(timestamp, inputFrame);
         if (res != OK) {
             ALOGE("%s: Failed to process JPEG APP segments: %s (%d)", __FUNCTION__,
@@ -766,12 +799,18 @@
         }
     }
 
-    if (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0) {
-        res = processCompletedInputFrame(timestamp, inputFrame);
-        if (res != OK) {
-            ALOGE("%s: Failed to process completed input frame: %s (%d)", __FUNCTION__,
-                    strerror(-res), res);
-            return res;
+    if (inputFrame.pendingOutputTiles == 0) {
+        if (inputFrame.appSegmentWritten) {
+            res = processCompletedInputFrame(timestamp, inputFrame);
+            if (res != OK) {
+                ALOGE("%s: Failed to process completed input frame: %s (%d)", __FUNCTION__,
+                        strerror(-res), res);
+                return res;
+            }
+        } else if (mLockedAppSegmentBufferCnt == kMaxAcquiredAppSegment) {
+            ALOGE("%s: Out-of-order app segment buffers reaches limit %u", __FUNCTION__,
+                    kMaxAcquiredAppSegment);
+            return INVALID_OPERATION;
         }
     }
 
@@ -780,11 +819,6 @@
 
 status_t HeicCompositeStream::startMuxerForInputFrame(nsecs_t timestamp, InputFrame &inputFrame) {
     sp<ANativeWindow> outputANW = mOutputSurface;
-    if (inputFrame.codecOutputBuffers.size() == 0) {
-        // No single codec output buffer has been generated. Continue to
-        // wait.
-        return OK;
-    }
 
     auto res = outputANW->dequeueBuffer(mOutputSurface.get(), &inputFrame.anb, &inputFrame.fenceFd);
     if (res != OK) {
@@ -792,6 +826,7 @@
                 res);
         return res;
     }
+    mDequeuedOutputBufferCnt++;
 
     // Combine current thread id, stream id and timestamp to uniquely identify image.
     std::ostringstream tempOutputFile;
@@ -828,7 +863,7 @@
         }
     }
 
-    ssize_t trackId = inputFrame.muxer->addTrack(mFormat);
+    ssize_t trackId = inputFrame.muxer->addTrack(inputFrame.format);
     if (trackId < 0) {
         ALOGE("%s: Failed to addTrack to the muxer: %zd", __FUNCTION__, trackId);
         return NO_INIT;
@@ -844,6 +879,8 @@
         return res;
     }
 
+    ALOGV("%s: [%" PRId64 "]: Muxer started for inputFrame", __FUNCTION__,
+            timestamp);
     return OK;
 }
 
@@ -852,9 +889,6 @@
     auto appSegmentSize = findAppSegmentsSize(inputFrame.appSegmentBuffer.data,
             inputFrame.appSegmentBuffer.width * inputFrame.appSegmentBuffer.height,
             &app1Size);
-    ALOGV("%s: appSegmentSize is %zu, width %d, height %d, app1Size %zu", __FUNCTION__,
-          appSegmentSize, inputFrame.appSegmentBuffer.width,
-          inputFrame.appSegmentBuffer.height, app1Size);
     if (appSegmentSize == 0) {
         ALOGE("%s: Failed to find JPEG APP segment size", __FUNCTION__);
         return NO_INIT;
@@ -910,7 +944,16 @@
                 __FUNCTION__, strerror(-res), res);
         return res;
     }
+
+    ALOGV("%s: [%" PRId64 "]: appSegmentSize is %zu, width %d, height %d, app1Size %zu",
+          __FUNCTION__, timestamp, appSegmentSize, inputFrame.appSegmentBuffer.width,
+          inputFrame.appSegmentBuffer.height, app1Size);
+
     inputFrame.appSegmentWritten = true;
+    // Release the buffer now so any pending input app segments can be processed
+    mAppSegmentConsumer->unlockBuffer(inputFrame.appSegmentBuffer);
+    inputFrame.appSegmentBuffer.data = nullptr;
+    mLockedAppSegmentBufferCnt--;
 
     return OK;
 }
@@ -934,8 +977,9 @@
                 mOutputWidth - tileX * mGridWidth : mGridWidth;
         size_t height = (tileY == static_cast<size_t>(mGridRows) - 1) ?
                 mOutputHeight - tileY * mGridHeight : mGridHeight;
-        ALOGV("%s: inputBuffer tileIndex [%zu, %zu], top %zu, left %zu, width %zu, height %zu",
-                __FUNCTION__, tileX, tileY, top, left, width, height);
+        ALOGV("%s: inputBuffer tileIndex [%zu, %zu], top %zu, left %zu, width %zu, height %zu,"
+                " timeUs %" PRId64, __FUNCTION__, tileX, tileY, top, left, width, height,
+                inputBuffer.timeUs);
 
         res = copyOneYuvTile(buffer, inputFrame.yuvBuffer, top, left, width, height);
         if (res != OK) {
@@ -990,6 +1034,9 @@
     }
 
     inputFrame.codecOutputBuffers.erase(inputFrame.codecOutputBuffers.begin());
+
+    ALOGV("%s: [%" PRId64 "]: Output buffer index %d",
+        __FUNCTION__, timestamp, it->index);
     return OK;
 }
 
@@ -1046,7 +1093,9 @@
         return res;
     }
     inputFrame.anb = nullptr;
+    mDequeuedOutputBufferCnt--;
 
+    ALOGV("%s: [%" PRId64 "]", __FUNCTION__, timestamp);
     ATRACE_ASYNC_END("HEIC capture", inputFrame.frameNumber);
     return OK;
 }
@@ -1060,7 +1109,6 @@
     if (inputFrame->appSegmentBuffer.data != nullptr) {
         mAppSegmentConsumer->unlockBuffer(inputFrame->appSegmentBuffer);
         inputFrame->appSegmentBuffer.data = nullptr;
-        mAppSegmentBufferAcquired = false;
     }
 
     while (!inputFrame->codecOutputBuffers.empty()) {
@@ -1098,11 +1146,13 @@
     }
 }
 
-void HeicCompositeStream::releaseInputFramesLocked(int64_t currentTs) {
+void HeicCompositeStream::releaseInputFramesLocked() {
     auto it = mPendingInputFrames.begin();
     while (it != mPendingInputFrames.end()) {
-        if (it->first <= currentTs) {
-            releaseInputFrameLocked(&it->second);
+        auto& inputFrame = it->second;
+        if (inputFrame.error ||
+            (inputFrame.appSegmentWritten && inputFrame.pendingOutputTiles == 0)) {
+            releaseInputFrameLocked(&inputFrame);
             it = mPendingInputFrames.erase(it);
         } else {
             it++;
@@ -1506,7 +1556,7 @@
             // In case we landed in error state, return any pending buffers and
             // halt all further processing.
             compilePendingInputLocked();
-            releaseInputFramesLocked(currentTs);
+            releaseInputFramesLocked();
             return false;
         }
 
@@ -1548,11 +1598,7 @@
         mPendingInputFrames[currentTs].error = true;
     }
 
-    if (mPendingInputFrames[currentTs].error ||
-            (mPendingInputFrames[currentTs].appSegmentWritten &&
-            mPendingInputFrames[currentTs].pendingOutputTiles == 0)) {
-        releaseInputFramesLocked(currentTs);
-    }
+    releaseInputFramesLocked();
 
     return true;
 }
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index 260c68e..04e7b83 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -25,6 +25,7 @@
 #include <media/hardware/VideoAPI.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaMuxer.h>
 
@@ -157,6 +158,7 @@
         bool                      errorNotified;
         int64_t                   frameNumber;
 
+        sp<AMessage>              format;
         sp<MediaMuxer>            muxer;
         int                       fenceFd;
         int                       fileFd;
@@ -187,7 +189,7 @@
     status_t processCompletedInputFrame(nsecs_t timestamp, InputFrame &inputFrame);
 
     void releaseInputFrameLocked(InputFrame *inputFrame /*out*/);
-    void releaseInputFramesLocked(int64_t currentTs);
+    void releaseInputFramesLocked();
 
     size_t findAppSegmentsSize(const uint8_t* appSegmentBuffer, size_t maxSize,
             size_t* app1SegmentSize);
@@ -205,11 +207,13 @@
             static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS);
     static const android_dataspace kHeifDataSpace =
             static_cast<android_dataspace>(HAL_DATASPACE_HEIF);
+    // Use the limit of pipeline depth in the API sepc as maximum number of acquired
+    // app segment buffers.
+    static const uint32_t kMaxAcquiredAppSegment = 8;
 
     int               mAppSegmentStreamId, mAppSegmentSurfaceId;
     sp<CpuConsumer>   mAppSegmentConsumer;
     sp<Surface>       mAppSegmentSurface;
-    bool              mAppSegmentBufferAcquired;
     size_t            mAppSegmentMaxSize;
     CameraMetadata    mStaticInfo;
 
@@ -218,9 +222,10 @@
     sp<CpuConsumer>   mMainImageConsumer; // Only applicable for HEVC codec.
     bool              mYuvBufferAcquired; // Only applicable to HEVC codec
 
+    static const int32_t kMaxOutputSurfaceProducerCount = 1;
     sp<Surface>       mOutputSurface;
     sp<ProducerListener> mProducerListener;
-
+    int32_t           mDequeuedOutputBufferCnt;
 
     // Map from frame number to JPEG setting of orientation+quality
     std::map<int64_t, std::pair<int32_t, int32_t>> mSettingsByFrameNumber;
@@ -229,11 +234,12 @@
 
     // Keep all incoming APP segment Blob buffer pending further processing.
     std::vector<int64_t> mInputAppSegmentBuffers;
+    int32_t           mLockedAppSegmentBufferCnt;
 
     // Keep all incoming HEIC blob buffer pending further processing.
     std::vector<CodecOutputBufferInfo> mCodecOutputBuffers;
     std::queue<int64_t> mCodecOutputBufferTimestamps;
-    size_t mOutputBufferCounter;
+    size_t mCodecOutputCounter;
 
     // Keep all incoming Yuv buffer pending tiling and encoding (for HEVC YUV tiling only)
     std::vector<int64_t> mInputYuvBuffers;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 608521a..7ed4c3d 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1187,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__,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 4112711..2ef1f6f 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -96,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;
@@ -112,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);
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 74cfe42..1daa035 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -191,6 +191,14 @@
       _hidl_cb(status, {});
       return Void();
     }
+    cameraStatusAndIds.erase(std::remove_if(cameraStatusAndIds.begin(), cameraStatusAndIds.end(),
+            [this](const hardware::CameraStatus& s) {
+              bool supportsHAL3 = false;
+              binder::Status sRet =
+                            mAidlICameraService->supportsCameraApi(String16(s.cameraId),
+                                    hardware::ICameraService::API_VERSION_2, &supportsHAL3);
+              return !sRet.isOk() || !supportsHAL3;
+            }), cameraStatusAndIds.end());
     hidl_vec<HCameraStatusAndId> hCameraStatusAndIds;
     //Convert cameraStatusAndIds to HIDL and call callback
     convertToHidl(cameraStatusAndIds, &hCameraStatusAndIds);
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 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 988c06b..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,193 +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_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);
-            }
-            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) {
@@ -305,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) {
@@ -313,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 #");
@@ -325,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());
@@ -357,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
             }
         }
     }
@@ -633,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/iface_statsd.cpp b/services/mediaanalytics/iface_statsd.cpp
index 6fd4415..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 },
@@ -68,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;
@@ -81,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/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_audiopolicy.cpp b/services/mediaanalytics/statsd_audiopolicy.cpp
index 06c4dde..95cb274 100644
--- a/services/mediaanalytics/statsd_audiopolicy.cpp
+++ b/services/mediaanalytics/statsd_audiopolicy.cpp
@@ -60,14 +60,14 @@
         metrics_proto.set_status(status);
     }
     //string char kAudioPolicyRqstSrc[] = "android.media.audiopolicy.rqst.src";
-    char *rqst_src = NULL;
-    if (item->getCString("android.media.audiopolicy.rqst.src", &rqst_src)) {
-        metrics_proto.set_request_source(rqst_src);
+    std::string rqst_src;
+    if (item->getString("android.media.audiopolicy.rqst.src", &rqst_src)) {
+        metrics_proto.set_request_source(std::move(rqst_src));
     }
     //string char kAudioPolicyRqstPkg[] = "android.media.audiopolicy.rqst.pkg";
-    char *rqst_pkg = NULL;
-    if (item->getCString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
-        metrics_proto.set_request_package(rqst_pkg);
+    std::string rqst_pkg;
+    if (item->getString("android.media.audiopolicy.rqst.pkg", &rqst_pkg)) {
+        metrics_proto.set_request_package(std::move(rqst_pkg));
     }
     //int32 char kAudioPolicyRqstSession[] = "android.media.audiopolicy.rqst.session";
     int32_t rqst_session = -1;
@@ -75,20 +75,20 @@
         metrics_proto.set_request_session(rqst_session);
     }
     //string char kAudioPolicyRqstDevice[] = "android.media.audiopolicy.rqst.device";
-    char *rqst_device = NULL;
-    if (item->getCString("android.media.audiopolicy.rqst.device", &rqst_device)) {
-        metrics_proto.set_request_device(rqst_device);
+    std::string rqst_device;
+    if (item->getString("android.media.audiopolicy.rqst.device", &rqst_device)) {
+        metrics_proto.set_request_device(std::move(rqst_device));
     }
 
     //string char kAudioPolicyActiveSrc[] = "android.media.audiopolicy.active.src";
-    char *active_src = NULL;
-    if (item->getCString("android.media.audiopolicy.active.src", &active_src)) {
-        metrics_proto.set_active_source(active_src);
+    std::string active_src;
+    if (item->getString("android.media.audiopolicy.active.src", &active_src)) {
+        metrics_proto.set_active_source(std::move(active_src));
     }
     //string char kAudioPolicyActivePkg[] = "android.media.audiopolicy.active.pkg";
-    char *active_pkg = NULL;
-    if (item->getCString("android.media.audiopolicy.active.pkg", &active_pkg)) {
-        metrics_proto.set_active_package(active_pkg);
+    std::string active_pkg;
+    if (item->getString("android.media.audiopolicy.active.pkg", &active_pkg)) {
+        metrics_proto.set_active_package(std::move(active_pkg));
     }
     //int32 char kAudioPolicyActiveSession[] = "android.media.audiopolicy.active.session";
     int32_t active_session = -1;
@@ -96,9 +96,9 @@
         metrics_proto.set_active_session(active_session);
     }
     //string char kAudioPolicyActiveDevice[] = "android.media.audiopolicy.active.device";
-    char *active_device = NULL;
-    if (item->getCString("android.media.audiopolicy.active.device", &active_device)) {
-        metrics_proto.set_active_device(active_device);
+    std::string active_device;
+    if (item->getString("android.media.audiopolicy.active.device", &active_device)) {
+        metrics_proto.set_active_device(std::move(active_device));
     }
 
 
@@ -119,14 +119,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(rqst_src);
-    free(rqst_pkg);
-    free(rqst_device);
-    free(active_src);
-    free(active_pkg);
-    free(active_device);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_audiorecord.cpp b/services/mediaanalytics/statsd_audiorecord.cpp
index c9edb27..7c7a62c 100644
--- a/services/mediaanalytics/statsd_audiorecord.cpp
+++ b/services/mediaanalytics/statsd_audiorecord.cpp
@@ -54,14 +54,14 @@
 
     // flesh out the protobuf we'll hand off with our data
     //
-    char *encoding = NULL;
-    if (item->getCString("android.media.audiorecord.encoding", &encoding)) {
-        metrics_proto.set_encoding(encoding);
+    std::string encoding;
+    if (item->getString("android.media.audiorecord.encoding", &encoding)) {
+        metrics_proto.set_encoding(std::move(encoding));
     }
 
-    char *source = NULL;
-    if (item->getCString("android.media.audiorecord.source", &source)) {
-        metrics_proto.set_source(source);
+    std::string source;
+    if (item->getString("android.media.audiorecord.source", &source)) {
+        metrics_proto.set_source(std::move(source));
     }
 
     int32_t latency = -1;
@@ -101,11 +101,11 @@
         metrics_proto.set_error_code(errcode);
     }
 
-    char *errfunc = NULL;
-    if (item->getCString("android.media.audiorecord.errfunc", &errfunc)) {
-        metrics_proto.set_error_function(errfunc);
-    } else if (item->getCString("android.media.audiorecord.lastError.at", &errfunc)) {
-        metrics_proto.set_error_function(errfunc);
+    std::string errfunc;
+    if (item->getString("android.media.audiorecord.errfunc", &errfunc)) {
+        metrics_proto.set_error_function(std::move(errfunc));
+    } else if (item->getString("android.media.audiorecord.lastError.at", &errfunc)) {
+        metrics_proto.set_error_function(std::move(errfunc));
     }
 
     // portId (int32)
@@ -119,9 +119,9 @@
         metrics_proto.set_frame_count(frameCount);
     }
     // attributes (string)
-    char *attributes = NULL;
-    if (item->getCString("android.media.audiorecord.attributes", &attributes)) {
-        metrics_proto.set_attributes(attributes);
+    std::string attributes;
+    if (item->getString("android.media.audiorecord.attributes", &attributes)) {
+        metrics_proto.set_attributes(std::move(attributes));
     }
     // channelMask (int64)
     int64_t channelMask = -1;
@@ -152,12 +152,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(encoding);
-    free(source);
-    free(errfunc);
-    free(attributes);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_audiothread.cpp b/services/mediaanalytics/statsd_audiothread.cpp
index 8232424..e9d6b17 100644
--- a/services/mediaanalytics/statsd_audiothread.cpp
+++ b/services/mediaanalytics/statsd_audiothread.cpp
@@ -56,9 +56,9 @@
 
     // flesh out the protobuf we'll hand off with our data
     //
-    char *mytype = NULL;
-    if (item->getCString(MM_PREFIX "type", &mytype)) {
-        metrics_proto.set_type(mytype);
+    std::string mytype;
+    if (item->getString(MM_PREFIX "type", &mytype)) {
+        metrics_proto.set_type(std::move(mytype));
     }
     int32_t framecount = -1;
     if (item->getInt32(MM_PREFIX "framecount", &framecount)) {
@@ -68,17 +68,17 @@
     if (item->getInt32(MM_PREFIX "samplerate", &samplerate)) {
         metrics_proto.set_samplerate(samplerate);
     }
-    char *workhist = NULL;
-    if (item->getCString(MM_PREFIX "workMs.hist", &workhist)) {
-        metrics_proto.set_work_millis_hist(workhist);
+    std::string workhist;
+    if (item->getString(MM_PREFIX "workMs.hist", &workhist)) {
+        metrics_proto.set_work_millis_hist(std::move(workhist));
     }
-    char *latencyhist = NULL;
-    if (item->getCString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
-        metrics_proto.set_latency_millis_hist(latencyhist);
+    std::string latencyhist;
+    if (item->getString(MM_PREFIX "latencyMs.hist", &latencyhist)) {
+        metrics_proto.set_latency_millis_hist(std::move(latencyhist));
     }
-    char *warmuphist = NULL;
-    if (item->getCString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
-        metrics_proto.set_warmup_millis_hist(warmuphist);
+    std::string warmuphist;
+    if (item->getString(MM_PREFIX "warmupMs.hist", &warmuphist)) {
+        metrics_proto.set_warmup_millis_hist(std::move(warmuphist));
     }
     int64_t underruns = -1;
     if (item->getInt64(MM_PREFIX "underruns", &underruns)) {
@@ -108,9 +108,9 @@
         metrics_proto.set_port_id(port_id);
     }
     // item->setCString(MM_PREFIX "type", threadTypeToString(mType));
-    char *type = NULL;
-    if (item->getCString(MM_PREFIX "type", &type)) {
-        metrics_proto.set_type(type);
+    std::string type;
+    if (item->getString(MM_PREFIX "type", &type)) {
+        metrics_proto.set_type(std::move(type));
     }
     // item->setInt32(MM_PREFIX "sampleRate", (int32_t)mSampleRate);
     int32_t sample_rate = -1;
@@ -123,9 +123,9 @@
         metrics_proto.set_channel_mask(channel_mask);
     }
     // item->setCString(MM_PREFIX "encoding", toString(mFormat).c_str());
-    char *encoding = NULL;
-    if (item->getCString(MM_PREFIX "encoding", &encoding)) {
-        metrics_proto.set_encoding(encoding);
+    std::string encoding;
+    if (item->getString(MM_PREFIX "encoding", &encoding)) {
+        metrics_proto.set_encoding(std::move(encoding));
     }
     // item->setInt32(MM_PREFIX "frameCount", (int32_t)mFrameCount);
     int32_t frame_count = -1;
@@ -133,14 +133,14 @@
         metrics_proto.set_frame_count(frame_count);
     }
     // item->setCString(MM_PREFIX "outDevice", toString(mOutDevice).c_str());
-    char *outDevice = NULL;
-    if (item->getCString(MM_PREFIX "outDevice", &outDevice)) {
-        metrics_proto.set_output_device(outDevice);
+    std::string outDevice;
+    if (item->getString(MM_PREFIX "outDevice", &outDevice)) {
+        metrics_proto.set_output_device(std::move(outDevice));
     }
     // item->setCString(MM_PREFIX "inDevice", toString(mInDevice).c_str());
-    char *inDevice = NULL;
-    if (item->getCString(MM_PREFIX "inDevice", &inDevice)) {
-        metrics_proto.set_input_device(inDevice);
+    std::string inDevice;
+    if (item->getString(MM_PREFIX "inDevice", &inDevice)) {
+        metrics_proto.set_input_device(std::move(inDevice));
     }
     // item->setDouble(MM_PREFIX "ioJitterMs.mean", mIoJitterMs.getMean());
     double iojitters_ms_mean = -1;
@@ -201,16 +201,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(mytype);
-    free(workhist);
-    free(latencyhist);
-    free(warmuphist);
-    free(type);
-    free(encoding);
-    free(inDevice);
-    free(outDevice);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_audiotrack.cpp b/services/mediaanalytics/statsd_audiotrack.cpp
index f250ced..57cda99 100644
--- a/services/mediaanalytics/statsd_audiotrack.cpp
+++ b/services/mediaanalytics/statsd_audiotrack.cpp
@@ -57,23 +57,23 @@
 
     // static constexpr char kAudioTrackStreamType[] = "android.media.audiotrack.streamtype";
     // optional string streamType;
-    char *streamtype = NULL;
-    if (item->getCString("android.media.audiotrack.streamtype", &streamtype)) {
-        metrics_proto.set_stream_type(streamtype);
+    std::string streamtype;
+    if (item->getString("android.media.audiotrack.streamtype", &streamtype)) {
+        metrics_proto.set_stream_type(std::move(streamtype));
     }
 
     // static constexpr char kAudioTrackContentType[] = "android.media.audiotrack.type";
     // optional string contentType;
-    char *contenttype = NULL;
-    if (item->getCString("android.media.audiotrack.type", &contenttype)) {
-        metrics_proto.set_content_type(contenttype);
+    std::string contenttype;
+    if (item->getString("android.media.audiotrack.type", &contenttype)) {
+        metrics_proto.set_content_type(std::move(contenttype));
     }
 
     // static constexpr char kAudioTrackUsage[] = "android.media.audiotrack.usage";
     // optional string trackUsage;
-    char *trackusage = NULL;
-    if (item->getCString("android.media.audiotrack.usage", &trackusage)) {
-        metrics_proto.set_track_usage(trackusage);
+    std::string trackusage;
+    if (item->getString("android.media.audiotrack.usage", &trackusage)) {
+        metrics_proto.set_track_usage(std::move(trackusage));
     }
 
     // static constexpr char kAudioTrackSampleRate[] = "android.media.audiotrack.samplerate";
@@ -111,9 +111,9 @@
         metrics_proto.set_port_id(port_id);
     }
     // encoding (string)
-    char *encoding = NULL;
-    if (item->getCString("android.media.audiotrack.encoding", &encoding)) {
-        metrics_proto.set_encoding(encoding);
+    std::string encoding;
+    if (item->getString("android.media.audiotrack.encoding", &encoding)) {
+        metrics_proto.set_encoding(std::move(encoding));
     }
     // frameCount (int32)
     int32_t frame_count = -1;
@@ -121,9 +121,9 @@
         metrics_proto.set_frame_count(frame_count);
     }
     // attributes (string)
-    char *attributes = NULL;
-    if (item->getCString("android.media.audiotrack.attributes", &attributes)) {
-        metrics_proto.set_attributes(attributes);
+    std::string attributes;
+    if (item->getString("android.media.audiotrack.attributes", &attributes)) {
+        metrics_proto.set_attributes(std::move(attributes));
     }
 
     std::string serialized;
@@ -143,13 +143,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(streamtype);
-    free(contenttype);
-    free(trackusage);
-    free(encoding);
-    free(attributes);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_codec.cpp b/services/mediaanalytics/statsd_codec.cpp
index dc8e4ef..bf82e50 100644
--- a/services/mediaanalytics/statsd_codec.cpp
+++ b/services/mediaanalytics/statsd_codec.cpp
@@ -55,19 +55,19 @@
     // flesh out the protobuf we'll hand off with our data
     //
     // android.media.mediacodec.codec   string
-    char *codec = NULL;
-    if (item->getCString("android.media.mediacodec.codec", &codec)) {
-        metrics_proto.set_codec(codec);
+    std::string codec;
+    if (item->getString("android.media.mediacodec.codec", &codec)) {
+        metrics_proto.set_codec(std::move(codec));
     }
     // android.media.mediacodec.mime    string
-    char *mime = NULL;
-    if (item->getCString("android.media.mediacodec.mime", &mime)) {
-        metrics_proto.set_mime(mime);
+    std::string mime;
+    if (item->getString("android.media.mediacodec.mime", &mime)) {
+        metrics_proto.set_mime(std::move(mime));
     }
     // android.media.mediacodec.mode    string
-    char *mode = NULL;
-    if ( item->getCString("android.media.mediacodec.mode", &mode)) {
-        metrics_proto.set_mode(mode);
+    std::string mode;
+    if ( item->getString("android.media.mediacodec.mode", &mode)) {
+        metrics_proto.set_mode(std::move(mode));
     }
     // android.media.mediacodec.encoder int32
     int32_t encoder = -1;
@@ -125,9 +125,9 @@
         metrics_proto.set_error_code(errcode);
     }
     // android.media.mediacodec.errstate        string
-    char *errstate = NULL;
-    if ( item->getCString("android.media.mediacodec.errstate", &errstate)) {
-        metrics_proto.set_error_state(errstate);
+    std::string errstate;
+    if ( item->getString("android.media.mediacodec.errstate", &errstate)) {
+        metrics_proto.set_error_state(std::move(errstate));
     }
     // android.media.mediacodec.latency.max  int64
     int64_t latency_max = -1;
@@ -173,12 +173,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(codec);
-    free(mime);
-    free(mode);
-    free(errstate);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_extractor.cpp b/services/mediaanalytics/statsd_extractor.cpp
index 395c912..d84930c 100644
--- a/services/mediaanalytics/statsd_extractor.cpp
+++ b/services/mediaanalytics/statsd_extractor.cpp
@@ -56,14 +56,14 @@
     //
 
     // android.media.mediaextractor.fmt         string
-    char *fmt = NULL;
-    if (item->getCString("android.media.mediaextractor.fmt", &fmt)) {
-        metrics_proto.set_format(fmt);
+    std::string fmt;
+    if (item->getString("android.media.mediaextractor.fmt", &fmt)) {
+        metrics_proto.set_format(std::move(fmt));
     }
     // android.media.mediaextractor.mime        string
-    char *mime = NULL;
-    if (item->getCString("android.media.mediaextractor.mime", &mime)) {
-        metrics_proto.set_mime(mime);
+    std::string mime;
+    if (item->getString("android.media.mediaextractor.mime", &mime)) {
+        metrics_proto.set_mime(std::move(mime));
     }
     // android.media.mediaextractor.ntrk        int32
     int32_t ntrk = -1;
@@ -88,10 +88,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(fmt);
-    free(mime);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_nuplayer.cpp b/services/mediaanalytics/statsd_nuplayer.cpp
index 5ec118a..e6e0f2c 100644
--- a/services/mediaanalytics/statsd_nuplayer.cpp
+++ b/services/mediaanalytics/statsd_nuplayer.cpp
@@ -62,13 +62,13 @@
     // differentiate between nuplayer and nuplayer2
     metrics_proto.set_whichplayer(item->getKey().c_str());
 
-    char *video_mime = NULL;
-    if (item->getCString("android.media.mediaplayer.video.mime", &video_mime)) {
-        metrics_proto.set_video_mime(video_mime);
+    std::string video_mime;
+    if (item->getString("android.media.mediaplayer.video.mime", &video_mime)) {
+        metrics_proto.set_video_mime(std::move(video_mime));
     }
-    char *video_codec = NULL;
-    if (item->getCString("android.media.mediaplayer.video.codec", &video_codec)) {
-        metrics_proto.set_video_codec(video_codec);
+    std::string video_codec;
+    if (item->getString("android.media.mediaplayer.video.codec", &video_codec)) {
+        metrics_proto.set_video_codec(std::move(video_codec));
     }
 
     int32_t width = -1;
@@ -97,13 +97,13 @@
         metrics_proto.set_framerate(fps);
     }
 
-    char *audio_mime = NULL;
-    if (item->getCString("android.media.mediaplayer.audio.mime", &audio_mime)) {
-        metrics_proto.set_audio_mime(audio_mime);
+    std::string audio_mime;
+    if (item->getString("android.media.mediaplayer.audio.mime", &audio_mime)) {
+        metrics_proto.set_audio_mime(std::move(audio_mime));
     }
-    char *audio_codec = NULL;
-    if (item->getCString("android.media.mediaplayer.audio.codec", &audio_codec)) {
-        metrics_proto.set_audio_codec(audio_codec);
+    std::string audio_codec;
+    if (item->getString("android.media.mediaplayer.audio.codec", &audio_codec)) {
+        metrics_proto.set_audio_codec(std::move(audio_codec));
     }
 
     int64_t duration_ms = -1;
@@ -123,14 +123,14 @@
     if (item->getInt32("android.media.mediaplayer.errcode", &error_code)) {
         metrics_proto.set_error_code(error_code);
     }
-    char *error_state = NULL;
-    if (item->getCString("android.media.mediaplayer.errstate", &error_state)) {
-        metrics_proto.set_error_state(error_state);
+    std::string error_state;
+    if (item->getString("android.media.mediaplayer.errstate", &error_state)) {
+        metrics_proto.set_error_state(std::move(error_state));
     }
 
-    char *data_source_type = NULL;
-    if (item->getCString("android.media.mediaplayer.dataSource", &data_source_type)) {
-        metrics_proto.set_data_source_type(data_source_type);
+    std::string data_source_type;
+    if (item->getString("android.media.mediaplayer.dataSource", &data_source_type)) {
+        metrics_proto.set_data_source_type(std::move(data_source_type));
     }
 
     int64_t rebufferingMs = -1;
@@ -164,14 +164,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(video_mime);
-    free(video_codec);
-    free(audio_mime);
-    free(audio_codec);
-    free(error_state);
-    free(data_source_type);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/statsd_recorder.cpp b/services/mediaanalytics/statsd_recorder.cpp
index 4d981b4..d286f00 100644
--- a/services/mediaanalytics/statsd_recorder.cpp
+++ b/services/mediaanalytics/statsd_recorder.cpp
@@ -56,14 +56,14 @@
     //
 
     // string kRecorderAudioMime = "android.media.mediarecorder.audio.mime";
-    char *audio_mime = NULL;
-    if (item->getCString("android.media.mediarecorder.audio.mime", &audio_mime)) {
-        metrics_proto.set_audio_mime(audio_mime);
+    std::string audio_mime;
+    if (item->getString("android.media.mediarecorder.audio.mime", &audio_mime)) {
+        metrics_proto.set_audio_mime(std::move(audio_mime));
     }
     // string kRecorderVideoMime = "android.media.mediarecorder.video.mime";
-    char *video_mime = NULL;
-    if (item->getCString("android.media.mediarecorder.video.mime", &video_mime)) {
-        metrics_proto.set_video_mime(video_mime);
+    std::string video_mime;
+    if (item->getString("android.media.mediarecorder.video.mime", &video_mime)) {
+        metrics_proto.set_video_mime(std::move(video_mime));
     }
     // int32 kRecorderVideoProfile = "android.media.mediarecorder.video-encoder-profile";
     int32_t videoProfile = -1;
@@ -183,10 +183,6 @@
         ALOGV("NOT sending: private data (len=%zu)", strlen(serialized.c_str()));
     }
 
-    // must free the strings that we were given
-    free(audio_mime);
-    free(video_mime);
-
     return true;
 }
 
diff --git a/services/mediaanalytics/tests/Android.bp b/services/mediaanalytics/tests/Android.bp
new file mode 100644
index 0000000..7bca1c4
--- /dev/null
+++ b/services/mediaanalytics/tests/Android.bp
@@ -0,0 +1,25 @@
+cc_test {
+    name: "mediametrics_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/mediadrm/Android.mk b/services/mediadrm/Android.mk
index 707a2aa..72d42ae 100644
--- a/services/mediadrm/Android.mk
+++ b/services/mediadrm/Android.mk
@@ -21,6 +21,7 @@
     main_mediadrmserver.cpp
 
 LOCAL_HEADER_LIBRARIES:= \
+    libmedia_headers \
     libmediadrm_headers
 
 LOCAL_SHARED_LIBRARIES:= \
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index ac6b771..6239fb2 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -55,7 +55,7 @@
 
 sp<IDataSource> MediaExtractorService::makeIDataSource(int fd, int64_t offset, int64_t length)
 {
-    sp<DataSource> source = DataSourceFactory::CreateFromFd(fd, offset, length);
+    sp<DataSource> source = DataSourceFactory::getInstance()->CreateFromFd(fd, offset, length);
     return CreateIDataSourceFromDataSource(source);
 }
 
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index bee5d25..74b63d5 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -6,6 +6,10 @@
         "MediaLogService.cpp",
     ],
 
+    header_libs: [
+        "libmedia_headers",
+    ],
+
     shared_libs: [
         "libaudioutils",
         "libbinder",
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 45eea0f..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,44 +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::mergeResources(
-        MediaResource& r1, const MediaResource& r2) {
-    if (r1.mType == MediaResource::kDrmSession) {
-        // This means we are using a session. Each session's mValue is initialized to UINT64_MAX.
-        // The oftener a session is used the lower it's mValue. During reclaim the session with
-        // the highest mValue/lowest usage would be closed.
-        r1.mValue -= (r1.mValue == 0 ? 0 : 1);
+        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.mValue += r2.mValue;
+        r1.value = INT64_MAX;
     }
 }
 
-void ResourceManagerService::addResource(
-        int pid,
-        int uid,
+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);
@@ -315,15 +325,26 @@
     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 &res = resources[i];
-        const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
+        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()) {
+            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 {
@@ -335,10 +356,12 @@
         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);
@@ -346,46 +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 &res = resources[i];
-        const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
+        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 > res.mValue) {
-                resource.mValue -= res.mValue;
+            MediaResourceParcel &resource = info.resources[resType];
+            if (resource.value > res.value) {
+                resource.value -= res.value;
             } else {
-                // drm sessions always take this branch because res.mValue is set
-                // to UINT64_MAX
                 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);
@@ -394,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];
@@ -417,45 +445,49 @@
     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 MediaResource *drmSession = 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::kDrmSession) {
+            } else if (type == MediaResource::Type::kDrmSession) {
                 drmSession = &resources[i];
             }
         }
@@ -463,27 +495,27 @@
         // 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 false;
+                return Status::ok();
             }
         }
 
@@ -501,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();
     }
 
     {
@@ -551,7 +586,7 @@
         }
     }
 
-    return false;
+    return Status::ok();
 }
 
 bool ResourceManagerService::getAllClients_l(
@@ -666,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;
                 }
             }
@@ -685,4 +720,5 @@
     return true;
 }
 
+} // namespace media
 } // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 44d0c28..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::tuple<MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>, 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,14 +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(MediaResource& r1, const MediaResource& r2);
+    void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
 
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
@@ -140,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 9e14151..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,13 @@
     }
 
 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 &res = resources1[i];
-            const auto resType = std::tuple(res.mType, res.mSubType, res.mId);
+            const auto resType = std::tuple(res.type, res.subType, res.id);
             r1[resType] = res;
         }
         return r1 == resources2;
@@ -183,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));
@@ -219,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;
@@ -256,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);
@@ -289,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;
@@ -305,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;
@@ -344,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);
     }
 
@@ -380,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
@@ -395,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 ###
         {
@@ -406,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 ###
@@ -428,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));
         }
 
 
@@ -447,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 ###
@@ -473,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 ###
@@ -497,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 ###
         {
@@ -525,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));
         }
 
 
@@ -547,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 ###
@@ -570,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
@@ -587,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));
 
@@ -596,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);
     }
 
@@ -606,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();
@@ -617,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;
@@ -626,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));
 
@@ -648,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());
@@ -659,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());
@@ -687,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());
@@ -698,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());
@@ -738,6 +817,10 @@
     testCombineResource();
 }
 
+TEST_F(ResourceManagerServiceTest, combineResourceNegative) {
+    testCombineResourceWithNegativeValues();
+}
+
 TEST_F(ResourceManagerServiceTest, removeResource) {
     testRemoveResource();
 }
@@ -779,4 +862,5 @@
     testCpusetBoost();
 }
 
+} // namespace media
 } // namespace android