Merge "Revert "Ignore config error if non-offloadable effect is on offload thread""
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 67003c1..51cef8c 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -33,6 +33,7 @@
  * Do not #include files that aren't part of the NDK.
  */
 #include <sys/cdefs.h>
+#include <stdbool.h>
 
 #include <android/native_window.h>
 #include "NdkCameraError.h"
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index c0eb5c1..b715b12 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -153,6 +153,11 @@
 } ACameraDevice_StateCallbacks;
 
 /**
+ * For backward compatiblity.
+ */
+typedef ACameraDevice_StateCallbacks ACameraDevice_stateCallbacks;
+
+/**
  * Close the connection and free this ACameraDevice synchronously. Access to the ACameraDevice
  * after calling this method will cause a crash.
  *
@@ -252,35 +257,6 @@
      */
     TEMPLATE_MANUAL = 6,
 
-    /**
-     * A template for selecting camera parameters that match TEMPLATE_PREVIEW as closely as
-     * possible while improving the camera output for motion tracking use cases.
-     *
-     * <p>This template is best used by applications that are frequently switching between motion
-     * tracking use cases and regular still capture use cases, to minimize the IQ changes
-     * when swapping use cases.</p>
-     *
-     * <p>This template is guaranteed to be supported on camera devices that support the
-     * {@link ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING} capability.</p>
-     *
-     * @see ACameraDevice_createCaptureRequest
-     */
-    TEMPLATE_MOTION_TRACKING_PREVIEW = 7,
-
-    /**
-     * A template for selecting camera parameters that maximize the quality of camera output for
-     * motion tracking use cases.
-     *
-     * <p>This template is best used by applications dedicated to motion tracking applications,
-     * which aren't concerned about fast switches between motion tracking and other use cases.</p>
-     *
-     * <p>This template is guaranteed to be supported on camera devices that support the
-     * {@link ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING} capability.</p>
-     *
-     * @see ACameraDevice_createCaptureRequest
-     */
-    TEMPLATE_MOTION_TRACKING_BEST = 8,
-
 } ACameraDevice_request_template;
 
 /**
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 588e96a..d88a7a5 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2453,9 +2453,6 @@
      *
      * <p>Different calibration methods and use cases can produce better or worse results
      * depending on the selected coordinate origin.</p>
-     * <p>For devices designed to support the MOTION_TRACKING capability, the GYROSCOPE origin
-     * makes device calibration and later usage by applications combining camera and gyroscope
-     * information together simpler.</p>
      */
     ACAMERA_LENS_POSE_REFERENCE =                               // byte (acamera_metadata_enum_android_lens_pose_reference_t)
             ACAMERA_LENS_START + 12,
@@ -4565,7 +4562,7 @@
     ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE =                  // byte (acamera_metadata_enum_android_statistics_lens_shading_map_mode_t)
             ACAMERA_STATISTICS_START + 16,
     /**
-     * <p>Whether the camera device outputs the OIS data in output
+     * <p>A control for selecting whether OIS position information is included in output
      * result metadata.</p>
      *
      * <p>Type: byte (acamera_metadata_enum_android_statistics_ois_data_mode_t)</p>
@@ -4576,11 +4573,6 @@
      *   <li>ACaptureRequest</li>
      * </ul></p>
      *
-     * <p>When set to ON,
-     * ACAMERA_STATISTICS_OIS_TIMESTAMPS, android.statistics.oisShiftPixelX,
-     * android.statistics.oisShiftPixelY will provide OIS data in the output result metadata.</p>
-     *
-     * @see ACAMERA_STATISTICS_OIS_TIMESTAMPS
      */
     ACAMERA_STATISTICS_OIS_DATA_MODE =                          // byte (acamera_metadata_enum_android_statistics_ois_data_mode_t)
             ACAMERA_STATISTICS_START + 17,
@@ -4613,7 +4605,7 @@
      *
      * <p>The array contains the amount of shifts in x direction, in pixels, based on OIS samples.
      * A positive value is a shift from left to right in active array coordinate system. For
-     * example, if the optical center is (1000, 500) in active array coordinates, an shift of
+     * example, if the optical center is (1000, 500) in active array coordinates, a shift of
      * (3, 0) puts the new optical center at (1003, 500).</p>
      * <p>The number of shifts must match the number of timestamps in
      * ACAMERA_STATISTICS_OIS_TIMESTAMPS.</p>
@@ -4634,7 +4626,7 @@
      *
      * <p>The array contains the amount of shifts in y direction, in pixels, based on OIS samples.
      * A positive value is a shift from top to bottom in active array coordinate system. For
-     * example, if the optical center is (1000, 500) in active array coordinates, an shift of
+     * example, if the optical center is (1000, 500) in active array coordinates, a shift of
      * (0, 5) puts the new optical center at (1000, 505).</p>
      * <p>The number of shifts must match the number of timestamps in
      * ACAMERA_STATISTICS_OIS_TIMESTAMPS.</p>
@@ -6601,7 +6593,7 @@
     /**
      * <p>The value of ACAMERA_LENS_POSE_TRANSLATION is relative to the optical center of
      * the largest camera device facing the same direction as this camera.</p>
-     * <p>This default value for API levels before Android P.</p>
+     * <p>This is the default value for API levels before Android P.</p>
      *
      * @see ACAMERA_LENS_POSE_TRANSLATION
      */
@@ -6610,7 +6602,6 @@
     /**
      * <p>The value of ACAMERA_LENS_POSE_TRANSLATION is relative to the position of the
      * primary gyroscope of this Android device.</p>
-     * <p>This is the value reported by all devices that support the MOTION_TRACKING capability.</p>
      *
      * @see ACAMERA_LENS_POSE_TRANSLATION
      */
@@ -6974,46 +6965,12 @@
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT              = 8,
 
     /**
-     * <p>The device supports controls and metadata required for accurate motion tracking for
-     * use cases such as augmented reality, electronic image stabilization, and so on.</p>
-     * <p>This means this camera device has accurate optical calibration and timestamps relative
-     * to the inertial sensors.</p>
-     * <p>This capability requires the camera device to support the following:</p>
-     * <ul>
-     * <li>Capture request templates <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#TEMPLATE_MOTION_TRACKING_PREVIEW">CameraDevice#TEMPLATE_MOTION_TRACKING_PREVIEW</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#TEMPLATE_MOTION_TRACKING_BEST">CameraDevice#TEMPLATE_MOTION_TRACKING_BEST</a> are defined.</li>
-     * <li>The stream configurations listed in <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for MOTION_TRACKING are
-     *   supported, either at 30 or 60fps maximum frame rate.</li>
-     * <li>The following camera characteristics and capture result metadata are provided:<ul>
-     * <li>ACAMERA_LENS_INTRINSIC_CALIBRATION</li>
-     * <li>ACAMERA_LENS_RADIAL_DISTORTION</li>
-     * <li>ACAMERA_LENS_POSE_ROTATION</li>
-     * <li>ACAMERA_LENS_POSE_TRANSLATION</li>
-     * <li>ACAMERA_LENS_POSE_REFERENCE with value GYROSCOPE</li>
-     * </ul>
-     * </li>
-     * <li>The ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE field has value <code>REALTIME</code>. When compared to
-     *   timestamps from the device's gyroscopes, the clock difference for events occuring at
-     *   the same actual time instant will be less than 1 ms.</li>
-     * <li>The value of the ACAMERA_SENSOR_ROLLING_SHUTTER_SKEW field is accurate to within 1 ms.</li>
-     * <li>The value of ACAMERA_SENSOR_EXPOSURE_TIME is guaranteed to be available in the
-     *   capture result.</li>
-     * <li>The ACAMERA_CONTROL_CAPTURE_INTENT control supports MOTION_TRACKING to limit maximum
-     *   exposure to 20 milliseconds.</li>
-     * <li>The stream configurations required for MOTION_TRACKING (listed at <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) can operate at least at
-     *   30fps; optionally, they can operate at 60fps, and '[60, 60]' is listed in
-     *   ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES.</li>
-     * </ul>
+     * <p>The camera device supports the MOTION_TRACKING value for
+     * ACAMERA_CONTROL_CAPTURE_INTENT, which limits maximum exposure time to 20 ms.</p>
+     * <p>This limits the motion blur of capture images, resulting in better image tracking
+     * results for use cases such as image stabilization or augmented reality.</p>
      *
-     * @see ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
      * @see ACAMERA_CONTROL_CAPTURE_INTENT
-     * @see ACAMERA_LENS_INTRINSIC_CALIBRATION
-     * @see ACAMERA_LENS_POSE_REFERENCE
-     * @see ACAMERA_LENS_POSE_ROTATION
-     * @see ACAMERA_LENS_POSE_TRANSLATION
-     * @see ACAMERA_LENS_RADIAL_DISTORTION
-     * @see ACAMERA_SENSOR_EXPOSURE_TIME
-     * @see ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE
-     * @see ACAMERA_SENSOR_ROLLING_SHUTTER_SKEW
      */
     ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING           = 10,
 
@@ -7036,19 +6993,24 @@
      * <li>ACAMERA_LENS_RADIAL_DISTORTION</li>
      * </ul>
      * </li>
+     * <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
+     *   the same.</li>
      * <li>The logical camera device must be LIMITED or higher device.</li>
      * </ul>
      * <p>Both the logical camera device and its underlying physical devices support the
      * mandatory stream combinations required for their device levels.</p>
      * <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
      * <ul>
-     * <li>Replacing one logical {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888}
+     * <li>For each guaranteed stream combination, the logical camera supports replacing one
+     *   logical {@link AIMAGE_FORMAT_YUV_420_888 YUV_420_888}
      *   or raw stream with two physical streams of the same size and format, each from a
      *   separate physical camera, given that the size and format are supported by both
      *   physical cameras.</li>
-     * <li>Adding two raw streams, each from one physical camera, if the logical camera doesn't
-     *   advertise RAW capability, but the underlying physical cameras do. This is usually
-     *   the case when the physical cameras have different sensor sizes.</li>
+     * <li>If the logical camera doesn't advertise RAW capability, but the underlying physical
+     *   cameras do, the logical camera will support guaranteed stream combinations for RAW
+     *   capability, except that the RAW streams will be physical streams, each from a separate
+     *   physical camera. This is usually the case when the physical cameras have different
+     *   sensor sizes.</li>
      * </ul>
      * <p>Using physical streams in place of a logical stream of the same size and format will
      * not slow down the frame rate of the capture, as long as the minimum frame duration
@@ -7403,6 +7365,12 @@
 
     /**
      * <p>Include OIS data in the capture result.</p>
+     * <p>ACAMERA_STATISTICS_OIS_TIMESTAMPS, ACAMERA_STATISTICS_OIS_X_SHIFTS,
+     * and ACAMERA_STATISTICS_OIS_Y_SHIFTS provide OIS data in the output result metadata.</p>
+     *
+     * @see ACAMERA_STATISTICS_OIS_TIMESTAMPS
+     * @see ACAMERA_STATISTICS_OIS_X_SHIFTS
+     * @see ACAMERA_STATISTICS_OIS_Y_SHIFTS
      */
     ACAMERA_STATISTICS_OIS_DATA_MODE_ON                              = 1,
 
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 46bd8f0..9d2daab 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -50,6 +50,7 @@
 #include <media/stagefright/MediaCodec.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaMuxer.h>
+#include <media/stagefright/PersistentSurface.h>
 #include <media/ICrypto.h>
 #include <media/MediaCodecBuffer.h>
 
@@ -70,6 +71,7 @@
 static bool gVerbose = false;           // chatty on stdout
 static bool gRotate = false;            // rotate 90 degrees
 static bool gMonotonicTime = false;     // use system monotonic time for timestamps
+static bool gPersistentSurface = false; // use persistent surface
 static enum {
     FORMAT_MP4, FORMAT_H264, FORMAT_FRAMES, FORMAT_RAW_FRAMES
 } gOutputFormat = FORMAT_MP4;           // data format for output
@@ -199,10 +201,18 @@
 
     ALOGV("Creating encoder input surface");
     sp<IGraphicBufferProducer> bufferProducer;
-    err = codec->createInputSurface(&bufferProducer);
+    if (gPersistentSurface) {
+        sp<PersistentSurface> surface = MediaCodec::CreatePersistentInputSurface();
+        bufferProducer = surface->getBufferProducer();
+        err = codec->setInputSurface(surface);
+    } else {
+        err = codec->createInputSurface(&bufferProducer);
+    }
     if (err != NO_ERROR) {
         fprintf(stderr,
-            "ERROR: unable to create encoder input surface (err=%d)\n", err);
+            "ERROR: unable to %s encoder input surface (err=%d)\n",
+            gPersistentSurface ? "set" : "create",
+            err);
         codec->release();
         return err;
     }
@@ -920,6 +930,7 @@
         { "output-format",      required_argument,  NULL, 'o' },
         { "codec-name",         required_argument,  NULL, 'N' },
         { "monotonic-time",     no_argument,        NULL, 'm' },
+        { "persistent-surface", no_argument,        NULL, 'p' },
         { NULL,                 0,                  NULL, 0 }
     };
 
@@ -1005,6 +1016,9 @@
         case 'm':
             gMonotonicTime = true;
             break;
+        case 'p':
+            gPersistentSurface = true;
+            break;
         default:
             if (ic != '?') {
                 fprintf(stderr, "getopt_long returned unexpected value 0x%x\n", ic);
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index cad8caf..9e40a0f 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -4,6 +4,7 @@
 
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 
@@ -59,10 +60,10 @@
 }
 
 status_t SineSource::read(
-        MediaBuffer **out, const ReadOptions * /* options */) {
+        MediaBufferBase **out, const ReadOptions * /* options */) {
     *out = NULL;
 
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
 
     if (err != OK) {
diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h
index f1fb96d..1817291 100644
--- a/cmds/stagefright/SineSource.h
+++ b/cmds/stagefright/SineSource.h
@@ -18,7 +18,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **out, const ReadOptions *options = NULL);
+            MediaBufferBase **out, const ReadOptions *options = NULL);
 
 protected:
     virtual ~SineSource();
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index fc24646..d4f2e8d 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -169,7 +169,7 @@
 ALOGI("Line: %d", __LINE__);
         } else {
             CHECK_EQ(decoder->start(), (status_t)OK);
-            MediaBuffer* buffer;
+            MediaBufferBase* buffer;
             while (decoder->read(&buffer) == OK) {
                 // do something with buffer (save it eventually?)
                 // need to stop after some count though...
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 073ee6b..44b0015 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -328,7 +328,7 @@
 
     int32_t n = 0;
     status_t err;
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     while ((err = encoder->read(&buffer)) == OK) {
         printf(".");
         fflush(stdout);
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index af39d46..b7a5066 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -90,7 +90,7 @@
     }
 
     virtual status_t read(
-            MediaBuffer **buffer, const MediaSource::ReadOptions *options __unused) {
+            MediaBufferBase **buffer, const MediaSource::ReadOptions *options __unused) {
 
         if (mNumFramesOutput % 10 == 0) {
             fprintf(stderr, ".");
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index bb517aa..5fa8304 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -150,7 +150,7 @@
 
     status_t err;
     for (;;) {
-        MediaBuffer *mbuf;
+        MediaBufferBase *mbuf;
         err = source->read(&mbuf);
 
         if (err == INFO_FORMAT_CHANGED) {
@@ -234,7 +234,7 @@
         CHECK(meta->findInt64(kKeyDuration, &durationUs));
 
         status_t err;
-        MediaBuffer *buffer;
+        MediaBufferBase *buffer;
         MediaSource::ReadOptions options;
         int64_t seekTimeUs = -1;
         for (;;) {
@@ -321,7 +321,7 @@
     while (numIterationsLeft-- > 0) {
         long numFrames = 0;
 
-        MediaBuffer *buffer;
+        MediaBufferBase *buffer;
 
         for (;;) {
             int64_t startDecodeUs = getNowUs();
@@ -416,7 +416,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options);
+            MediaBufferBase **buffer, const ReadOptions *options);
 
 private:
     enum StreamType {
@@ -465,7 +465,7 @@
     return mSource->getFormat();
 }
 
-static bool isIDRFrame(MediaBuffer *buffer) {
+static bool isIDRFrame(MediaBufferBase *buffer) {
     const uint8_t *data =
         (const uint8_t *)buffer->data() + buffer->range_offset();
     size_t size = buffer->range_length();
@@ -482,7 +482,7 @@
 }
 
 status_t DetectSyncSource::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
+        MediaBufferBase **buffer, const ReadOptions *options) {
     for (;;) {
         status_t err = mSource->read(buffer, options);
 
@@ -562,7 +562,7 @@
         options.setSeekTo(
                 seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
 
-        MediaBuffer *buffer;
+        MediaBufferBase *buffer;
         status_t err;
         for (;;) {
             err = source->read(&buffer, &options);
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index ea239c5..5ea4614 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -15,25 +15,20 @@
         "IDrm.cpp",
         "IDrmClient.cpp",
         "IMediaDrmService.cpp",
-        "PluginMetricsReporting.cpp",
         "SharedLibrary.cpp",
         "DrmHal.cpp",
-	"DrmMetrics.cpp",
         "CryptoHal.cpp",
-        "protos/plugin_metrics.proto",
     ],
 
-    proto: {
-        type: "lite",
-    },
-
     shared_libs: [
         "libbinder",
         "libcutils",
         "libdl",
         "liblog",
+        "libmediadrmmetrics_lite",
         "libmediametrics",
         "libmediautils",
+        "libprotobuf-cpp-lite",
         "libstagefright_foundation",
         "libutils",
         "android.hardware.drm@1.0",
@@ -48,3 +43,66 @@
         "-Wall",
     ],
 }
+
+// This is the version of the drm metrics configured for protobuf lite.
+cc_library_shared {
+    name: "libmediadrmmetrics_lite",
+    srcs: [
+        "DrmMetrics.cpp",
+        "PluginMetricsReporting.cpp",
+        "protos/metrics.proto",
+    ],
+
+    proto: {
+        export_proto_headers: true,
+	type: "lite",
+    },
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libmediametrics",
+        "libprotobuf-cpp-lite",
+        "libutils",
+    ],
+    cflags: [
+        // Suppress unused parameter and no error options. These cause problems
+        // with the when using the map type in a proto definition.
+        "-Wno-unused-parameter",
+        "-Wno-error",
+    ],
+}
+
+// This is the version of the drm metrics library configured for full protobuf.
+cc_library_shared {
+    name: "libmediadrmmetrics_full",
+    srcs: [
+        "DrmMetrics.cpp",
+        "PluginMetricsReporting.cpp",
+        "protos/metrics.proto",
+    ],
+
+    proto: {
+        export_proto_headers: true,
+	type: "full",
+    },
+    shared_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libmediametrics",
+        "libprotobuf-cpp-full",
+        "libutils",
+    ],
+    cflags: [
+        // Suppress unused parameter and no error options. These cause problems
+	// when using the map type in a proto definition.
+	"-Wno-unused-parameter",
+	"-Wno-error",
+    ],
+}
+
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 039e1e9..068a52b 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -16,6 +16,8 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "DrmHal"
+#include <iomanip>
+
 #include <utils/Log.h>
 
 #include <binder/IPCThreadState.h>
@@ -52,6 +54,7 @@
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::os::PersistableBundle;
 using ::android::sp;
 
 namespace {
@@ -97,6 +100,15 @@
     return hidl_string(string.string());
 }
 
+std::string toHexString(const std::string& str) {
+  std::ostringstream out;
+  out << std::hex << std::setfill('0');
+  for (size_t i = 0; i < str.size(); i++) {
+    out << std::setw(2) << (int)(str[i]);
+  }
+  return out.str();
+}
+
 static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
     switch(level) {
     case SecurityLevel::SW_SECURE_CRYPTO:
@@ -249,20 +261,39 @@
 }
 
 void DrmHal::closeOpenSessions() {
-    if (mPlugin != NULL) {
-        for (size_t i = 0; i < mOpenSessions.size(); i++) {
-            mPlugin->closeSession(toHidlVec(mOpenSessions[i]));
-            DrmSessionManager::Instance()->removeSession(mOpenSessions[i]);
-        }
+    Mutex::Autolock autoLock(mLock);
+    auto openSessions = mOpenSessions;
+    for (size_t i = 0; i < openSessions.size(); i++) {
+        mLock.unlock();
+        closeSession(openSessions[i]);
+        mLock.lock();
     }
     mOpenSessions.clear();
 }
 
 DrmHal::~DrmHal() {
-    closeOpenSessions();
     DrmSessionManager::Instance()->removeDrm(mDrmSessionClient);
 }
 
+void DrmHal::cleanup() {
+    closeOpenSessions();
+
+    Mutex::Autolock autoLock(mLock);
+    reportPluginMetrics();
+    reportFrameworkMetrics();
+
+    setListener(NULL);
+    mInitCheck = NO_INIT;
+
+    if (mPlugin != NULL) {
+        if (!mPlugin->setListener(NULL).isOk()) {
+            mInitCheck = DEAD_OBJECT;
+        }
+    }
+    mPlugin.clear();
+    mPluginV1_1.clear();
+}
+
 Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
     Vector<sp<IDrmFactory>> factories;
 
@@ -308,6 +339,7 @@
 
 sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
         const uint8_t uuid[16], const String8& appPackageName) {
+    mMetrics.SetAppPackageName(appPackageName);
 
     sp<IDrmPlugin> plugin;
     Return<void> hResult = factory->createPlugin(uuid, appPackageName.string(),
@@ -499,21 +531,7 @@
 }
 
 status_t DrmHal::destroyPlugin() {
-    Mutex::Autolock autoLock(mLock);
-    INIT_CHECK();
-
-    closeOpenSessions();
-    reportMetrics();
-    setListener(NULL);
-    mInitCheck = NO_INIT;
-
-    if (mPlugin != NULL) {
-        if (!mPlugin->setListener(NULL).isOk()) {
-            mInitCheck = DEAD_OBJECT;
-        }
-    }
-    mPlugin.clear();
-    mPluginV1_1.clear();
+    cleanup();
     return OK;
 }
 
@@ -594,6 +612,7 @@
         DrmSessionManager::Instance()->addSession(getCallingPid(),
                 mDrmSessionClient, sessionId);
         mOpenSessions.push(sessionId);
+        mMetrics.SetSessionStart(sessionId);
     }
 
     mMetrics.mOpenSessionCounter.Increment(err);
@@ -615,8 +634,8 @@
                 }
             }
         }
-        reportMetrics();
         status_t response = toStatusT(status);
+        mMetrics.SetSessionEnd(sessionId);
         mMetrics.mCloseSessionCounter.Increment(response);
         return response;
     }
@@ -631,7 +650,7 @@
         String8 &defaultUrl, DrmPlugin::KeyRequestType *keyRequestType) {
     Mutex::Autolock autoLock(mLock);
     INIT_CHECK();
-    EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTiming);
+    EventTimer<status_t> keyRequestTimer(&mMetrics.mGetKeyRequestTimeUs);
 
     DrmSessionManager::Instance()->useSession(sessionId);
 
@@ -726,7 +745,7 @@
 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.mProvideKeyResponseTiming);
+    EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
 
     INIT_CHECK();
 
@@ -1095,7 +1114,7 @@
     return toStatusT(status);
 }
 
-status_t DrmHal::getMetrics(MediaAnalyticsItem* item) {
+status_t DrmHal::getMetrics(PersistableBundle* item) {
     if (item == nullptr) {
       return UNEXPECTED_NULL;
     }
@@ -1251,17 +1270,7 @@
 
 void DrmHal::binderDied(const wp<IBinder> &the_late_who __unused)
 {
-    Mutex::Autolock autoLock(mLock);
-    closeOpenSessions();
-    setListener(NULL);
-    mInitCheck = NO_INIT;
-
-    if (mPlugin != NULL) {
-        if (!mPlugin->setListener(NULL).isOk()) {
-            mInitCheck = DEAD_OBJECT;
-        }
-    }
-    mPlugin.clear();
+    cleanup();
 }
 
 void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
@@ -1274,8 +1283,41 @@
     }
 }
 
+void DrmHal::reportFrameworkMetrics() const
+{
+    MediaAnalyticsItem item("mediadrm");
+    item.generateSessionID();
+    item.setPkgName(mMetrics.GetAppPackageName().c_str());
+    String8 vendor;
+    String8 description;
+    status_t result = getPropertyStringInternal(String8("vendor"), vendor);
+    if (result != OK) {
+        ALOGE("Failed to get vendor from drm plugin: %d", result);
+    } else {
+        item.setCString("vendor", vendor.c_str());
+    }
+    result = getPropertyStringInternal(String8("description"), description);
+    if (result != OK) {
+        ALOGE("Failed to get description from drm plugin: %d", result);
+    } else {
+        item.setCString("description", description.c_str());
+    }
 
-void DrmHal::reportMetrics() const
+    std::string serializedMetrics;
+    result = mMetrics.GetSerializedMetrics(&serializedMetrics);
+    if (result != OK) {
+        ALOGE("Failed to serialize framework metrics: %d", result);
+    }
+    serializedMetrics = toHexString(serializedMetrics);
+    if (!serializedMetrics.empty()) {
+        item.setCString("serialized_metrics", serializedMetrics.c_str());
+    }
+    if (!item.selfrecord()) {
+        ALOGE("Failed to self record framework metrics");
+    }
+}
+
+void DrmHal::reportPluginMetrics() const
 {
     Vector<uint8_t> metrics;
     String8 vendor;
@@ -1286,7 +1328,7 @@
         status_t res = android::reportDrmPluginMetrics(
                 metrics, vendor, description);
         if (res != OK) {
-            ALOGE("Metrics were retrieved but could not be reported: %i", res);
+            ALOGE("Metrics were retrieved but could not be reported: %d", res);
         }
     }
 }
diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp
index 258c4b0..03bd88a 100644
--- a/drm/libmediadrm/DrmMetrics.cpp
+++ b/drm/libmediadrm/DrmMetrics.cpp
@@ -13,140 +13,330 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "DrmMetrics"
+#include <iomanip>
+#include <utility>
 
 #include <android-base/macros.h>
 #include <media/DrmMetrics.h>
+#include <media/stagefright/foundation/base64.h>
+#include <sys/time.h>
+#include <utils/Log.h>
+#include <utils/Timers.h>
 
+#include "protos/metrics.pb.h"
+
+using ::android::String16;
+using ::android::String8;
+using ::android::drm_metrics::DrmFrameworkMetrics;
 using ::android::hardware::drm::V1_0::EventType;
 using ::android::hardware::drm::V1_0::KeyStatusType;
+using ::android::os::PersistableBundle;
 
 namespace {
 
-template<typename T>
-std::string GetAttributeName(T type);
+template <typename T> std::string GetAttributeName(T type);
 
-template<>
-std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
-  static const char* type_names[] = {
-      "USABLE", "EXPIRED", "OUTPUT_NOT_ALLOWED",
-      "STATUS_PENDING", "INTERNAL_ERROR" };
-  if (((size_t) type) > arraysize(type_names)) {
-    return "UNKNOWN_TYPE";
-  }
-  return type_names[(size_t) type];
+template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
+    static const char *type_names[] = {"USABLE", "EXPIRED",
+                                       "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
+                                       "INTERNAL_ERROR"};
+    if (((size_t)type) > arraysize(type_names)) {
+        return "UNKNOWN_TYPE";
+    }
+    return type_names[(size_t)type];
 }
 
-template<>
-std::string GetAttributeName<EventType>(EventType type) {
-  static const char* type_names[] = {
-      "PROVISION_REQUIRED", "KEY_NEEDED", "KEY_EXPIRED",
-      "VENDOR_DEFINED", "SESSION_RECLAIMED" };
-  if (((size_t) type) > arraysize(type_names)) {
-    return "UNKNOWN_TYPE";
-  }
-  return type_names[(size_t) type];
+template <> std::string GetAttributeName<EventType>(EventType type) {
+    static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
+                                       "KEY_EXPIRED", "VENDOR_DEFINED",
+                                       "SESSION_RECLAIMED"};
+    if (((size_t)type) > arraysize(type_names)) {
+        return "UNKNOWN_TYPE";
+    }
+    return type_names[(size_t)type];
 }
 
-template<typename T>
-void ExportCounterMetric(const android::CounterMetric<T>& counter,
-                         android::MediaAnalyticsItem* item) {
-  if (!item) {
-    ALOGE("item was unexpectedly null.");
-    return;
-  }
-  std::string success_count_name = counter.metric_name() + ".ok.count";
-  std::string error_count_name = counter.metric_name() + ".error.count";
-  counter.ExportValues(
-      [&] (const android::status_t status, const int64_t value) {
-          if (status == android::OK) {
-              item->setInt64(success_count_name.c_str(), value);
-          } else {
-              int64_t total_errors(0);
-              item->getInt64(error_count_name.c_str(), &total_errors);
-              item->setInt64(error_count_name.c_str(), total_errors + value);
-              // TODO: Add support for exporting the list of error values.
-              // This probably needs to be added to MediaAnalyticsItem.
-          }
-      });
+template <typename T>
+void ExportCounterMetric(const android::CounterMetric<T> &counter,
+                         PersistableBundle *metrics) {
+    if (!metrics) {
+        ALOGE("metrics was unexpectedly null.");
+        return;
+    }
+    std::string success_count_name = counter.metric_name() + ".ok.count";
+    std::string error_count_name = counter.metric_name() + ".error.count";
+    std::vector<int64_t> status_values;
+    counter.ExportValues(
+        [&](const android::status_t status, const int64_t value) {
+            if (status == android::OK) {
+                metrics->putLong(android::String16(success_count_name.c_str()),
+                                 value);
+            } else {
+                int64_t total_errors(0);
+                metrics->getLong(android::String16(error_count_name.c_str()),
+                                 &total_errors);
+                metrics->putLong(android::String16(error_count_name.c_str()),
+                                 total_errors + value);
+                status_values.push_back(status);
+            }
+        });
+    if (!status_values.empty()) {
+        std::string error_list_name = counter.metric_name() + ".error.list";
+        metrics->putLongVector(android::String16(error_list_name.c_str()),
+                               status_values);
+    }
 }
 
-template<typename T>
+template <typename T>
 void ExportCounterMetricWithAttributeNames(
-    const android::CounterMetric<T>& counter,
-    android::MediaAnalyticsItem* item) {
-  if (!item) {
-    ALOGE("item was unexpectedly null.");
-    return;
-  }
-  counter.ExportValues(
-      [&] (const T& attribute, const int64_t value) {
-          std::string name = counter.metric_name()
-              + "." + GetAttributeName(attribute) + ".count";
-          item->setInt64(name.c_str(), value);
-      });
+    const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
+    if (!metrics) {
+        ALOGE("metrics was unexpectedly null.");
+        return;
+    }
+    counter.ExportValues([&](const T &attribute, const int64_t value) {
+        std::string name = counter.metric_name() + "." +
+                           GetAttributeName(attribute) + ".count";
+        metrics->putLong(android::String16(name.c_str()), value);
+    });
 }
 
-template<typename T>
-void ExportEventMetric(const android::EventMetric<T>& event,
-                       android::MediaAnalyticsItem* item) {
-  if (!item) {
-    ALOGE("item was unexpectedly null.");
-    return;
-  }
-  std::string success_count_name = event.metric_name() + ".ok.count";
-  std::string error_count_name = event.metric_name() + ".error.count";
-  std::string timing_name = event.metric_name() + ".ok.average_time_micros";
-  event.ExportValues(
-      [&] (const android::status_t& status,
-           const android::EventStatistics& value) {
-          if (status == android::OK) {
-              item->setInt64(success_count_name.c_str(), value.count);
-              item->setInt64(timing_name.c_str(), value.mean);
-          } else {
-              int64_t total_errors(0);
-              item->getInt64(error_count_name.c_str(), &total_errors);
-              item->setInt64(error_count_name.c_str(),
+template <typename T>
+void ExportEventMetric(const android::EventMetric<T> &event,
+                       PersistableBundle *metrics) {
+    if (!metrics) {
+        ALOGE("metrics was unexpectedly null.");
+        return;
+    }
+    std::string success_count_name = event.metric_name() + ".ok.count";
+    std::string error_count_name = event.metric_name() + ".error.count";
+    std::string timing_name = event.metric_name() + ".ok.average_time_micros";
+    std::vector<int64_t> status_values;
+    event.ExportValues([&](const android::status_t &status,
+                           const android::EventStatistics &value) {
+        if (status == android::OK) {
+            metrics->putLong(android::String16(success_count_name.c_str()),
+                             value.count);
+            metrics->putLong(android::String16(timing_name.c_str()),
+                             value.mean);
+        } else {
+            int64_t total_errors(0);
+            metrics->getLong(android::String16(error_count_name.c_str()),
+                             &total_errors);
+            metrics->putLong(android::String16(error_count_name.c_str()),
                              total_errors + value.count);
-              // TODO: Add support for exporting the list of error values.
-              // This probably needs to be added to MediaAnalyticsItem.
-          }
-      });
+            status_values.push_back(status);
+        }
+    });
+    if (!status_values.empty()) {
+        std::string error_list_name = event.metric_name() + ".error.list";
+        metrics->putLongVector(android::String16(error_list_name.c_str()),
+                               status_values);
+    }
 }
 
-}  // namespace anonymous
+void ExportSessionLifespans(
+    const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans,
+    PersistableBundle *metrics) {
+    if (!metrics) {
+        ALOGE("metrics was unexpectedly null.");
+        return;
+    }
+
+    if (mSessionLifespans.empty()) {
+        return;
+    }
+
+    PersistableBundle startTimesBundle;
+    PersistableBundle endTimesBundle;
+    for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end();
+         it++) {
+        String16 key(it->first.c_str(), it->first.size());
+        startTimesBundle.putLong(key, it->second.first);
+        endTimesBundle.putLong(key, it->second.second);
+    }
+    metrics->putPersistableBundle(
+        android::String16("drm.mediadrm.session_start_times_ms"),
+        startTimesBundle);
+    metrics->putPersistableBundle(
+        android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
+}
+
+std::string ToHexString(const android::Vector<uint8_t> &sessionId) {
+    std::ostringstream out;
+    out << std::hex << std::setfill('0');
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        out << std::setw(2) << (int)(sessionId[i]);
+    }
+    return out.str();
+}
+
+} // namespace
 
 namespace android {
 
 MediaDrmMetrics::MediaDrmMetrics()
     : mOpenSessionCounter("drm.mediadrm.open_session", "status"),
       mCloseSessionCounter("drm.mediadrm.close_session", "status"),
-      mGetKeyRequestTiming("drm.mediadrm.get_key_request", "status"),
-      mProvideKeyResponseTiming("drm.mediadrm.provide_key_response", "status"),
-      mGetProvisionRequestCounter(
-          "drm.mediadrm.get_provision_request", "status"),
+      mGetKeyRequestTimeUs("drm.mediadrm.get_key_request", "status"),
+      mProvideKeyResponseTimeUs("drm.mediadrm.provide_key_response", "status"),
+      mGetProvisionRequestCounter("drm.mediadrm.get_provision_request",
+                                  "status"),
       mProvideProvisionResponseCounter(
           "drm.mediadrm.provide_provision_response", "status"),
-      mKeyStatusChangeCounter(
-          "drm.mediadrm.key_status_change", "key_status_type"),
+      mKeyStatusChangeCounter("drm.mediadrm.key_status_change",
+                              "key_status_type"),
       mEventCounter("drm.mediadrm.event", "event_type"),
-      mGetDeviceUniqueIdCounter(
-          "drm.mediadrm.get_device_unique_id", "status") {
+      mGetDeviceUniqueIdCounter("drm.mediadrm.get_device_unique_id", "status") {
 }
 
-void MediaDrmMetrics::Export(MediaAnalyticsItem* item) {
-  if (!item) {
-    ALOGE("item was unexpectedly null.");
-    return;
-  }
-  ExportCounterMetric(mOpenSessionCounter, item);
-  ExportCounterMetric(mCloseSessionCounter, item);
-  ExportEventMetric(mGetKeyRequestTiming, item);
-  ExportEventMetric(mProvideKeyResponseTiming, item);
-  ExportCounterMetric(mGetProvisionRequestCounter, item);
-  ExportCounterMetric(mProvideProvisionResponseCounter, item);
-  ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, item);
-  ExportCounterMetricWithAttributeNames(mEventCounter, item);
-  ExportCounterMetric(mGetDeviceUniqueIdCounter, item);
+void MediaDrmMetrics::SetSessionStart(
+    const android::Vector<uint8_t> &sessionId) {
+    std::string sessionIdHex = ToHexString(sessionId);
+    mSessionLifespans[sessionIdHex] =
+        std::make_pair(GetCurrentTimeMs(), (int64_t)0);
 }
 
-}  // namespace android
+void MediaDrmMetrics::SetSessionEnd(const android::Vector<uint8_t> &sessionId) {
+    std::string sessionIdHex = ToHexString(sessionId);
+    int64_t endTimeMs = GetCurrentTimeMs();
+    if (mSessionLifespans.find(sessionIdHex) != mSessionLifespans.end()) {
+        mSessionLifespans[sessionIdHex] =
+            std::make_pair(mSessionLifespans[sessionIdHex].first, endTimeMs);
+    } else {
+        mSessionLifespans[sessionIdHex] = std::make_pair((int64_t)0, endTimeMs);
+    }
+}
+
+void MediaDrmMetrics::Export(PersistableBundle *metrics) {
+    if (!metrics) {
+        ALOGE("metrics was unexpectedly null.");
+        return;
+    }
+    ExportCounterMetric(mOpenSessionCounter, metrics);
+    ExportCounterMetric(mCloseSessionCounter, metrics);
+    ExportEventMetric(mGetKeyRequestTimeUs, metrics);
+    ExportEventMetric(mProvideKeyResponseTimeUs, metrics);
+    ExportCounterMetric(mGetProvisionRequestCounter, metrics);
+    ExportCounterMetric(mProvideProvisionResponseCounter, metrics);
+    ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics);
+    ExportCounterMetricWithAttributeNames(mEventCounter, metrics);
+    ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics);
+    ExportSessionLifespans(mSessionLifespans, metrics);
+}
+
+status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) {
+
+    if (!serializedMetrics) {
+        ALOGE("serializedMetrics was unexpectedly null.");
+        return UNEXPECTED_NULL;
+    }
+
+    DrmFrameworkMetrics metrics;
+
+    mOpenSessionCounter.ExportValues(
+        [&](const android::status_t status, const int64_t value) {
+            DrmFrameworkMetrics::Counter *counter =
+                metrics.add_open_session_counter();
+            counter->set_count(value);
+            counter->mutable_attributes()->set_error_code(status);
+        });
+
+    mCloseSessionCounter.ExportValues(
+        [&](const android::status_t status, const int64_t value) {
+            DrmFrameworkMetrics::Counter *counter =
+                metrics.add_close_session_counter();
+            counter->set_count(value);
+            counter->mutable_attributes()->set_error_code(status);
+        });
+
+    mGetProvisionRequestCounter.ExportValues(
+        [&](const android::status_t status, const int64_t value) {
+            DrmFrameworkMetrics::Counter *counter =
+                metrics.add_get_provisioning_request_counter();
+            counter->set_count(value);
+            counter->mutable_attributes()->set_error_code(status);
+        });
+
+    mProvideProvisionResponseCounter.ExportValues(
+        [&](const android::status_t status, const int64_t value) {
+            DrmFrameworkMetrics::Counter *counter =
+                metrics.add_provide_provisioning_response_counter();
+            counter->set_count(value);
+            counter->mutable_attributes()->set_error_code(status);
+        });
+
+    mKeyStatusChangeCounter.ExportValues(
+        [&](const KeyStatusType key_status_type, const int64_t value) {
+            DrmFrameworkMetrics::Counter *counter =
+                metrics.add_key_status_change_counter();
+            counter->set_count(value);
+            counter->mutable_attributes()->set_key_status_type(
+                (uint32_t)key_status_type);
+        });
+
+    mEventCounter.ExportValues(
+        [&](const EventType event_type, const int64_t value) {
+            DrmFrameworkMetrics::Counter *counter =
+                metrics.add_event_callback_counter();
+            counter->set_count(value);
+            counter->mutable_attributes()->set_event_type((uint32_t)event_type);
+        });
+
+    mGetDeviceUniqueIdCounter.ExportValues(
+        [&](const status_t status, const int64_t value) {
+            DrmFrameworkMetrics::Counter *counter =
+                metrics.add_get_device_unique_id_counter();
+            counter->set_count(value);
+            counter->mutable_attributes()->set_error_code(status);
+        });
+
+    mGetKeyRequestTimeUs.ExportValues(
+        [&](const status_t status, const EventStatistics &stats) {
+            DrmFrameworkMetrics::DistributionMetric *metric =
+                metrics.add_get_key_request_time_us();
+            metric->set_min(stats.min);
+            metric->set_max(stats.max);
+            metric->set_mean(stats.mean);
+            metric->set_operation_count(stats.count);
+            metric->set_variance(stats.sum_squared_deviation / stats.count);
+            metric->mutable_attributes()->set_error_code(status);
+        });
+
+    mProvideKeyResponseTimeUs.ExportValues(
+        [&](const status_t status, const EventStatistics &stats) {
+            DrmFrameworkMetrics::DistributionMetric *metric =
+                metrics.add_provide_key_response_time_us();
+            metric->set_min(stats.min);
+            metric->set_max(stats.max);
+            metric->set_mean(stats.mean);
+            metric->set_operation_count(stats.count);
+            metric->set_variance(stats.sum_squared_deviation / stats.count);
+            metric->mutable_attributes()->set_error_code(status);
+        });
+
+    for (const auto &sessionLifespan : mSessionLifespans) {
+        auto *map = metrics.mutable_session_lifetimes();
+
+        (*map)[sessionLifespan.first].set_start_time_ms(
+            sessionLifespan.second.first);
+        (*map)[sessionLifespan.first].set_end_time_ms(
+            sessionLifespan.second.second);
+    }
+
+    if (!metrics.SerializeToString(serializedMetrics)) {
+        ALOGE("Failed to serialize metrics.");
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+int64_t MediaDrmMetrics::GetCurrentTimeMs() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000);
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 9f54dba..22e4e6c 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -492,7 +492,10 @@
         return reply.readInt32();
     }
 
-    virtual status_t getMetrics(MediaAnalyticsItem *item) {
+    virtual status_t getMetrics(os::PersistableBundle *metrics) {
+        if (metrics == NULL) {
+            return BAD_VALUE;
+        }
         Parcel data, reply;
         data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
 
@@ -500,9 +503,23 @@
         if (status != OK) {
             return status;
         }
+        // The reply data is ordered as
+        // 1) 32 bit integer reply followed by
+        // 2) Serialized PersistableBundle containing metrics.
+        status_t reply_status;
+        if (reply.readInt32(&reply_status) != OK
+           || reply_status != OK) {
+          ALOGE("Failed to read getMetrics response code from parcel. %d",
+                reply_status);
+          return reply_status;
+        }
 
-        item->readFromParcel(reply);
-        return reply.readInt32();
+        status = metrics->readFromParcel(&reply);
+        if (status != OK) {
+            ALOGE("Failed to read metrics from parcel. %d", status);
+            return status;
+        }
+        return reply_status;
     }
 
     virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
@@ -1008,11 +1025,18 @@
         {
             CHECK_INTERFACE(IDrm, data, reply);
 
-            MediaAnalyticsItem item;
-            status_t result = getMetrics(&item);
-            item.writeToParcel(reply);
-            reply->writeInt32(result);
-            return OK;
+            os::PersistableBundle metrics;
+            status_t result = getMetrics(&metrics);
+            // The reply data is ordered as
+            // 1) 32 bit integer reply followed by
+            // 2) Serialized PersistableBundle containing metrics.
+            // Only write the metrics if the getMetrics result was
+            // OK and we successfully added the status to reply.
+            status_t parcel_result = reply->writeInt32(result);
+            if (result == OK && parcel_result == OK) {
+                parcel_result = metrics.writeToParcel(reply);
+            }
+            return parcel_result;
         }
 
         case SET_CIPHER_ALGORITHM:
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 26c8427..6c97f2b 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -23,7 +23,7 @@
 
 #include <media/MediaAnalyticsItem.h>
 
-#include "protos/plugin_metrics.pb.h"
+#include "protos/metrics.pb.h"
 
 namespace android {
 
diff --git a/drm/libmediadrm/protos/metrics.proto b/drm/libmediadrm/protos/metrics.proto
new file mode 100644
index 0000000..aa26f5f
--- /dev/null
+++ b/drm/libmediadrm/protos/metrics.proto
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.drm_metrics;
+
+// The MetricsGroup is a collection of metric name/value pair instances
+// that can be serialized and provided to a caller.
+message MetricsGroup {
+  message Metric {
+    message MetricValue {
+      // Exactly one of the following values must be set.
+      optional int64 int_value = 1;
+      optional double double_value = 2;
+      optional string string_value = 3;
+    }
+
+    // The name of the metric. Must be valid UTF-8. Required.
+    optional string name = 1;
+
+    // The value of the metric. Required.
+    optional MetricValue value = 2;
+  }
+
+  // The list of name/value pairs of metrics.
+  repeated Metric metric = 1;
+
+  // Allow multiple sub groups of metrics.
+  repeated MetricsGroup metric_sub_group = 2;
+
+  // Name of the application package associated with the metrics.
+  optional string app_package_name = 3;
+}
+
+// This message contains the specific metrics captured by DrmMetrics. It is
+// used for serializing and logging metrics.
+// next id: 11.
+message DrmFrameworkMetrics {
+  // TODO: Consider using extensions.
+
+  // Attributes are associated with a recorded value. E.g. A counter may
+  // represent a count of an operation returning a specific error code. The
+  // error code will be an attribute.
+  message Attributes {
+    // Reserved for compatibility with logging proto.
+    reserved 2 to 13;
+
+    // A general purpose error code where 0 means OK.
+    optional int32 error_code = 1;
+
+    // Defined at ::android::hardware::drm::V1_0::KeyStatusType;
+    optional uint32 key_status_type = 14;
+
+    // Defined at ::android::hardware::drm::V1_0::EventType;
+    optional uint32 event_type = 15;
+  }
+
+  // The Counter message is used to store a count value with an associated
+  // Attribute.
+  message Counter {
+    optional int64 count = 1;
+    // Represents the attributes associated with this counter instance.
+    optional Attributes attributes = 2;
+  }
+
+  // The DistributionMetric is meant to capture the moments of a normally
+  // distributed (or approximately normal) value.
+  message DistributionMetric {
+    optional double min = 1;
+    optional double max = 2;
+    optional double mean = 3;
+    optional double variance = 4;
+    optional double operation_count = 5;
+
+    // Represents the attributes assocated with this distribution metric
+    // instance.
+    optional Attributes attributes = 6;
+  }
+
+  message SessionLifetime {
+    // Start time of the session in milliseconds since epoch.
+    optional int64 start_time_ms = 1;
+    // End time of the session in milliseconds since epoch.
+    optional int64 end_time_ms = 2;
+  }
+
+  // The count of open session operations. Each instance has a specific error
+  // code associated with it.
+  repeated Counter open_session_counter = 1;
+
+  // The count of close session operations. Each instance has a specific error
+  // code associated with it.
+  repeated Counter close_session_counter = 2;
+
+  // Count and execution time of getKeyRequest calls.
+  repeated DistributionMetric get_key_request_time_us = 3;
+
+  // Count and execution time of provideKeyResponse calls.
+  repeated DistributionMetric provide_key_response_time_us = 4;
+
+  // Count of getProvisionRequest calls.
+  repeated Counter get_provisioning_request_counter = 5;
+
+  // Count of provideProvisionResponse calls.
+  repeated Counter provide_provisioning_response_counter = 6;
+
+  // Count of key status events broken out by status type.
+  repeated Counter key_status_change_counter = 7;
+
+  // Count of events broken out by event type
+  repeated Counter event_callback_counter = 8;
+
+  // Count getPropertyByteArray calls to retrieve the device unique id.
+  repeated Counter get_device_unique_id_counter = 9;
+
+  // Session ids to lifetime (start and end time) map.
+  // Session ids are strings of hex-encoded byte arrays.
+  map<string, SessionLifetime> session_lifetimes = 10;
+}
+
diff --git a/drm/libmediadrm/protos/plugin_metrics.proto b/drm/libmediadrm/protos/plugin_metrics.proto
deleted file mode 100644
index 7e3bcf5..0000000
--- a/drm/libmediadrm/protos/plugin_metrics.proto
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- */
-
-syntax = "proto2";
-
-package android.drm_metrics;
-
-// need this if we are using libprotobuf-cpp-2.3.0-lite
-option optimize_for = LITE_RUNTIME;
-
-// The MetricsGroup is a collection of metric name/value pair instances
-// that can be serialized and provided to a caller.
-message MetricsGroup {
-  message Metric {
-    message MetricValue {
-      // Exactly one of the following values must be set.
-      optional int64 int_value = 1;
-      optional double double_value = 2;
-      optional string string_value = 3;
-    }
-
-    // The name of the metric. Must be valid UTF-8. Required.
-    optional string name = 1;
-
-    // The value of the metric. Required.
-    optional MetricValue value = 2;
-  }
-
-  // The list of name/value pairs of metrics.
-  repeated Metric metric = 1;
-
-  // Allow multiple sub groups of metrics.
-  repeated MetricsGroup metric_sub_group = 2;
-
-  // Name of the application package associated with the metrics.
-  optional string app_package_name = 3;
-}
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
index fdc982d..670d3b9 100644
--- a/drm/libmediadrm/tests/Android.bp
+++ b/drm/libmediadrm/tests/Android.bp
@@ -16,16 +16,23 @@
     srcs: ["DrmMetrics_test.cpp"],
     shared_libs: [
       "android.hardware.drm@1.0",
+      "libbinder",
       "liblog",
-      "libmediadrm",
+      "libmediadrmmetrics_full",
       "libmediametrics",
+      "libprotobuf-cpp-full",
       "libutils",
     ],
-    include_dirs: ["frameworks/av/include/media"],
-    cflags: [
-      "-Werror",
-      "-Wall",
+    static_libs: ["libgmock"],
+    include_dirs: [
+      "frameworks/av/include/media",
     ],
+    cflags: [
+        // Suppress unused parameter and no error options. These cause problems
+        // when using the map type in a proto definition.
+        "-Wno-unused-parameter",
+        "-Wno-error",
+    ]
 }
 
 cc_test {
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp
index d1948b4..fe762c9 100644
--- a/drm/libmediadrm/tests/DrmMetrics_test.cpp
+++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp
@@ -14,27 +14,48 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
+#define LOG_TAG "DrmMetricsTest"
 #include "DrmMetrics.h"
 
+#include <binder/PersistableBundle.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/message_differencer.h>
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include "protos/metrics.pb.h"
+
+using ::android::drm_metrics::DrmFrameworkMetrics;
 using ::android::hardware::drm::V1_0::EventType;
 using ::android::hardware::drm::V1_0::KeyStatusType;
+using ::android::os::PersistableBundle;
+using ::google::protobuf::util::MessageDifferencer;
+using ::google::protobuf::TextFormat;
 
 namespace android {
 
 /**
  * Unit tests for the MediaDrmMetrics class.
  */
-class MediaDrmMetricsTest : public ::testing::Test {
+class MediaDrmMetricsTest : public ::testing::Test {};
+
+/**
+ * This derived class mocks the clock for testing purposes.
+ */
+class FakeMediaDrmMetrics : public MediaDrmMetrics {
+ public:
+  FakeMediaDrmMetrics() : MediaDrmMetrics(), time_(0) {};
+
+  int64_t GetCurrentTimeMs() { return time_++; }
+  int64_t time_;
 };
 
 TEST_F(MediaDrmMetricsTest, EmptySuccess) {
   MediaDrmMetrics metrics;
-  MediaAnalyticsItem item;
+  PersistableBundle bundle;
 
-  metrics.Export(&item);
-  EXPECT_EQ(0, item.count());
+  metrics.Export(&bundle);
+  EXPECT_TRUE(bundle.empty());
 }
 
 TEST_F(MediaDrmMetricsTest, AllValuesSuccessCounts) {
@@ -44,9 +65,9 @@
   metrics.mCloseSessionCounter.Increment(OK);
 
   {
-    EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTiming);
+    EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs);
     EventTimer<status_t> provide_key_response_timer(
-        &metrics.mProvideKeyResponseTiming);
+        &metrics.mProvideKeyResponseTimeUs);
     get_key_request_timer.SetAttribute(OK);
     provide_key_response_timer.SetAttribute(OK);
   }
@@ -58,10 +79,10 @@
   metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
   metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
 
-  MediaAnalyticsItem item;
+  PersistableBundle bundle;
 
-  metrics.Export(&item);
-  EXPECT_EQ(11, item.count());
+  metrics.Export(&bundle);
+  EXPECT_EQ(11U, bundle.size());
 
   // Verify the list of pairs of int64 metrics.
   std::vector<std::pair<std::string, int64_t>> expected_values = {
@@ -75,24 +96,24 @@
       { "drm.mediadrm.event.PROVISION_REQUIRED.count", 1 },
       { "drm.mediadrm.get_device_unique_id.ok.count", 1 }};
   for (const auto& expected_pair : expected_values) {
+    String16 key(expected_pair.first.c_str());
     int64_t value = -1;
-    EXPECT_TRUE(item.getInt64(expected_pair.first.c_str(), &value))
-        << "Failed to get " << expected_pair.first;
+    EXPECT_TRUE(bundle.getLong(key, &value))
+        << "Unexpected error retrieviing key: " << key;
     EXPECT_EQ(expected_pair.second, value)
-        << "Unexpected value for " << expected_pair.first;
+        << "Unexpected value for " << expected_pair.first << ". " << value;
   }
 
   // Validate timing values exist.
+  String16 get_key_request_key(
+      "drm.mediadrm.get_key_request.ok.average_time_micros");
+  String16 provide_key_response_key(
+      "drm.mediadrm.provide_key_response.ok.average_time_micros");
   int64_t value = -1;
-  EXPECT_TRUE(
-      item.getInt64("drm.mediadrm.get_key_request.ok.average_time_micros",
-                    &value));
+  EXPECT_TRUE(bundle.getLong(get_key_request_key, &value));
   EXPECT_GE(value, 0);
-
   value = -1;
-  EXPECT_TRUE(
-      item.getInt64("drm.mediadrm.provide_key_response.ok.average_time_micros",
-                    &value));
+  EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value));
   EXPECT_GE(value, 0);
 }
 
@@ -107,9 +128,9 @@
 
   for (status_t s : {OK, UNEXPECTED_NULL}) {
     {
-      EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTiming);
+      EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs);
       EventTimer<status_t> provide_key_response_timer(
-          &metrics.mProvideKeyResponseTiming);
+          &metrics.mProvideKeyResponseTimeUs);
       get_key_request_timer.SetAttribute(s);
       provide_key_response_timer.SetAttribute(s);
     }
@@ -133,10 +154,23 @@
   metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
   metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
 
-  MediaAnalyticsItem item;
+  android::Vector<uint8_t> sessionId1;
+  sessionId1.push_back(1);
+  sessionId1.push_back(2);
+  android::Vector<uint8_t> sessionId2;
+  sessionId2.push_back(3);
+  sessionId2.push_back(4);
+  String16 hexSessionId1("0102");
+  String16 hexSessionId2("0304");
 
-  metrics.Export(&item);
-  EXPECT_EQ(26, item.count());
+  metrics.SetSessionStart(sessionId1);
+  metrics.SetSessionStart(sessionId2);
+  metrics.SetSessionEnd(sessionId2);
+  metrics.SetSessionEnd(sessionId1);
+
+  PersistableBundle bundle;
+  metrics.Export(&bundle);
+  EXPECT_EQ(35U, bundle.size());
 
   // Verify the list of pairs of int64 metrics.
   std::vector<std::pair<std::string, int64_t>> expected_values = {
@@ -165,25 +199,217 @@
       { "drm.mediadrm.event.VENDOR_DEFINED.count", 1 },
       { "drm.mediadrm.event.SESSION_RECLAIMED.count", 1 }};
   for (const auto& expected_pair : expected_values) {
+    String16 key(expected_pair.first.c_str());
     int64_t value = -1;
-    EXPECT_TRUE(item.getInt64(expected_pair.first.c_str(), &value))
-        << "Failed to get " << expected_pair.first;
+    EXPECT_TRUE(bundle.getLong(key, &value))
+        << "Unexpected error retrieviing key: " << key;
     EXPECT_EQ(expected_pair.second, value)
-        << "Unexpected value for " << expected_pair.first;
+        << "Unexpected value for " << expected_pair.first << ". " << value;
+  }
+
+  // Verify the error lists
+  std::vector<std::pair<std::string, std::vector<int64_t>>> expected_vector_values = {
+      { "drm.mediadrm.close_session.error.list", { UNEXPECTED_NULL } },
+      { "drm.mediadrm.get_device_unique_id.error.list", { UNEXPECTED_NULL } },
+      { "drm.mediadrm.get_key_request.error.list", { UNEXPECTED_NULL } },
+      { "drm.mediadrm.get_provision_request.error.list", { UNEXPECTED_NULL } },
+      { "drm.mediadrm.open_session.error.list", { UNEXPECTED_NULL } },
+      { "drm.mediadrm.provide_key_response.error.list", { UNEXPECTED_NULL } },
+      { "drm.mediadrm.provide_provision_response.error.list", { UNEXPECTED_NULL } }};
+  for (const auto& expected_pair : expected_vector_values) {
+    String16 key(expected_pair.first.c_str());
+    std::vector<int64_t> values;
+    EXPECT_TRUE(bundle.getLongVector(key, &values))
+        << "Unexpected error retrieviing key: " << key;
+    for (auto expected : expected_pair.second) {
+      EXPECT_TRUE(std::find(values.begin(), values.end(), expected) != values.end())
+          << "Could not find " << expected << " for key " << expected_pair.first;
+    }
+  }
+
+  // Verify the lifespans
+  PersistableBundle start_times;
+  PersistableBundle end_times;
+  String16 start_time_key("drm.mediadrm.session_start_times_ms");
+  String16 end_time_key("drm.mediadrm.session_end_times_ms");
+  ASSERT_TRUE(bundle.getPersistableBundle(start_time_key, &start_times));
+  ASSERT_TRUE(bundle.getPersistableBundle(end_time_key, &end_times));
+  EXPECT_EQ(2U, start_times.size());
+  EXPECT_EQ(2U, end_times.size());
+  int64_t start_time, end_time;
+  for (const auto& sid : { hexSessionId1, hexSessionId2 }) {
+    start_time = -1;
+    end_time = -1;
+    EXPECT_TRUE(start_times.getLong(sid, &start_time));
+    EXPECT_TRUE(end_times.getLong(sid, &end_time));
+    EXPECT_GT(start_time, 0);
+    EXPECT_GE(end_time, start_time);
   }
 
   // Validate timing values exist.
+  String16 get_key_request_key(
+      "drm.mediadrm.get_key_request.ok.average_time_micros");
+  String16 provide_key_response_key(
+      "drm.mediadrm.provide_key_response.ok.average_time_micros");
   int64_t value = -1;
-  EXPECT_TRUE(
-      item.getInt64("drm.mediadrm.get_key_request.ok.average_time_micros",
-                    &value));
+  EXPECT_TRUE(bundle.getLong(get_key_request_key, &value));
   EXPECT_GE(value, 0);
-
   value = -1;
-  EXPECT_TRUE(
-      item.getInt64("drm.mediadrm.provide_key_response.ok.average_time_micros",
-                    &value));
+  EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value));
   EXPECT_GE(value, 0);
 }
 
+
+TEST_F(MediaDrmMetricsTest, CounterValuesProtoSerialization) {
+  MediaDrmMetrics metrics;
+
+  metrics.mOpenSessionCounter.Increment(OK);
+  metrics.mOpenSessionCounter.Increment(UNEXPECTED_NULL);
+  metrics.mCloseSessionCounter.Increment(OK);
+  metrics.mCloseSessionCounter.Increment(UNEXPECTED_NULL);
+
+  metrics.mGetProvisionRequestCounter.Increment(OK);
+  metrics.mGetProvisionRequestCounter.Increment(UNEXPECTED_NULL);
+  metrics.mProvideProvisionResponseCounter.Increment(OK);
+  metrics.mProvideProvisionResponseCounter.Increment(UNEXPECTED_NULL);
+  metrics.mGetDeviceUniqueIdCounter.Increment(OK);
+  metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL);
+
+  metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE);
+  metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED);
+  metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED);
+  metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING);
+  metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR);
+  metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED);
+  metrics.mEventCounter.Increment(EventType::KEY_NEEDED);
+  metrics.mEventCounter.Increment(EventType::KEY_EXPIRED);
+  metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED);
+  metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED);
+
+  std::string serializedMetrics;
+  ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+  DrmFrameworkMetrics metricsProto;
+  ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+  std::string expectedMetrics =
+      "open_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+      "open_session_counter { count: 1 attributes { error_code: 0 } } "
+      "close_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+      "close_session_counter { count: 1 attributes { error_code: 0 } } "
+      "get_provisioning_request_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } "
+      "get_provisioning_request_counter { count: 1 attributes { error_code: 0 } } "
+      "provide_provisioning_response_counter { count: 1 attributes { error_code: -0x7ffffff8 } } "
+      "provide_provisioning_response_counter { count: 1 attributes { error_code: 0 } } "
+      "get_device_unique_id_counter { count: 1 attributes { error_code: -0x7ffffff8 } } "
+      "get_device_unique_id_counter { count: 1 attributes { error_code: 0 } } "
+      "key_status_change_counter { count: 1 attributes { key_status_type: 0 } } "
+      "key_status_change_counter { count: 1 attributes { key_status_type: 1 } } "
+      "key_status_change_counter { count: 1 attributes { key_status_type: 2 } } "
+      "key_status_change_counter { count: 1 attributes { key_status_type: 3 } } "
+      "key_status_change_counter { count: 1 attributes { key_status_type: 4 } } "
+      "event_callback_counter { count: 1 attributes { event_type: 0 } } "
+      "event_callback_counter { count: 1 attributes { event_type: 1 } } "
+      "event_callback_counter { count: 1 attributes { event_type: 2 } } "
+      "event_callback_counter { count: 1 attributes { event_type: 3 } } "
+      "event_callback_counter { count: 1 attributes { event_type: 4 } } ";
+
+  DrmFrameworkMetrics expectedMetricsProto;
+  ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+  std::string diffString;
+  MessageDifferencer differ;
+  differ.ReportDifferencesToString(&diffString);
+  ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+      << diffString;
+}
+
+TEST_F(MediaDrmMetricsTest, TimeMetricsProtoSerialization) {
+  MediaDrmMetrics metrics;
+
+  for (status_t s : {OK, UNEXPECTED_NULL}) {
+    double time = 0;
+    for (int i = 0; i < 5; i++) {
+      time += 1.0;
+      metrics.mGetKeyRequestTimeUs.Record(time, s);
+      metrics.mProvideKeyResponseTimeUs.Record(time, s);
+    }
+  }
+
+  std::string serializedMetrics;
+  ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+  DrmFrameworkMetrics metricsProto;
+  ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+  std::string expectedMetrics =
+      "get_key_request_timing { "
+      "  min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+      "  attributes { error_code: -0x7FFFFFF8 } "
+      "} "
+      "get_key_request_timing { "
+      "  min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+      "  attributes { error_code: 0 } "
+      "} "
+      "provide_key_response_timing { "
+      "  min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+      "  attributes { error_code: -0x7FFFFFF8 } "
+      "} "
+      "provide_key_response_timing { "
+      "  min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 "
+      "  attributes { error_code: 0 } "
+      "} ";
+
+  DrmFrameworkMetrics expectedMetricsProto;
+  ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+  std::string diffString;
+  MessageDifferencer differ;
+  differ.ReportDifferencesToString(&diffString);
+  ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+      << diffString;
+}
+
+TEST_F(MediaDrmMetricsTest, SessionLifetimeProtoSerialization) {
+  // Use the fake so the clock is predictable;
+  FakeMediaDrmMetrics metrics;
+
+  android::Vector<uint8_t> sessionId1;
+  sessionId1.push_back(1);
+  sessionId1.push_back(2);
+  android::Vector<uint8_t> sessionId2;
+  sessionId2.push_back(3);
+  sessionId2.push_back(4);
+
+  metrics.SetSessionStart(sessionId1);
+  metrics.SetSessionStart(sessionId2);
+  metrics.SetSessionEnd(sessionId2);
+  metrics.SetSessionEnd(sessionId1);
+
+  std::string serializedMetrics;
+  ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics));
+
+  DrmFrameworkMetrics metricsProto;
+  ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics));
+
+  std::string expectedMetrics =
+      "session_lifetimes: { "
+      "  key: '0102' "
+      "  value { start_time_ms: 0 end_time_ms: 3 } "
+      "} "
+      "session_lifetimes: { "
+      "  key: '0304' "
+      "  value { start_time_ms: 1 end_time_ms: 2 } "
+      "} ";
+
+  DrmFrameworkMetrics expectedMetricsProto;
+  ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto));
+
+  std::string diffString;
+  MessageDifferencer differ;
+  differ.ReportDifferencesToString(&diffString);
+  ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto))
+      << diffString;
+}
+
 }  // namespace android
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index d921d9e..6b0201a 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -110,6 +110,38 @@
     return Status::ERROR_DRM_SESSION_NOT_OPENED;
 }
 
+Status DrmPlugin::getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
+        const hidl_vec<uint8_t>& initData,
+        const hidl_string& mimeType,
+        KeyType keyType,
+        const hidl_vec<KeyValue>& optionalParameters,
+        std::vector<uint8_t> *request,
+        KeyRequestType *keyRequestType,
+        std::string *defaultUrl) {
+        UNUSED(optionalParameters);
+
+    *defaultUrl = "";
+    *keyRequestType = KeyRequestType::UNKNOWN;
+    *request = std::vector<uint8_t>();
+
+    if (scope.size() == 0) {
+        return Status::BAD_VALUE;
+    }
+
+    if (keyType != KeyType::STREAMING) {
+        return Status::ERROR_DRM_CANNOT_HANDLE;
+    }
+
+    sp<Session> session = mSessionLibrary->findSession(toVector(scope));
+    if (!session.get()) {
+        return Status::ERROR_DRM_SESSION_NOT_OPENED;
+    }
+
+    Status status = session->getKeyRequest(initData, mimeType, request);
+    *keyRequestType = KeyRequestType::INITIAL;
+    return status;
+}
+
 Return<void> DrmPlugin::getKeyRequest(
         const hidl_vec<uint8_t>& scope,
         const hidl_vec<uint8_t>& initData,
@@ -119,29 +151,16 @@
         getKeyRequest_cb _hidl_cb) {
     UNUSED(optionalParameters);
 
-    if (scope.size() == 0) {
-        // Returns empty keyRequest, unknown keyType and empty defaultUrl
-        _hidl_cb(Status::BAD_VALUE, hidl_vec<uint8_t>(),
-                KeyRequestType::UNKNOWN, "");
-        return Void();
-    }
-
-    if (keyType != KeyType::STREAMING) {
-        _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, hidl_vec<uint8_t>(),
-                KeyRequestType::UNKNOWN, "");
-        return Void();
-    }
-
-    sp<Session> session = mSessionLibrary->findSession(toVector(scope));
-    if (!session.get()) {
-        _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, hidl_vec<uint8_t>(),
-                KeyRequestType::UNKNOWN, "");
-        return Void();
-    }
-
+    KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+    std::string defaultUrl("");
     std::vector<uint8_t> request;
-    Status status = session->getKeyRequest(initData, mimeType, &request);
-    _hidl_cb(status, toHidlVec(request), KeyRequestType::INITIAL, "");
+    Status status = getKeyRequestCommon(
+            scope, initData, mimeType, keyType, optionalParameters,
+            &request, &keyRequestType, &defaultUrl);
+
+    _hidl_cb(status, toHidlVec(request),
+            static_cast<drm::V1_0::KeyRequestType>(keyRequestType),
+            hidl_string(defaultUrl));
     return Void();
 }
 
@@ -152,23 +171,16 @@
         KeyType keyType,
         const hidl_vec<KeyValue>& optionalParameters,
         getKeyRequest_1_1_cb _hidl_cb) {
-    hidl_string defaultUrl;
-    hidl_vec<uint8_t> request;
-    ::android::hardware::drm::V1_1::KeyRequestType requestType =
-            static_cast<::android::hardware::drm::V1_1::KeyRequestType>(KeyRequestType::UNKNOWN);
-    Status status = Status::OK;
+    UNUSED(optionalParameters);
 
-    defaultUrl.clear();
-    getKeyRequest(scope, initData, mimeType, keyType, optionalParameters,
-            [&](Status statusCode, const hidl_vec<uint8_t>& hResult,
-            KeyRequestType hKeyRequestType,
-            const hidl_string& hDefaultUrl) {
-        defaultUrl = hDefaultUrl;
-        request = hResult;
-        requestType = static_cast<::android::hardware::drm::V1_1::KeyRequestType>(hKeyRequestType);
-        status = statusCode;
-    });
-    _hidl_cb(status, request, requestType, defaultUrl);
+    KeyRequestType keyRequestType = KeyRequestType::UNKNOWN;
+    std::string defaultUrl("");
+    std::vector<uint8_t> request;
+    Status status = getKeyRequestCommon(
+            scope, initData, mimeType, keyType, optionalParameters,
+            &request, &keyRequestType, &defaultUrl);
+
+    _hidl_cb(status, toHidlVec(request), keyRequestType, hidl_string(defaultUrl));
     return Void();
 }
 
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
index 5d12598..19baf0b 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/DrmPlugin.h
@@ -31,7 +31,6 @@
 
 using ::android::hardware::drm::V1_0::EventType;
 using ::android::hardware::drm::V1_0::IDrmPluginListener;
-using ::android::hardware::drm::V1_0::KeyRequestType;
 using ::android::hardware::drm::V1_0::KeyStatus;
 using ::android::hardware::drm::V1_0::KeyType;
 using ::android::hardware::drm::V1_0::KeyValue;
@@ -39,6 +38,8 @@
 using ::android::hardware::drm::V1_0::SecureStopId;
 using ::android::hardware::drm::V1_0::Status;
 using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::hardware::drm::V1_1::IDrmPlugin;
+using ::android::hardware::drm::V1_1::KeyRequestType;
 
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
@@ -46,7 +47,6 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-
 struct DrmPlugin : public IDrmPlugin {
     explicit DrmPlugin(SessionLibrary* sessionLibrary);
 
@@ -335,6 +335,15 @@
     Return<Status> setSecurityLevel(const hidl_vec<uint8_t>& sessionId,
             SecurityLevel level);
 
+    Status getKeyRequestCommon(const hidl_vec<uint8_t>& scope,
+            const hidl_vec<uint8_t>& initData,
+            const hidl_string& mimeType,
+            KeyType keyType,
+            const hidl_vec<KeyValue>& optionalParameters,
+            std::vector<uint8_t> *request,
+            KeyRequestType *getKeyRequestType,
+            std::string *defaultUrl);
+
     std::vector<KeyValue> mPlayPolicy;
     std::map<std::string, std::string> mStringProperties;
     std::map<std::string, std::vector<uint8_t> > mByteArrayProperties;
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index ff440bc..b4fa3c5 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -438,7 +438,11 @@
         return 0;
     }
 
-    virtual uint32_t    getUnderrunFrames() const {
+    virtual uint32_t getUnderrunFrames() const override {
+        return 0;
+    }
+
+    virtual uint32_t getUnderrunCount() const override {
         return 0;
     }
 
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 1614ca4..f6c8664 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -46,7 +46,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
     virtual ~AACSource();
@@ -259,7 +259,7 @@
 
     mCurrentTimeUs = 0;
     mGroup = new MediaBufferGroup;
-    mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+    mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
     mStarted = true;
 
     return OK;
@@ -280,7 +280,7 @@
 }
 
 status_t AACSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
@@ -303,7 +303,7 @@
         return ERROR_END_OF_STREAM;
     }
 
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
         return err;
@@ -333,13 +333,20 @@
 
 static MediaExtractor* CreateExtractor(
         DataSourceBase *source,
-        const sp<AMessage>& meta) {
-    return new AACExtractor(source, meta);
+        void *meta) {
+    sp<AMessage> metaData = static_cast<AMessage *>(meta);
+    return new AACExtractor(source, metaData);
+}
+
+static void FreeMeta(void *meta) {
+    if (meta != nullptr) {
+        static_cast<AMessage *>(meta)->decStrong(nullptr);
+    }
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *meta) {
+        DataSourceBase *source, float *confidence, void **meta,
+        MediaExtractor::FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
 
     for (;;) {
@@ -377,11 +384,14 @@
 
     // ADTS syncword
     if ((header[0] == 0xff) && ((header[1] & 0xf6) == 0xf0)) {
-        *mimeType = MEDIA_MIMETYPE_AUDIO_AAC_ADTS;
         *confidence = 0.2;
 
-        *meta = new AMessage;
-        (*meta)->setInt64("offset", pos);
+        AMessage *msg = new AMessage;
+        msg->setInt64("offset", pos);
+        *meta = msg;
+        *freeMeta = &FreeMeta;
+        // ref count will be decreased in FreeMeta.
+        msg->incStrong(nullptr);
 
         return CreateExtractor;
     }
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index 547e3f5..59d9ef1 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -45,7 +45,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
     virtual ~AMRSource();
@@ -122,7 +122,7 @@
       mOffsetTableLength(0) {
     String8 mimeType;
     float confidence;
-    if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
+    if (!SniffAMR(mDataSource, &mimeType, &confidence)) {
         return;
     }
 
@@ -233,7 +233,7 @@
     mOffset = mIsWide ? 9 : 6;
     mCurrentTimeUs = 0;
     mGroup = new MediaBufferGroup;
-    mGroup->add_buffer(new MediaBuffer(128));
+    mGroup->add_buffer(MediaBufferBase::Create(128));
     mStarted = true;
 
     return OK;
@@ -254,7 +254,7 @@
 }
 
 status_t AMRSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
@@ -303,7 +303,7 @@
         return ERROR_MALFORMED;
     }
 
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
         return err;
@@ -339,8 +339,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffAMR(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
+        DataSourceBase *source, String8 *mimeType, float *confidence) {
     char header[9];
 
     if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
@@ -348,12 +347,16 @@
     }
 
     if (!memcmp(header, "#!AMR\n", 6)) {
-        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+        if (mimeType != nullptr) {
+            *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+        }
         *confidence = 0.5;
 
         return true;
     } else if (!memcmp(header, "#!AMR-WB\n", 9)) {
-        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+        if (mimeType != nullptr) {
+            *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+        }
         *confidence = 0.5;
 
         return true;
@@ -373,13 +376,13 @@
         "AMR Extractor",
         [](
                 DataSourceBase *source,
-                String8 *mimeType,
                 float *confidence,
-                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
-            if (SniffAMR(source, mimeType, confidence, meta)) {
+                void **,
+                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+            if (SniffAMR(source, nullptr, confidence)) {
                 return [](
                         DataSourceBase *source,
-                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                        void *) -> MediaExtractor* {
                     return new AMRExtractor(source);};
             }
             return NULL;
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index d6d49f2..b8b44ea 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -55,8 +55,7 @@
 };
 
 bool SniffAMR(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
+        DataSourceBase *source, String8 *mimeType, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 8dbb5a1..2c5e43e 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -31,7 +31,7 @@
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
 
 namespace android {
 
@@ -173,7 +173,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
     virtual ~FLACSource();
@@ -232,10 +232,10 @@
     // media buffers
     void allocateBuffers();
     void releaseBuffers();
-    MediaBuffer *readBuffer() {
+    MediaBufferBase *readBuffer() {
         return readBuffer(false, 0LL);
     }
-    MediaBuffer *readBuffer(FLAC__uint64 sample) {
+    MediaBufferBase *readBuffer(FLAC__uint64 sample) {
         return readBuffer(true, sample);
     }
 
@@ -274,7 +274,7 @@
     FLAC__StreamDecoderErrorStatus mErrorStatus;
 
     status_t init();
-    MediaBuffer *readBuffer(bool doSeek, FLAC__uint64 sample);
+    MediaBufferBase *readBuffer(bool doSeek, FLAC__uint64 sample);
 
     // no copy constructor or assignment
     FLACParser(const FLACParser &);
@@ -763,7 +763,7 @@
     CHECK(mGroup == NULL);
     mGroup = new MediaBufferGroup;
     mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
-    mGroup->add_buffer(new MediaBuffer(mMaxBufferSize));
+    mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
 }
 
 void FLACParser::releaseBuffers()
@@ -773,7 +773,7 @@
     mGroup = NULL;
 }
 
-MediaBuffer *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
+MediaBufferBase *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample)
 {
     mWriteRequested = true;
     mWriteCompleted = false;
@@ -810,7 +810,7 @@
     }
     // acquire a media buffer
     CHECK(mGroup != NULL);
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
         return NULL;
@@ -881,9 +881,9 @@
 }
 
 status_t FLACSource::read(
-        MediaBuffer **outBuffer, const ReadOptions *options)
+        MediaBufferBase **outBuffer, const ReadOptions *options)
 {
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     // process an optional seek request
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
@@ -968,9 +968,7 @@
 
 // Sniffer
 
-bool SniffFLAC(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *)
+bool SniffFLAC(DataSourceBase *source, float *confidence)
 {
     // first 4 is the signature word
     // second 4 is the sizeof STREAMINFO
@@ -983,7 +981,6 @@
         return false;
     }
 
-    *mimeType = MEDIA_MIMETYPE_AUDIO_FLAC;
     *confidence = 0.5;
 
     return true;
@@ -1001,13 +998,13 @@
             "FLAC Extractor",
             [](
                     DataSourceBase *source,
-                    String8 *mimeType,
                     float *confidence,
-                    sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
-                if (SniffFLAC(source, mimeType, confidence, meta)) {
+                    void **,
+                    MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+                if (SniffFLAC(source, confidence)) {
                     return [](
                             DataSourceBase *source,
-                            const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                            void *) -> MediaExtractor* {
                         return new FLACExtractor(source);};
                 }
                 return NULL;
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index ef07212..f41d878 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -56,8 +56,7 @@
 
 };
 
-bool SniffFLAC(DataSourceBase *source, String8 *mimeType,
-        float *confidence, sp<AMessage> *);
+bool SniffFLAC(DataSourceBase *source, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 711c6a5..cf446db 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -30,7 +30,7 @@
 
 namespace android {
 
-// how many Sonivox output buffers to aggregate into one MediaBuffer
+// how many Sonivox output buffers to aggregate into one MediaBufferBase
 static const int NUM_COMBINE_BUFFERS = 4;
 
 class MidiSource : public MediaSourceBase {
@@ -45,7 +45,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
     virtual ~MidiSource();
@@ -114,10 +114,10 @@
 }
 
 status_t MidiSource::read(
-        MediaBuffer **outBuffer, const ReadOptions *options)
+        MediaBufferBase **outBuffer, const ReadOptions *options)
 {
     ALOGV("MidiSource::read");
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     // process an optional seek request
     int64_t seekTimeUs;
     ReadOptions::SeekMode mode;
@@ -207,7 +207,7 @@
     int bufsize = sizeof(EAS_PCM)
             * mEasConfig->mixBufferSize * mEasConfig->numChannels * NUM_COMBINE_BUFFERS;
     ALOGV("using %d byte buffer", bufsize);
-    mGroup->add_buffer(new MediaBuffer(bufsize));
+    mGroup->add_buffer(MediaBufferBase::Create(bufsize));
     return OK;
 }
 
@@ -223,13 +223,13 @@
     return result == EAS_SUCCESS ? OK : UNKNOWN_ERROR;
 }
 
-MediaBuffer* MidiEngine::readBuffer() {
+MediaBufferBase* MidiEngine::readBuffer() {
     EAS_STATE state;
     EAS_State(mEasData, mEasHandle, &state);
     if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) {
         return NULL;
     }
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
         ALOGE("readBuffer: no buffer");
@@ -307,13 +307,10 @@
 
 // Sniffer
 
-bool SniffMidi(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *)
+bool SniffMidi(DataSourceBase *source, float *confidence)
 {
     sp<MidiEngine> p = new MidiEngine(source, NULL, NULL);
     if (p->initCheck() == OK) {
-        *mimeType = MEDIA_MIMETYPE_AUDIO_MIDI;
         *confidence = 0.8;
         ALOGV("SniffMidi: yes");
         return true;
@@ -334,13 +331,13 @@
         "MIDI Extractor",
         [](
                 DataSourceBase *source,
-                String8 *mimeType,
                 float *confidence,
-                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
-            if (SniffMidi(source, mimeType, confidence, meta)) {
+                void **,
+                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+            if (SniffMidi(source, confidence)) {
                 return [](
                         DataSourceBase *source,
-                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                        void *) -> MediaExtractor* {
                     return new MidiExtractor(source);};
             }
             return NULL;
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 91efd06..4274513 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -19,7 +19,7 @@
 
 #include <media/DataSourceBase.h>
 #include <media/MediaExtractor.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/MidiIoWrapper.h>
 #include <utils/String8.h>
@@ -39,7 +39,7 @@
     status_t allocateBuffers();
     status_t releaseBuffers();
     status_t seekTo(int64_t positionUs);
-    MediaBuffer* readBuffer();
+    MediaBufferBase* readBuffer();
 private:
     sp<MidiIoWrapper> mIoWrapper;
     MediaBufferGroup *mGroup;
@@ -87,8 +87,7 @@
 
 };
 
-bool SniffMidi(DataSourceBase *source, String8 *mimeType,
-        float *confidence, sp<AMessage> *);
+bool SniffMidi(DataSourceBase *source, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index f61f7c7..65988d3 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -29,7 +29,7 @@
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/foundation/ColorUtils.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
@@ -130,7 +130,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options);
+            MediaBufferBase **buffer, const ReadOptions *options);
 
 protected:
     virtual ~MatroskaSource();
@@ -150,11 +150,11 @@
     BlockIterator mBlockIter;
     ssize_t mNALSizeLen;  // for type AVC or HEVC
 
-    List<MediaBuffer *> mPendingFrames;
+    List<MediaBufferBase *> mPendingFrames;
 
     status_t advance();
 
-    status_t setWebmBlockCryptoInfo(MediaBuffer *mbuf);
+    status_t setWebmBlockCryptoInfo(MediaBufferBase *mbuf);
     status_t readBlock();
     void clearPendingFrames();
 
@@ -568,7 +568,7 @@
 
 void MatroskaSource::clearPendingFrames() {
     while (!mPendingFrames.empty()) {
-        MediaBuffer *frame = *mPendingFrames.begin();
+        MediaBufferBase *frame = *mPendingFrames.begin();
         mPendingFrames.erase(mPendingFrames.begin());
 
         frame->release();
@@ -576,7 +576,7 @@
     }
 }
 
-status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBuffer *mbuf) {
+status_t MatroskaSource::setWebmBlockCryptoInfo(MediaBufferBase *mbuf) {
     if (mbuf->range_length() < 1 || mbuf->range_length() - 1 > INT32_MAX) {
         // 1-byte signal
         return ERROR_MALFORMED;
@@ -662,7 +662,7 @@
         }
 
         len += trackInfo->mHeaderLen;
-        MediaBuffer *mbuf = new MediaBuffer(len);
+        MediaBufferBase *mbuf = MediaBufferBase::Create(len);
         uint8_t *data = static_cast<uint8_t *>(mbuf->data());
         if (trackInfo->mHeader) {
             memcpy(data, trackInfo->mHeader, trackInfo->mHeaderLen);
@@ -695,7 +695,7 @@
 }
 
 status_t MatroskaSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t targetSampleTimeUs = -1ll;
@@ -731,7 +731,7 @@
         }
     }
 
-    MediaBuffer *frame = *mPendingFrames.begin();
+    MediaBufferBase *frame = *mPendingFrames.begin();
     mPendingFrames.erase(mPendingFrames.begin());
 
     if ((mType != AVC && mType != HEVC) || mNALSizeLen == 0) {
@@ -760,7 +760,7 @@
     size_t srcSize = frame->range_length();
 
     size_t dstSize = 0;
-    MediaBuffer *buffer = NULL;
+    MediaBufferBase *buffer = NULL;
     uint8_t *dstPtr = NULL;
 
     for (int32_t pass = 0; pass < 2; ++pass) {
@@ -820,7 +820,7 @@
                 // each 4-byte nal size with a 4-byte start code
                 buffer = frame;
             } else {
-                buffer = new MediaBuffer(dstSize);
+                buffer = MediaBufferBase::Create(dstSize);
             }
 
             int64_t timeUs;
@@ -1548,8 +1548,7 @@
 }
 
 bool SniffMatroska(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
+        DataSourceBase *source, float *confidence) {
     DataSourceBaseReader reader(source);
     mkvparser::EBMLHeader ebmlHeader;
     long long pos;
@@ -1557,7 +1556,6 @@
         return false;
     }
 
-    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MATROSKA);
     *confidence = 0.6;
 
     return true;
@@ -1575,13 +1573,13 @@
         "Matroska Extractor",
         [](
                 DataSourceBase *source,
-                String8 *mimeType,
                 float *confidence,
-                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
-            if (SniffMatroska(source, mimeType, confidence, meta)) {
+                void **,
+                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+            if (SniffMatroska(source, confidence)) {
                 return [](
                         DataSourceBase *source,
-                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                        void *) -> MediaExtractor* {
                     return new MatroskaExtractor(source);};
             }
             return NULL;
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 25d4deb..90ee653 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -30,7 +30,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -222,7 +222,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
     virtual ~MP3Source();
@@ -463,7 +463,7 @@
 
     mGroup = new MediaBufferGroup;
 
-    mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+    mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
 
     mCurrentPos = mFirstFramePos;
     mCurrentTimeUs = 0;
@@ -492,7 +492,7 @@
 }
 
 status_t MP3Source::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
@@ -522,7 +522,7 @@
         mSamplesRead = 0;
     }
 
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
         return err;
@@ -668,13 +668,20 @@
 
 static MediaExtractor* CreateExtractor(
         DataSourceBase *source,
-        const sp<AMessage>& meta) {
-    return new MP3Extractor(source, meta);
+        void *meta) {
+    sp<AMessage> metaData = static_cast<AMessage *>(meta);
+    return new MP3Extractor(source, metaData);
+}
+
+static void FreeMeta(void *meta) {
+    if (meta != nullptr) {
+        static_cast<AMessage *>(meta)->decStrong(nullptr);
+    }
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source, String8 *mimeType,
-        float *confidence, sp<AMessage> *meta) {
+        DataSourceBase *source, float *confidence, void **meta,
+        MediaExtractor::FreeMetaFunc *freeMeta) {
     off64_t pos = 0;
     off64_t post_id3_pos;
     uint32_t header;
@@ -691,12 +698,15 @@
         return NULL;
     }
 
-    *meta = new AMessage;
-    (*meta)->setInt64("offset", pos);
-    (*meta)->setInt32("header", header);
-    (*meta)->setInt64("post-id3-offset", post_id3_pos);
+    AMessage *msg = new AMessage;
+    msg->setInt64("offset", pos);
+    msg->setInt32("header", header);
+    msg->setInt64("post-id3-offset", post_id3_pos);
+    *meta = msg;
+    *freeMeta = &FreeMeta;
+    // ref count will be decreased in FreeMeta.
+    msg->incStrong(nullptr);
 
-    *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
     *confidence = 0.2f;
 
     return CreateExtractor;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 30dda13..40c84a5 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -41,7 +41,7 @@
 #include <media/stagefright/foundation/ColorUtils.h>
 #include <media/stagefright/foundation/avc_utils.h>
 #include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
@@ -83,9 +83,9 @@
 
     virtual sp<MetaData> getFormat();
 
-    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
     virtual bool supportNonblockingRead() { return true; }
-    virtual status_t fragmentedRead(MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t fragmentedRead(MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
     virtual ~MPEG4Source();
 
@@ -128,7 +128,7 @@
 
     MediaBufferGroup *mGroup;
 
-    MediaBuffer *mBuffer;
+    MediaBufferBase *mBuffer;
 
     bool mWantsNALFragments;
 
@@ -354,9 +354,7 @@
       mPreferHeif(mime != NULL && !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEIF)),
       mFirstTrack(NULL),
       mLastTrack(NULL),
-      mFileMetaData(new MetaData),
-      mFirstSINF(NULL),
-      mIsDrm(false) {
+      mFileMetaData(new MetaData) {
     ALOGV("mime=%s, mPreferHeif=%d", mime, mPreferHeif);
 }
 
@@ -370,15 +368,6 @@
     }
     mFirstTrack = mLastTrack = NULL;
 
-    SINF *sinf = mFirstSINF;
-    while (sinf) {
-        SINF *next = sinf->next;
-        delete[] sinf->IPMPData;
-        delete sinf;
-        sinf = next;
-    }
-    mFirstSINF = NULL;
-
     for (size_t i = 0; i < mPssh.size(); i++) {
         delete [] mPssh[i].data;
     }
@@ -672,177 +661,6 @@
     return mInitCheck;
 }
 
-char* MPEG4Extractor::getDrmTrackInfo(size_t trackID, int *len) {
-    if (mFirstSINF == NULL) {
-        return NULL;
-    }
-
-    SINF *sinf = mFirstSINF;
-    while (sinf && (trackID != sinf->trackID)) {
-        sinf = sinf->next;
-    }
-
-    if (sinf == NULL) {
-        return NULL;
-    }
-
-    *len = sinf->len;
-    return sinf->IPMPData;
-}
-
-// Reads an encoded integer 7 bits at a time until it encounters the high bit clear.
-static int32_t readSize(off64_t offset,
-        DataSourceBase *DataSourceBase, uint8_t *numOfBytes) {
-    uint32_t size = 0;
-    uint8_t data;
-    bool moreData = true;
-    *numOfBytes = 0;
-
-    while (moreData) {
-        if (DataSourceBase->readAt(offset, &data, 1) < 1) {
-            return -1;
-        }
-        offset ++;
-        moreData = (data >= 128) ? true : false;
-        size = (size << 7) | (data & 0x7f); // Take last 7 bits
-        (*numOfBytes) ++;
-    }
-
-    return size;
-}
-
-status_t MPEG4Extractor::parseDrmSINF(
-        off64_t * /* offset */, off64_t data_offset) {
-    uint8_t updateIdTag;
-    if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
-        return ERROR_IO;
-    }
-    data_offset ++;
-
-    if (0x01/*OBJECT_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
-        return ERROR_MALFORMED;
-    }
-
-    uint8_t numOfBytes;
-    int32_t size = readSize(data_offset, mDataSource, &numOfBytes);
-    if (size < 0) {
-        return ERROR_IO;
-    }
-    data_offset += numOfBytes;
-
-    while(size >= 11 ) {
-        uint8_t descriptorTag;
-        if (mDataSource->readAt(data_offset, &descriptorTag, 1) < 1) {
-            return ERROR_IO;
-        }
-        data_offset ++;
-
-        if (0x11/*OBJECT_DESCRIPTOR_ID_TAG*/ != descriptorTag) {
-            return ERROR_MALFORMED;
-        }
-
-        uint8_t buffer[8];
-        //ObjectDescriptorID and ObjectDescriptor url flag
-        if (mDataSource->readAt(data_offset, buffer, 2) < 2) {
-            return ERROR_IO;
-        }
-        data_offset += 2;
-
-        if ((buffer[1] >> 5) & 0x0001) { //url flag is set
-            return ERROR_MALFORMED;
-        }
-
-        if (mDataSource->readAt(data_offset, buffer, 8) < 8) {
-            return ERROR_IO;
-        }
-        data_offset += 8;
-
-        if ((0x0F/*ES_ID_REF_TAG*/ != buffer[1])
-                || ( 0x0A/*IPMP_DESCRIPTOR_POINTER_ID_TAG*/ != buffer[5])) {
-            return ERROR_MALFORMED;
-        }
-
-        SINF *sinf = new SINF;
-        sinf->trackID = U16_AT(&buffer[3]);
-        sinf->IPMPDescriptorID = buffer[7];
-        sinf->next = mFirstSINF;
-        mFirstSINF = sinf;
-
-        size -= (8 + 2 + 1);
-    }
-
-    if (size != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
-        return ERROR_IO;
-    }
-    data_offset ++;
-
-    if(0x05/*IPMP_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
-        return ERROR_MALFORMED;
-    }
-
-    size = readSize(data_offset, mDataSource, &numOfBytes);
-    if (size < 0) {
-        return ERROR_IO;
-    }
-    data_offset += numOfBytes;
-
-    while (size > 0) {
-        uint8_t tag;
-        int32_t dataLen;
-        if (mDataSource->readAt(data_offset, &tag, 1) < 1) {
-            return ERROR_IO;
-        }
-        data_offset ++;
-
-        if (0x0B/*IPMP_DESCRIPTOR_ID_TAG*/ == tag) {
-            uint8_t id;
-            dataLen = readSize(data_offset, mDataSource, &numOfBytes);
-            if (dataLen < 0) {
-                return ERROR_IO;
-            } else if (dataLen < 4) {
-                return ERROR_MALFORMED;
-            }
-            data_offset += numOfBytes;
-
-            if (mDataSource->readAt(data_offset, &id, 1) < 1) {
-                return ERROR_IO;
-            }
-            data_offset ++;
-
-            SINF *sinf = mFirstSINF;
-            while (sinf && (sinf->IPMPDescriptorID != id)) {
-                sinf = sinf->next;
-            }
-            if (sinf == NULL) {
-                return ERROR_MALFORMED;
-            }
-            sinf->len = dataLen - 3;
-            sinf->IPMPData = new (std::nothrow) char[sinf->len];
-            if (sinf->IPMPData == NULL) {
-                return ERROR_MALFORMED;
-            }
-            data_offset += 2;
-
-            if (mDataSource->readAt(data_offset, sinf->IPMPData, sinf->len) < sinf->len) {
-                return ERROR_IO;
-            }
-            data_offset += sinf->len;
-
-            size -= (dataLen + numOfBytes + 1);
-        }
-    }
-
-    if (size != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    return UNKNOWN_ERROR;  // Return a dummy error.
-}
-
 struct PathAdder {
     PathAdder(Vector<uint32_t> *path, uint32_t chunkType)
         : mPath(path) {
@@ -1144,11 +962,7 @@
             } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
                 mInitCheck = OK;
 
-                if (!mIsDrm) {
-                    return UNKNOWN_ERROR;  // Return a dummy error.
-                } else {
-                    return OK;
-                }
+                return UNKNOWN_ERROR;  // Return a dummy error.
             }
             break;
         }
@@ -1596,7 +1410,7 @@
             }
 
             if (chunk_type != FOURCC('e', 'n', 'c', 'a')) {
-                // if the chunk type is enca, we'll get the type from the sinf/frma box later
+                // if the chunk type is enca, we'll get the type from the frma box later
                 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
                 AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate);
             }
@@ -1656,7 +1470,7 @@
                 return ERROR_MALFORMED;
 
             if (chunk_type != FOURCC('e', 'n', 'c', 'v')) {
-                // if the chunk type is encv, we'll get the type from the sinf/frma box later
+                // if the chunk type is encv, we'll get the type from the frma box later
                 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
             }
             mLastTrack->meta->setInt32(kKeyWidth, width);
@@ -2278,20 +2092,10 @@
 
         case FOURCC('m', 'd', 'a', 't'):
         {
-            ALOGV("mdat chunk, drm: %d", mIsDrm);
-
             mMdatFound = true;
 
-            if (!mIsDrm) {
-                *offset += chunk_size;
-                break;
-            }
-
-            if (chunk_size < 8) {
-                return ERROR_MALFORMED;
-            }
-
-            return parseDrmSINF(offset, data_offset);
+            *offset += chunk_size;
+            break;
         }
 
         case FOURCC('h', 'd', 'l', 'r'):
@@ -4681,7 +4485,7 @@
 }
 
 status_t MPEG4Source::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     Mutex::Autolock autoLock(mLock);
 
     CHECK(mStarted);
@@ -4906,7 +4710,7 @@
             return ERROR_MALFORMED;
         }
 
-        MediaBuffer *clone = mBuffer->clone();
+        MediaBufferBase *clone = mBuffer->clone();
         CHECK(clone != NULL);
         clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);
 
@@ -5026,7 +4830,7 @@
 }
 
 status_t MPEG4Source::fragmentedRead(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
 
     ALOGV("MPEG4Source::fragmentedRead");
 
@@ -5230,7 +5034,7 @@
             return ERROR_MALFORMED;
         }
 
-        MediaBuffer *clone = mBuffer->clone();
+        MediaBufferBase *clone = mBuffer->clone();
         CHECK(clone != NULL);
         clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);
 
@@ -5382,8 +5186,7 @@
     return NULL;
 }
 
-static bool LegacySniffMPEG4(
-        DataSourceBase *source, String8 *mimeType, float *confidence) {
+static bool LegacySniffMPEG4(DataSourceBase *source, float *confidence) {
     uint8_t header[8];
 
     ssize_t n = source->readAt(4, header, sizeof(header));
@@ -5399,7 +5202,6 @@
         || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)
         || !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)
         || !memcmp(header, "ftypmsf1", 8) || !memcmp(header, "ftyphevc", 8)) {
-        *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
         *confidence = 0.4;
 
         return true;
@@ -5449,9 +5251,7 @@
 // Also try to identify where this file's metadata ends
 // (end of the 'moov' atom) and report it to the caller as part of
 // the metadata.
-static bool BetterSniffMPEG4(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *meta) {
+static bool BetterSniffMPEG4(DataSourceBase *source, float *confidence) {
     // We scan up to 128 bytes to identify this file as an MP4.
     static const off64_t kMaxScanOffset = 128ll;
 
@@ -5553,35 +5353,23 @@
         return false;
     }
 
-    *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
     *confidence = 0.4f;
 
-    if (moovAtomEndOffset >= 0) {
-        *meta = new AMessage;
-        (*meta)->setInt64("meta-data-size", moovAtomEndOffset);
-
-        ALOGV("found metadata size: %lld", (long long)moovAtomEndOffset);
-    }
-
     return true;
 }
 
-static MediaExtractor* CreateExtractor(
-        DataSourceBase *source,
-        const sp<AMessage>& meta __unused) {
+static MediaExtractor* CreateExtractor(DataSourceBase *source, void *) {
     return new MPEG4Extractor(source);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        DataSourceBase *source,
-        String8 *mimeType,
-        float *confidence,
-        sp<AMessage> *meta) {
-    if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
+        DataSourceBase *source, float *confidence, void **,
+        MediaExtractor::FreeMetaFunc *) {
+    if (BetterSniffMPEG4(source, confidence)) {
         return CreateExtractor;
     }
 
-    if (LegacySniffMPEG4(source, mimeType, confidence)) {
+    if (LegacySniffMPEG4(source, confidence)) {
         ALOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
         return CreateExtractor;
     }
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index 644c430..5c86345 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -63,9 +63,6 @@
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG4Extractor"; }
 
-    // for DRM
-    virtual char* getDrmTrackInfo(size_t trackID, int *len);
-
 protected:
     virtual ~MPEG4Extractor();
 
@@ -131,21 +128,8 @@
 
     static status_t verifyTrack(Track *track);
 
-    struct SINF {
-        SINF *next;
-        uint16_t trackID;
-        uint8_t IPMPDescriptorID;
-        ssize_t len;
-        char *IPMPData;
-    };
-
-    SINF *mFirstSINF;
-
-    bool mIsDrm;
     sp<ItemTable> mItemTable;
 
-    status_t parseDrmSINF(off64_t *offset, off64_t data_offset);
-
     status_t parseTrackHeader(off64_t data_offset, off64_t data_size);
 
     status_t parseSegmentIndex(off64_t data_offset, size_t data_size);
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 818f9b0..b012b5d 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -18,6 +18,7 @@
         "libbinder",
         "libcrypto",
         "libcutils",
+        "libhidlallocatorutils",
         "libhidlbase",
         "liblog",
         "libmediaextractor",
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index 443d685..8a0fa03 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -35,18 +35,18 @@
         "MPEG2-PS/TS Extractor",
         [](
                 DataSourceBase *source,
-                String8 *mimeType,
                 float *confidence,
-                sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
-            if (SniffMPEG2TS(source, mimeType, confidence, meta)) {
+                void **,
+                MediaExtractor::FreeMetaFunc *) -> MediaExtractor::CreatorFunc {
+            if (SniffMPEG2TS(source, confidence)) {
                 return [](
                         DataSourceBase *source,
-                        const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                        void *) -> MediaExtractor* {
                     return new MPEG2TSExtractor(source);};
-            } else if (SniffMPEG2PS(source, mimeType, confidence, meta)) {
+            } else if (SniffMPEG2PS(source, confidence)) {
                         return [](
                                 DataSourceBase *source,
-                                const sp<AMessage>& meta __unused) -> MediaExtractor* {
+                                void *) -> MediaExtractor* {
                             return new MPEG2PSExtractor(source);};
             }
             return NULL;
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 697e44f..c2de6e7 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -49,7 +49,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options);
+            MediaBufferBase **buffer, const ReadOptions *options);
 
 protected:
     virtual ~Track();
@@ -80,7 +80,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options);
+            MediaBufferBase **buffer, const ReadOptions *options);
 
 protected:
     virtual ~WrappedTrack();
@@ -659,7 +659,7 @@
 }
 
 status_t MPEG2PSExtractor::Track::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
+        MediaBufferBase **buffer, const ReadOptions *options) {
     if (mSource == NULL) {
         return NO_INIT;
     }
@@ -744,15 +744,14 @@
 }
 
 status_t MPEG2PSExtractor::WrappedTrack::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
+        MediaBufferBase **buffer, const ReadOptions *options) {
     return mTrack->read(buffer, options);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffMPEG2PS(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
+        DataSourceBase *source, float *confidence) {
     uint8_t header[5];
     if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return false;
@@ -764,8 +763,6 @@
 
     *confidence = 0.25f;  // Slightly larger than .mp3 extractor's confidence
 
-    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
-
     return true;
 }
 
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
index adf719a..2541f4d 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -71,9 +71,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2PSExtractor);
 };
 
-bool SniffMPEG2PS(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
+bool SniffMPEG2PS(DataSourceBase *source, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index a8a366b..7887a7c 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -61,7 +61,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 private:
     MPEG2TSExtractor *mExtractor;
@@ -99,7 +99,7 @@
 }
 
 status_t MPEG2TSSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
@@ -645,9 +645,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool SniffMPEG2TS(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
+bool SniffMPEG2TS(DataSourceBase *source, float *confidence) {
     for (int i = 0; i < 5; ++i) {
         char header;
         if (source->readAt(kTSPacketSize * i, &header, 1) != 1
@@ -657,7 +655,6 @@
     }
 
     *confidence = 0.1f;
-    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
 
     return true;
 }
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index fc15501..df07fac 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -99,9 +99,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSExtractor);
 };
 
-bool SniffMPEG2TS(
-        DataSourceBase *source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
+bool SniffMPEG2TS(DataSourceBase *source, float *confidence);
 
 }  // namespace android
 
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 1d04bed..6d7576f 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -27,7 +27,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/base64.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -54,7 +54,7 @@
     virtual status_t stop();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
     virtual ~OggSource();
@@ -82,7 +82,7 @@
 
     status_t seekToTime(int64_t timeUs);
     status_t seekToOffset(off64_t offset);
-    virtual status_t readNextPacket(MediaBuffer **buffer) = 0;
+    virtual status_t readNextPacket(MediaBufferBase **buffer) = 0;
 
     status_t init();
 
@@ -141,7 +141,7 @@
     // 1 - bitstream identification header
     // 3 - comment header
     // 5 - codec setup header (Vorbis only)
-    virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type) = 0;
+    virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type) = 0;
 
     // Read the next ogg packet from the underlying data source; optionally
     // calculate the timestamp for the output packet whilst pretending
@@ -149,9 +149,9 @@
     //
     // *buffer is NULL'ed out immediately upon entry, and if successful a new buffer is allocated;
     // clients are responsible for releasing the original buffer.
-    status_t _readNextPacket(MediaBuffer **buffer, bool calcVorbisTimestamp);
+    status_t _readNextPacket(MediaBufferBase **buffer, bool calcVorbisTimestamp);
 
-    int32_t getPacketBlockSize(MediaBuffer *buffer);
+    int32_t getPacketBlockSize(MediaBufferBase *buffer);
 
     void parseFileMetaData();
 
@@ -173,7 +173,7 @@
 
     virtual uint64_t approxBitrate() const;
 
-    virtual status_t readNextPacket(MediaBuffer **buffer) {
+    virtual status_t readNextPacket(MediaBufferBase **buffer) {
         return _readNextPacket(buffer, /* calcVorbisTimestamp = */ true);
     }
 
@@ -185,7 +185,7 @@
         return granulePos * 1000000ll / mVi.rate;
     }
 
-    virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type);
+    virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
 };
 
 struct MyOpusExtractor : public MyOggExtractor {
@@ -203,16 +203,16 @@
         return 0;
     }
 
-    virtual status_t readNextPacket(MediaBuffer **buffer);
+    virtual status_t readNextPacket(MediaBufferBase **buffer);
 
 protected:
     virtual int64_t getTimeUsOfGranule(uint64_t granulePos) const;
-    virtual status_t verifyHeader(MediaBuffer *buffer, uint8_t type);
+    virtual status_t verifyHeader(MediaBufferBase *buffer, uint8_t type);
 
 private:
-    status_t verifyOpusHeader(MediaBuffer *buffer);
-    status_t verifyOpusComments(MediaBuffer *buffer);
-    uint32_t getNumSamplesInPacket(MediaBuffer *buffer) const;
+    status_t verifyOpusHeader(MediaBufferBase *buffer);
+    status_t verifyOpusComments(MediaBufferBase *buffer);
+    uint32_t getNumSamplesInPacket(MediaBufferBase *buffer) const;
 
     uint8_t mChannelCount;
     uint16_t mCodecDelay;
@@ -256,7 +256,7 @@
 }
 
 status_t OggSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
@@ -268,7 +268,7 @@
         }
     }
 
-    MediaBuffer *packet;
+    MediaBufferBase *packet;
     status_t err = mExtractor->mImpl->readNextPacket(&packet);
 
     if (err != OK) {
@@ -562,13 +562,13 @@
     return sizeof(header) + page->mNumSegments + totalSize;
 }
 
-status_t MyOpusExtractor::readNextPacket(MediaBuffer **out) {
+status_t MyOpusExtractor::readNextPacket(MediaBufferBase **out) {
     if (mOffset <= mFirstDataOffset && mStartGranulePosition < 0) {
         // The first sample might not start at time 0; find out where by subtracting
         // the number of samples on the first page from the granule position
         // (position of last complete sample) of the first page. This happens
         // the first time before we attempt to read a packet from the first page.
-        MediaBuffer *mBuf;
+        MediaBufferBase *mBuf;
         uint32_t numSamples = 0;
         uint64_t curGranulePosition = 0;
         while (true) {
@@ -623,7 +623,7 @@
     return OK;
 }
 
-uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBuffer *buffer) const {
+uint32_t MyOpusExtractor::getNumSamplesInPacket(MediaBufferBase *buffer) const {
     if (buffer == NULL || buffer->range_length() < 1) {
         return 0;
     }
@@ -669,10 +669,10 @@
     return numSamples;
 }
 
-status_t MyOggExtractor::_readNextPacket(MediaBuffer **out, bool calcVorbisTimestamp) {
+status_t MyOggExtractor::_readNextPacket(MediaBufferBase **out, bool calcVorbisTimestamp) {
     *out = NULL;
 
-    MediaBuffer *buffer = NULL;
+    MediaBufferBase *buffer = NULL;
     int64_t timeUs = -1;
 
     for (;;) {
@@ -708,7 +708,7 @@
                 ALOGE("b/36592202");
                 return ERROR_MALFORMED;
             }
-            MediaBuffer *tmp = new (std::nothrow) MediaBuffer(fullSize);
+            MediaBufferBase *tmp = MediaBufferBase::Create(fullSize);
             if (tmp == NULL) {
                 if (buffer != NULL) {
                     buffer->release();
@@ -833,7 +833,7 @@
     mMeta->setCString(kKeyMIMEType, mMimeType);
 
     status_t err;
-    MediaBuffer *packet;
+    MediaBufferBase *packet;
     for (size_t i = 0; i < mNumHeaders; ++i) {
         // ignore timestamp for configuration packets
         if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != OK) {
@@ -910,7 +910,7 @@
     }
 }
 
-int32_t MyOggExtractor::getPacketBlockSize(MediaBuffer *buffer) {
+int32_t MyOggExtractor::getPacketBlockSize(MediaBufferBase *buffer) {
     const uint8_t *data =
         (const uint8_t *)buffer->data() + buffer->range_offset();
 
@@ -950,7 +950,7 @@
     return pcmSamplePosition * 1000000ll / kOpusSampleRate;
 }
 
-status_t MyOpusExtractor::verifyHeader(MediaBuffer *buffer, uint8_t type) {
+status_t MyOpusExtractor::verifyHeader(MediaBufferBase *buffer, uint8_t type) {
     switch (type) {
         // there are actually no header types defined in the Opus spec; we choose 1 and 3 to mean
         // header and comments such that we can share code with MyVorbisExtractor.
@@ -963,7 +963,7 @@
     }
 }
 
-status_t MyOpusExtractor::verifyOpusHeader(MediaBuffer *buffer) {
+status_t MyOpusExtractor::verifyOpusHeader(MediaBufferBase *buffer) {
     const size_t kOpusHeaderSize = 19;
     const uint8_t *data =
         (const uint8_t *)buffer->data() + buffer->range_offset();
@@ -989,7 +989,7 @@
     return OK;
 }
 
-status_t MyOpusExtractor::verifyOpusComments(MediaBuffer *buffer) {
+status_t MyOpusExtractor::verifyOpusComments(MediaBufferBase *buffer) {
     // add artificial framing bit so we can reuse _vorbis_unpack_comment
     int32_t commentSize = buffer->range_length() + 1;
     sp<ABuffer> aBuf = new ABuffer(commentSize);
@@ -1081,7 +1081,7 @@
 }
 
 status_t MyVorbisExtractor::verifyHeader(
-        MediaBuffer *buffer, uint8_t type) {
+        MediaBufferBase *buffer, uint8_t type) {
     const uint8_t *data =
         (const uint8_t *)buffer->data() + buffer->range_offset();
 
@@ -1371,21 +1371,20 @@
 
 static MediaExtractor* CreateExtractor(
         DataSourceBase *source,
-        const sp<AMessage>& meta __unused) {
+        void *) {
     return new OggExtractor(source);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
         DataSourceBase *source,
-        String8 *mimeType,
         float *confidence,
-        sp<AMessage> *) {
+        void **,
+        MediaExtractor::FreeMetaFunc *) {
     char tmp[4];
     if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
         return NULL;
     }
 
-    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
     *confidence = 0.2f;
 
     return CreateExtractor;
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 105a37f..a18cee5 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -68,7 +68,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
     virtual bool supportNonblockingRead() { return true; }
 
@@ -385,7 +385,7 @@
 
     if (mBitsPerSample == 8) {
         // As a temporary buffer for 8->16 bit conversion.
-        mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+        mGroup->add_buffer(MediaBufferBase::Create(kMaxFrameSize));
     }
 
     mCurrentPos = mOffset;
@@ -415,7 +415,7 @@
 }
 
 status_t WAVSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     if (options != nullptr && options->getNonBlocking() && !mGroup->has_buffers()) {
@@ -441,7 +441,7 @@
         mCurrentPos = pos + mOffset;
     }
 
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     status_t err = mGroup->acquire_buffer(&buffer);
     if (err != OK) {
         return err;
@@ -492,7 +492,7 @@
             // Convert 8-bit unsigned samples to 16-bit signed.
 
             // Create new buffer with 2 byte wide samples
-            MediaBuffer *tmp;
+            MediaBufferBase *tmp;
             CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
             tmp->set_range(0, 2 * n);
 
@@ -546,15 +546,15 @@
 
 static MediaExtractor* CreateExtractor(
         DataSourceBase *source,
-        const sp<AMessage>& meta __unused) {
+        void *) {
     return new WAVExtractor(source);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
         DataSourceBase *source,
-        String8 *mimeType,
         float *confidence,
-        sp<AMessage> *) {
+        void **,
+        MediaExtractor::FreeMetaFunc *) {
     char header[12];
     if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
         return NULL;
@@ -571,7 +571,6 @@
         return NULL;
     }
 
-    *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
     *confidence = 0.3f;
 
     return CreateExtractor;
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 2e29316..cf7d90f 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -46,10 +46,6 @@
 class AudioMixer
 {
 public:
-    // This mixer has a hard-coded upper limit of active track inputs;
-    // the value is arbitrary but should be less than TRACK0 to avoid confusion.
-    static constexpr int32_t MAX_NUM_TRACKS = 256;
-
     // Do not change these unless underlying code changes.
     // This mixer has a hard-coded upper limit of 8 channels for output.
     static constexpr uint32_t MAX_NUM_CHANNELS = FCC_8;
@@ -61,12 +57,6 @@
     static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
 
     enum { // names
-
-        // track names (MAX_NUM_TRACKS units)
-        TRACK0          = 0x1000,
-
-        // 0x2000 is unused
-
         // setParameter targets
         TRACK           = 0x3000,
         RESAMPLE        = 0x3001,
@@ -105,23 +95,33 @@
                                   // parameter 'value' is a pointer to the new playback rate.
     };
 
-    AudioMixer(size_t frameCount, uint32_t sampleRate, int32_t maxNumTracks = MAX_NUM_TRACKS)
-        : mMaxNumTracks(maxNumTracks)
-        , mSampleRate(sampleRate)
+    AudioMixer(size_t frameCount, uint32_t sampleRate)
+        : mSampleRate(sampleRate)
         , mFrameCount(frameCount) {
         pthread_once(&sOnceControl, &sInitRoutine);
     }
 
-    // For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS
+    // Create a new track in the mixer.
+    //
+    // \param name        a unique user-provided integer associated with the track.
+    //                    If name already exists, the function will abort.
+    // \param channelMask output channel mask.
+    // \param format      PCM format
+    // \param sessionId   Session id for the track. Tracks with the same
+    //                    session id will be submixed together.
+    //
+    // \return OK        on success.
+    //         BAD_VALUE if the format does not satisfy isValidFormat()
+    //                   or the channelMask does not satisfy isValidChannelMask().
+    status_t    create(
+            int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId);
 
-    // Allocate a track name.  Returns new track name if successful, -1 on failure.
-    // The failure could be because of an invalid channelMask or format, or that
-    // the track capacity of the mixer is exceeded.
-    int         getTrackName(audio_channel_mask_t channelMask,
-                             audio_format_t format, int sessionId);
+    bool        exists(int name) const {
+        return mTracks.count(name) > 0;
+    }
 
-    // Free an allocated track by name
-    void        deleteTrackName(int name);
+    // Free an allocated track by name.
+    void        destroy(int name);
 
     // Enable or disable an allocated track by name
     void        enable(int name);
@@ -149,6 +149,23 @@
         mNBLogWriter = logWriter;
     }
 
+    static inline bool isValidFormat(audio_format_t format) {
+        switch (format) {
+        case AUDIO_FORMAT_PCM_8_BIT:
+        case AUDIO_FORMAT_PCM_16_BIT:
+        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+        case AUDIO_FORMAT_PCM_32_BIT:
+        case AUDIO_FORMAT_PCM_FLOAT:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    static inline bool isValidChannelMask(audio_channel_mask_t channelMask) {
+        return audio_channel_mask_is_valid(channelMask); // the RemixBufferProvider is flexible.
+    }
+
 private:
 
     /* For multi-format functions (calls template functions
@@ -361,23 +378,9 @@
     static void convertMixerFormat(void *out, audio_format_t mixerOutFormat,
             void *in, audio_format_t mixerInFormat, size_t sampleCount);
 
-    static inline bool isValidPcmTrackFormat(audio_format_t format) {
-        switch (format) {
-        case AUDIO_FORMAT_PCM_8_BIT:
-        case AUDIO_FORMAT_PCM_16_BIT:
-        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
-        case AUDIO_FORMAT_PCM_32_BIT:
-        case AUDIO_FORMAT_PCM_FLOAT:
-            return true;
-        default:
-            return false;
-        }
-    }
-
     static void sInitRoutine();
 
     // initialization constants
-    const int mMaxNumTracks;
     const uint32_t mSampleRate;
     const size_t mFrameCount;
 
@@ -390,12 +393,6 @@
     std::unique_ptr<int32_t[]> mOutputTemp;
     std::unique_ptr<int32_t[]> mResampleTemp;
 
-    // fast lookup of previously deleted track names for reuse.
-    // the AudioMixer tries to return the smallest unused name -
-    // this is an arbitrary decision (actually any non-negative
-    // integer that isn't in mTracks could be used).
-    std::set<int /* name */> mUnusedNames;    // set of unused track names (may be empty)
-
     // track names grouped by main buffer, in no particular order of main buffer.
     // however names for a particular main buffer are in order (by construction).
     std::unordered_map<void * /* mainBuffer */, std::vector<int /* name */>> mGroups;
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index f1daeb4..93ed5f2 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -90,34 +90,21 @@
     return kUseFloat && kUseNewMixer ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT;
 }
 
-int AudioMixer::getTrackName(
-        audio_channel_mask_t channelMask, audio_format_t format, int sessionId)
+status_t AudioMixer::create(
+        int name, audio_channel_mask_t channelMask, audio_format_t format, int sessionId)
 {
-    if (!isValidPcmTrackFormat(format)) {
-        ALOGE("AudioMixer::getTrackName invalid format (%#x)", format);
-        return -1;
-    }
-    if (mTracks.size() >= (size_t)mMaxNumTracks) {
-        ALOGE("%s: out of track names (max = %d)", __func__, mMaxNumTracks);
-        return -1;
-    }
+    LOG_ALWAYS_FATAL_IF(exists(name), "name %d already exists", name);
 
-    // get a new name for the track.
-    int name;
-    if (mUnusedNames.size() != 0) {
-        // reuse first name for deleted track.
-        auto it = mUnusedNames.begin();
-        name = *it;
-        (void)mUnusedNames.erase(it);
-    } else {
-        // we're fully populated, so create a new name.
-        name = mTracks.size();
+    if (!isValidChannelMask(channelMask)) {
+        ALOGE("%s invalid channelMask: %#x", __func__, channelMask);
+        return BAD_VALUE;
     }
-    ALOGV("add track (%d)", name);
+    if (!isValidFormat(format)) {
+        ALOGE("%s invalid format: %#x", __func__, format);
+        return BAD_VALUE;
+    }
 
     auto t = std::make_shared<Track>();
-    mTracks[name] = t;
-
     {
         // TODO: move initialization to the Track constructor.
         // assume default parameters for the track, except where noted below
@@ -179,12 +166,14 @@
         status_t status = t->prepareForDownmix();
         if (status != OK) {
             ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
-            return -1;
+            return BAD_VALUE;
         }
         // prepareForDownmix() may change mDownmixRequiresFormat
         ALOGVV("mMixerFormat:%#x  mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat);
         t->prepareForReformat();
-        return TRACK0 + name;
+
+        mTracks[name] = t;
+        return OK;
     }
 }
 
@@ -193,7 +182,7 @@
 // which will simplify this logic.
 bool AudioMixer::setChannelMasks(int name,
         audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask) {
-    LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name);
+    LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
     const std::shared_ptr<Track> &track = mTracks[name];
 
     if (trackChannelMask == track->channelMask
@@ -361,23 +350,20 @@
     }
 }
 
-void AudioMixer::deleteTrackName(int name)
+void AudioMixer::destroy(int name)
 {
-    name -= TRACK0;
-    LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name);
+    LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
     ALOGV("deleteTrackName(%d)", name);
 
     if (mTracks[name]->enabled) {
         invalidate();
     }
     mTracks.erase(name); // deallocate track
-    mUnusedNames.emplace(name); // recycle name
 }
 
 void AudioMixer::enable(int name)
 {
-    name -= TRACK0;
-    LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name);
+    LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
     const std::shared_ptr<Track> &track = mTracks[name];
 
     if (!track->enabled) {
@@ -389,8 +375,7 @@
 
 void AudioMixer::disable(int name)
 {
-    name -= TRACK0;
-    LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name);
+    LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
     const std::shared_ptr<Track> &track = mTracks[name];
 
     if (track->enabled) {
@@ -528,8 +513,7 @@
 
 void AudioMixer::setParameter(int name, int target, int param, void *value)
 {
-    name -= TRACK0;
-    LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name);
+    LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
     const std::shared_ptr<Track> &track = mTracks[name];
 
     int valueInt = static_cast<int>(reinterpret_cast<uintptr_t>(value));
@@ -808,7 +792,6 @@
 
 size_t AudioMixer::getUnreleasedFrames(int name) const
 {
-    name -= TRACK0;
     const auto it = mTracks.find(name);
     if (it != mTracks.end()) {
         return it->second->getUnreleasedFrames();
@@ -818,7 +801,7 @@
 
 void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider)
 {
-    name -= TRACK0;
+    LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
     const std::shared_ptr<Track> &track = mTracks[name];
 
     if (track->mInputBufferProvider == bufferProvider) {
@@ -1410,13 +1393,12 @@
                     // been enabled for mixing.
                     if (t->mIn == nullptr) break;
 
-                    if (CC_UNLIKELY(aux != NULL)) {
-                        aux += outFrames;
-                    }
                     (t.get()->*t->hook)(
                             outTemp + outFrames * t->mMixerChannelCount, t->buffer.frameCount,
-                            mResampleTemp.get() /* naked ptr */, aux);
+                            mResampleTemp.get() /* naked ptr */,
+                            aux != nullptr ? aux + outFrames : nullptr);
                     outFrames += t->buffer.frameCount;
+
                     t->bufferProvider->releaseBuffer(&t->buffer);
                 }
             }
@@ -1704,7 +1686,7 @@
 
         out += outFrames * channels;
         if (aux != NULL) {
-            aux += channels;
+            aux += outFrames;
         }
         numFrames -= b.frameCount;
 
diff --git a/media/libaudioprocessing/tests/test-mixer.cpp b/media/libaudioprocessing/tests/test-mixer.cpp
index b67810d..bc9d2a6 100644
--- a/media/libaudioprocessing/tests/test-mixer.cpp
+++ b/media/libaudioprocessing/tests/test-mixer.cpp
@@ -143,10 +143,6 @@
         usage(progname);
         return EXIT_FAILURE;
     }
-    if ((unsigned)argc > AudioMixer::MAX_NUM_TRACKS) {
-        fprintf(stderr, "too many tracks: %d > %u", argc, AudioMixer::MAX_NUM_TRACKS);
-        return EXIT_FAILURE;
-    }
 
     size_t outputFrames = 0;
 
@@ -246,9 +242,10 @@
     for (size_t i = 0; i < providers.size(); ++i) {
         //printf("track %d out of %d\n", i, providers.size());
         uint32_t channelMask = audio_channel_out_mask_from_count(providers[i].getNumChannels());
-        int32_t name = mixer->getTrackName(channelMask,
-                formats[i], AUDIO_SESSION_OUTPUT_MIX);
-        ALOG_ASSERT(name >= 0);
+        const int name = i;
+        const status_t status = mixer->create(
+                name, channelMask, formats[i], AUDIO_SESSION_OUTPUT_MIX);
+        LOG_ALWAYS_FATAL_IF(status != OK);
         names[i] = name;
         mixer->setBufferProvider(name, &providers[i]);
         mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
@@ -315,8 +312,10 @@
     writeFile(outputFilename, outputAddr,
             outputSampleRate, outputChannels, outputFrames, useMixerFloat);
     if (auxFilename) {
-        // Aux buffer is always in q4_27 format for now.
-        memcpy_to_i16_from_q4_27((int16_t*)auxAddr, (const int32_t*)auxAddr, outputFrames);
+        // Aux buffer is always in q4_27 format for O and earlier.
+        // memcpy_to_i16_from_q4_27((int16_t*)auxAddr, (const int32_t*)auxAddr, outputFrames);
+        // Aux buffer is always in float format for P.
+        memcpy_to_i16_from_float((int16_t*)auxAddr, (const float*)auxAddr, outputFrames);
         writeFile(auxFilename, auxAddr, outputSampleRate, 1, outputFrames, false);
     }
 
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 51ccb5a..e9a6230 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -35,9 +35,7 @@
     GETTRACKMETADATA,
     GETMETADATA,
     FLAGS,
-    GETDRMTRACKINFO,
     SETMEDIACAS,
-    SETUID,
     NAME,
     GETMETRICS
 };
@@ -112,11 +110,6 @@
         return 0;
     }
 
-    virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
-        ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
-        return NULL;
-    }
-
     virtual status_t setMediaCas(const HInterfaceToken &casToken) {
         ALOGV("setMediaCas");
 
@@ -131,10 +124,6 @@
         return reply.readInt32();
     }
 
-    virtual void setUID(uid_t uid __unused) {
-        ALOGV("setUID NOT IMPLEMENTED");
-    }
-
     virtual const char * name() {
         ALOGV("name NOT IMPLEMENTED");
         return NULL;
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 0d5127c..f6b9255 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -113,9 +113,9 @@
         return NULL;
     }
 
-    virtual status_t read(MediaBuffer **buffer,
+    virtual status_t read(MediaBufferBase **buffer,
             const MediaSource::ReadOptions *options) {
-        Vector<MediaBuffer *> buffers;
+        Vector<MediaBufferBase *> buffers;
         status_t ret = readMultiple(&buffers, 1 /* maxNumBuffers */, options);
         *buffer = buffers.size() == 0 ? nullptr : buffers[0];
         ALOGV("read status %d, bufferCount %u, sinceStop %u",
@@ -124,7 +124,7 @@
     }
 
     virtual status_t readMultiple(
-            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers,
+            Vector<MediaBufferBase *> *buffers, uint32_t maxNumBuffers,
             const MediaSource::ReadOptions *options) {
         ALOGV("readMultiple");
         if (buffers == NULL || !buffers->isEmpty()) {
@@ -341,7 +341,7 @@
             uint32_t bufferCount = 0;
             for (; bufferCount < maxNumBuffers; ++bufferCount, ++mBuffersSinceStop) {
                 MediaBuffer *buf = nullptr;
-                ret = read(&buf, useOptions ? &opts : nullptr);
+                ret = read((MediaBufferBase **)&buf, useOptions ? &opts : nullptr);
                 opts.clearNonPersistent(); // Remove options that only apply to first buffer.
                 if (ret != NO_ERROR || buf == nullptr) {
                     break;
@@ -364,7 +364,7 @@
                     } else {
                         ALOGD("Large buffer %zu without IMemory!", length);
                         ret = mGroup->acquire_buffer(
-                                &transferBuf, false /* nonBlocking */, length);
+                                (MediaBufferBase **)&transferBuf, false /* nonBlocking */, length);
                         if (ret != OK
                                 || transferBuf == nullptr
                                 || transferBuf->mMemory == nullptr) {
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index a570ffe..5308e1c 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -141,6 +141,10 @@
     return mIsEncoder;
 }
 
+uint32_t MediaCodecInfo::rank() const {
+    return mRank;
+}
+
 void MediaCodecInfo::getSupportedMimes(Vector<AString> *mimes) const {
     mimes->clear();
     for (size_t ix = 0; ix < mCaps.size(); ix++) {
@@ -170,10 +174,12 @@
     AString name = AString::FromParcel(parcel);
     AString owner = AString::FromParcel(parcel);
     bool isEncoder = static_cast<bool>(parcel.readInt32());
+    uint32_t rank = parcel.readUint32();
     sp<MediaCodecInfo> info = new MediaCodecInfo;
     info->mName = name;
     info->mOwner = owner;
     info->mIsEncoder = isEncoder;
+    info->mRank = rank;
     size_t size = static_cast<size_t>(parcel.readInt32());
     for (size_t i = 0; i < size; i++) {
         AString mime = AString::FromParcel(parcel);
@@ -191,6 +197,7 @@
     mName.writeToParcel(parcel);
     mOwner.writeToParcel(parcel);
     parcel->writeInt32(mIsEncoder);
+    parcel->writeUint32(mRank);
     parcel->writeInt32(mCaps.size());
     for (size_t i = 0; i < mCaps.size(); i++) {
         mCaps.keyAt(i).writeToParcel(parcel);
@@ -210,7 +217,7 @@
     return -1;
 }
 
-MediaCodecInfo::MediaCodecInfo() {
+MediaCodecInfo::MediaCodecInfo() : mRank(0x100) {
 }
 
 void MediaCodecInfoWriter::setName(const char* name) {
@@ -225,6 +232,10 @@
     mInfo->mIsEncoder = isEncoder;
 }
 
+void MediaCodecInfoWriter::setRank(uint32_t rank) {
+    mInfo->mRank = rank;
+}
+
 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter>
         MediaCodecInfoWriter::addMime(const char *mime) {
     ssize_t ix = mInfo->getCapabilityIndex(mime);
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index 0896e75..5ca3b48 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -38,6 +38,7 @@
     mFd = open(path, O_RDONLY | O_LARGEFILE);
     mBase = 0;
     mLength = lseek(mFd, 0, SEEK_END);
+    mDataSource = nullptr;
 }
 
 MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
@@ -45,6 +46,7 @@
     mFd = fd < 0 ? -1 : dup(fd);
     mBase = offset;
     mLength = size;
+    mDataSource = nullptr;
 }
 
 MidiIoWrapper::MidiIoWrapper(DataSourceBase *source) {
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 942393d..936e92f 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -1057,6 +1057,13 @@
     return translateErrorCode(AMediaExtractor_setDataSource(mAMediaExtractor, location));
 }
 
+status_t AMediaExtractorWrapper::setDataSource(AMediaDataSource *source) {
+    if (mAMediaExtractor == NULL) {
+        return DEAD_OBJECT;
+    }
+    return translateErrorCode(AMediaExtractor_setDataSourceCustom(mAMediaExtractor, source));
+}
+
 size_t AMediaExtractorWrapper::getTrackCount() {
     if (mAMediaExtractor == NULL) {
         return 0;
@@ -1064,6 +1071,13 @@
     return AMediaExtractor_getTrackCount(mAMediaExtractor);
 }
 
+sp<AMediaFormatWrapper> AMediaExtractorWrapper::getFormat() {
+    if (mAMediaExtractor == NULL) {
+        return NULL;
+    }
+    return new AMediaFormatWrapper(AMediaExtractor_getFileFormat(mAMediaExtractor));
+}
+
 sp<AMediaFormatWrapper> AMediaExtractorWrapper::getTrackFormat(size_t idx) {
     if (mAMediaExtractor == NULL) {
         return NULL;
@@ -1085,6 +1099,26 @@
     return translateErrorCode(AMediaExtractor_unselectTrack(mAMediaExtractor, idx));
 }
 
+status_t AMediaExtractorWrapper::selectSingleTrack(size_t idx) {
+    if (mAMediaExtractor == NULL) {
+        return DEAD_OBJECT;
+    }
+    for (size_t i = 0; i < AMediaExtractor_getTrackCount(mAMediaExtractor); ++i) {
+        if (i == idx) {
+            media_status_t err = AMediaExtractor_selectTrack(mAMediaExtractor, i);
+            if (err != AMEDIA_OK) {
+                return translateErrorCode(err);
+            }
+        } else {
+            media_status_t err = AMediaExtractor_unselectTrack(mAMediaExtractor, i);
+            if (err != AMEDIA_OK) {
+                return translateErrorCode(err);
+            }
+        }
+    }
+    return OK;
+}
+
 ssize_t AMediaExtractorWrapper::readSampleData(const sp<ABuffer> &buffer) {
     if (mAMediaExtractor == NULL) {
         return -1;
@@ -1092,6 +1126,13 @@
     return AMediaExtractor_readSampleData(mAMediaExtractor, buffer->data(), buffer->capacity());
 }
 
+ssize_t AMediaExtractorWrapper::getSampleSize() {
+    if (mAMediaExtractor == NULL) {
+        return 0;
+    }
+    return AMediaExtractor_getSampleSize(mAMediaExtractor);
+}
+
 uint32_t AMediaExtractorWrapper::getSampleFlags() {
     if (mAMediaExtractor == NULL) {
         return 0;
@@ -1113,6 +1154,13 @@
     return AMediaExtractor_getSampleTime(mAMediaExtractor);
 }
 
+int64_t AMediaExtractorWrapper::getCachedDuration() {
+    if (mAMediaExtractor == NULL) {
+        return -1;
+    }
+    return AMediaExtractor_getCachedDuration(mAMediaExtractor);
+}
+
 bool AMediaExtractorWrapper::advance() {
     if (mAMediaExtractor == NULL) {
         return false;
@@ -1120,11 +1168,27 @@
     return AMediaExtractor_advance(mAMediaExtractor);
 }
 
-status_t AMediaExtractorWrapper::seekTo(int64_t seekPosUs, SeekMode mode) {
+status_t AMediaExtractorWrapper::seekTo(int64_t seekPosUs, MediaSource::ReadOptions::SeekMode mode) {
     if (mAMediaExtractor == NULL) {
         return DEAD_OBJECT;
     }
-    return AMediaExtractor_seekTo(mAMediaExtractor, seekPosUs, mode);
+
+    SeekMode aMode;
+    switch (mode) {
+        case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: {
+            aMode = AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC;
+            break;
+        }
+        case MediaSource::ReadOptions::SEEK_NEXT_SYNC: {
+            aMode = AMEDIAEXTRACTOR_SEEK_NEXT_SYNC;
+            break;
+        }
+        default: {
+            aMode = AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC;
+            break;
+        }
+    }
+    return AMediaExtractor_seekTo(mAMediaExtractor, seekPosUs, aMode);
 }
 
 PsshInfo* AMediaExtractorWrapper::getPsshInfo() {
@@ -1141,4 +1205,43 @@
     return new AMediaCodecCryptoInfoWrapper(AMediaExtractor_getSampleCryptoInfo(mAMediaExtractor));
 }
 
+ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_getSize(void *userdata) {
+    DataSource *source = static_cast<DataSource *>(userdata);
+    off64_t size = -1;
+    source->getSize(&size);
+    return size;
+}
+
+ssize_t AMediaDataSourceWrapper::AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
+    DataSource *source = static_cast<DataSource *>(userdata);
+    return source->readAt(offset, buf, size);
+}
+
+void AMediaDataSourceWrapper::AMediaDataSourceWrapper_close(void *userdata) {
+    DataSource *source = static_cast<DataSource *>(userdata);
+    source->close();
+}
+
+AMediaDataSourceWrapper::AMediaDataSourceWrapper(const sp<DataSource> &dataSource)
+    : mDataSource(dataSource),
+      mAMediaDataSource(AMediaDataSource_new()) {
+    ALOGV("setDataSource (source: %p)", dataSource.get());
+    AMediaDataSource_setUserdata(mAMediaDataSource, dataSource.get());
+    AMediaDataSource_setReadAt(mAMediaDataSource, AMediaDataSourceWrapper_readAt);
+    AMediaDataSource_setGetSize(mAMediaDataSource, AMediaDataSourceWrapper_getSize);
+    AMediaDataSource_setClose(mAMediaDataSource, AMediaDataSourceWrapper_close);
+}
+
+AMediaDataSourceWrapper::~AMediaDataSourceWrapper() {
+    if (mAMediaDataSource == NULL) {
+        return;
+    }
+    AMediaDataSource_delete(mAMediaDataSource);
+    mAMediaDataSource = NULL;
+}
+
+AMediaDataSource* AMediaDataSourceWrapper::getAMediaDataSource() {
+    return mAMediaDataSource;
+}
+
 }  // namespace android
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index 1c09036..c64b003 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -119,7 +119,7 @@
     virtual status_t setPropertyString(String8 const &name, String8 const &value ) const;
     virtual status_t setPropertyByteArray(String8 const &name,
                                           Vector<uint8_t> const &value ) const;
-    virtual status_t getMetrics(MediaAnalyticsItem *item);
+    virtual status_t getMetrics(os::PersistableBundle *metrics);
 
     virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
                                         String8 const &algorithm);
@@ -188,6 +188,7 @@
 
     Vector<Vector<uint8_t>> mOpenSessions;
     void closeOpenSessions();
+    void cleanup();
 
     /**
      * mInitCheck is:
@@ -203,7 +204,8 @@
 
     void writeByteArray(Parcel &obj, const hidl_vec<uint8_t>& array);
 
-    void reportMetrics() const;
+    void reportPluginMetrics() const;
+    void reportFrameworkMetrics() const;
     status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
     status_t getPropertyByteArrayInternal(String8 const &name,
                                           Vector<uint8_t> &value) const;
diff --git a/media/libmedia/include/media/DrmMetrics.h b/media/libmedia/include/media/DrmMetrics.h
index bb7509b..5c2fdf2 100644
--- a/media/libmedia/include/media/DrmMetrics.h
+++ b/media/libmedia/include/media/DrmMetrics.h
@@ -20,6 +20,7 @@
 #include <map>
 
 #include <android/hardware/drm/1.0/types.h>
+#include <binder/PersistableBundle.h>
 #include <media/CounterMetric.h>
 #include <media/EventMetric.h>
 
@@ -28,19 +29,20 @@
 /**
  * This class contains the definition of metrics captured within MediaDrm.
  * It also contains a method for exporting all of the metrics to a
- * MediaAnalyticsItem instance.
+ * PersistableBundle.
  */
 class MediaDrmMetrics {
  public:
   explicit MediaDrmMetrics();
+  virtual ~MediaDrmMetrics() {};
   // Count of openSession calls.
   CounterMetric<status_t> mOpenSessionCounter;
   // Count of closeSession calls.
   CounterMetric<status_t> mCloseSessionCounter;
   // Count and timing of getKeyRequest calls.
-  EventMetric<status_t> mGetKeyRequestTiming;
+  EventMetric<status_t> mGetKeyRequestTimeUs;
   // Count and timing of provideKeyResponse calls.
-  EventMetric<status_t> mProvideKeyResponseTiming;
+  EventMetric<status_t> mProvideKeyResponseTimeUs;
   // Count of getProvisionRequest calls.
   CounterMetric<status_t> mGetProvisionRequestCounter;
   // Count of provideProvisionResponse calls.
@@ -55,10 +57,37 @@
   // Count getPropertyByteArray calls to retrieve the device unique id.
   CounterMetric<status_t> mGetDeviceUniqueIdCounter;
 
-  // TODO: Add session start and end time support. These are a special case.
+  // Adds a session start time record.
+  void SetSessionStart(const Vector<uint8_t>& sessionId);
 
-  // Export the metrics to a MediaAnalyticsItem.
-  void Export(MediaAnalyticsItem* item);
+  // Adds a session end time record.
+  void SetSessionEnd(const Vector<uint8_t>& sessionId);
+
+  // The app package name is the application package name that is using the
+  // instance. The app package name is held here for convenience. It is not
+  // serialized or exported with the metrics.
+  void SetAppPackageName(const String8& appPackageName) { mAppPackageName = appPackageName; }
+  const String8& GetAppPackageName() { return mAppPackageName; }
+
+  // Export the metrics to a PersistableBundle.
+  void Export(os::PersistableBundle* metricsBundle);
+
+  // Get the serialized metrics. Metrics are formatted as a serialized
+  // DrmFrameworkMetrics proto. If there is a failure serializing the metrics,
+  // this returns an error. The parameter |serlializedMetrics| is owned by the
+  // caller and must not be null.
+  status_t GetSerializedMetrics(std::string* serializedMetrics);
+
+ protected:
+  // This is visible for testing only.
+  virtual int64_t GetCurrentTimeMs();
+
+ private:
+  // Session lifetimes. A pair of values representing the milliseconds since
+  // epoch, UTC. The first value is the start time, the second is the end time.
+  std::map<std::string, std::pair<int64_t, int64_t>> mSessionLifespans;
+
+  String8 mAppPackageName;
 };
 
 }  // namespace android
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
index c3ae684..a19b06b 100644
--- a/media/libmedia/include/media/IDrm.h
+++ b/media/libmedia/include/media/IDrm.h
@@ -15,6 +15,7 @@
  */
 
 #include <binder/IInterface.h>
+#include <binder/PersistableBundle.h>
 #include <media/stagefright/foundation/ABase.h>
 #include <media/drm/DrmAPI.h>
 #include <media/IDrmClient.h>
@@ -98,7 +99,7 @@
     virtual status_t setPropertyByteArray(String8 const &name,
                                           Vector<uint8_t> const &value) const = 0;
 
-    virtual status_t getMetrics(MediaAnalyticsItem *item) = 0;
+    virtual status_t getMetrics(os::PersistableBundle *metrics) = 0;
 
     virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
                                         String8 const &algorithm) = 0;
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 9899429..75e4ee2 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -60,13 +60,8 @@
     // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
     virtual uint32_t flags() const = 0;
 
-    // for DRM
-    virtual char* getDrmTrackInfo(size_t trackID, int *len)  = 0;
-
     virtual status_t setMediaCas(const HInterfaceToken &casToken) = 0;
 
-    virtual void setUID(uid_t uid)  = 0;
-
     virtual const char * name() = 0;
 };
 
diff --git a/media/libmedia/include/media/IMediaSource.h b/media/libmedia/include/media/IMediaSource.h
index dabe231..7a4b1b9 100644
--- a/media/libmedia/include/media/IMediaSource.h
+++ b/media/libmedia/include/media/IMediaSource.h
@@ -64,7 +64,7 @@
     //
     // TODO: consider removing read() in favor of readMultiple().
     virtual status_t read(
-            MediaBuffer **buffer,
+            MediaBufferBase **buffer,
             const MediaSource::ReadOptions *options = NULL) = 0;
 
     // Returns a vector of new buffers of data, where the new buffers are added
@@ -80,7 +80,7 @@
     // ReadOptions may be specified. Persistent options apply to all reads;
     // non-persistent options (e.g. seek) apply only to the first read.
     virtual status_t readMultiple(
-            Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1,
+            Vector<MediaBufferBase *> *buffers, uint32_t maxNumBuffers = 1,
             const MediaSource::ReadOptions *options = nullptr) = 0;
 
     // Returns true if |readMultiple| is supported, otherwise false.
@@ -110,7 +110,7 @@
 
     // TODO: Implement this for local media sources.
     virtual status_t readMultiple(
-            Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
+            Vector<MediaBufferBase *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
             const MediaSource::ReadOptions * /* options = nullptr */) {
         return ERROR_UNSUPPORTED;
     }
diff --git a/media/libmedia/include/media/MediaBufferHolder.h b/media/libmedia/include/media/MediaBufferHolder.h
index e8e2c4b..f9dfdf5 100644
--- a/media/libmedia/include/media/MediaBufferHolder.h
+++ b/media/libmedia/include/media/MediaBufferHolder.h
@@ -24,7 +24,7 @@
 namespace android {
 
 struct MediaBufferHolder : public RefBase {
-    MediaBufferHolder(MediaBuffer* buffer)
+    MediaBufferHolder(MediaBufferBase* buffer)
         : mMediaBuffer(buffer) {
         if (mMediaBuffer != nullptr) {
             mMediaBuffer->add_ref();
@@ -37,10 +37,10 @@
         }
     }
 
-    MediaBuffer* mediaBuffer() { return mMediaBuffer; }
+    MediaBufferBase* mediaBuffer() { return mMediaBuffer; }
 
 private:
-    MediaBuffer* const mMediaBuffer;
+    MediaBufferBase* const mMediaBuffer;
 };
 
 }  // android
diff --git a/media/libmedia/include/media/MediaCodecInfo.h b/media/libmedia/include/media/MediaCodecInfo.h
index ab2cd24..b3777d3 100644
--- a/media/libmedia/include/media/MediaCodecInfo.h
+++ b/media/libmedia/include/media/MediaCodecInfo.h
@@ -170,6 +170,7 @@
      * Currently, this is the "instance name" of the IOmx service.
      */
     const char *getOwnerName() const;
+    uint32_t rank() const;
 
     /**
      * Serialization over Binder
@@ -182,6 +183,7 @@
     AString mOwner;
     bool mIsEncoder;
     KeyedVector<AString, sp<Capabilities> > mCaps;
+    uint32_t mRank;
 
     ssize_t getCapabilityIndex(const char *mime) const;
 
@@ -252,6 +254,13 @@
      * @return `true` if `mime` is removed; `false` if `mime` is not found.
      */
     bool removeMime(const char* mime);
+    /**
+     * Set rank of the codec. MediaCodecList will stable-sort the list according
+     * to rank in non-descending order.
+     *
+     * @param rank The rank of the component.
+     */
+    void setRank(uint32_t rank);
 private:
     /**
      * The associated `MediaCodecInfo`.
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index 00e0fd4..49d728d 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -18,6 +18,9 @@
 
 #define NDK_WRAPPER_H_
 
+#include <media/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/NdkMediaDataSource.h>
 #include <media/NdkMediaError.h>
 #include <media/NdkMediaExtractor.h>
 #include <media/hardware/CryptoAPI.h>
@@ -286,25 +289,35 @@
 
     status_t setDataSource(const char *location);
 
+    status_t setDataSource(AMediaDataSource *);
+
     size_t getTrackCount();
 
+    sp<AMediaFormatWrapper> getFormat();
+
     sp<AMediaFormatWrapper> getTrackFormat(size_t idx);
 
     status_t selectTrack(size_t idx);
 
     status_t unselectTrack(size_t idx);
 
+    status_t selectSingleTrack(size_t idx);
+
     ssize_t readSampleData(const sp<ABuffer> &buffer);
 
+    ssize_t getSampleSize();
+
     uint32_t getSampleFlags();
 
     int getSampleTrackIndex();
 
     int64_t getSampleTime();
 
+    int64_t getCachedDuration();
+
     bool advance();
 
-    status_t seekTo(int64_t seekPosUs, SeekMode mode);
+    status_t seekTo(int64_t seekPosUs, MediaSource::ReadOptions::SeekMode mode);
 
     // the returned PsshInfo is still owned by this wrapper.
     PsshInfo* getPsshInfo();
@@ -320,6 +333,31 @@
     DISALLOW_EVIL_CONSTRUCTORS(AMediaExtractorWrapper);
 };
 
+struct AMediaDataSourceWrapper : public RefBase {
+
+    static status_t translate_error(media_status_t err);
+
+    static ssize_t AMediaDataSourceWrapper_getSize(void *userdata);
+
+    static ssize_t AMediaDataSourceWrapper_readAt(void *userdata, off64_t offset, void * buf, size_t size);
+
+    static void AMediaDataSourceWrapper_close(void *userdata);
+
+    AMediaDataSourceWrapper(const sp<DataSource> &dataSource);
+
+    AMediaDataSource *getAMediaDataSource();
+
+protected:
+    virtual ~AMediaDataSourceWrapper();
+
+private:
+    sp<DataSource> mDataSource;
+
+    AMediaDataSource *mAMediaDataSource;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AMediaDataSourceWrapper);
+};
+
 }  // namespace android
 
 #endif  // NDK_WRAPPER_H_
diff --git a/media/libmedia/include/media/OMXBuffer.h b/media/libmedia/include/media/OMXBuffer.h
index 3e84858..9c9f5e7 100644
--- a/media/libmedia/include/media/OMXBuffer.h
+++ b/media/libmedia/include/media/OMXBuffer.h
@@ -91,6 +91,7 @@
 
 private:
     friend struct OMXNodeInstance;
+    friend struct C2OMXNode;
 
     // This is needed temporarily for OMX HIDL transition.
     friend inline bool (::android::hardware::media::omx::V1_0::implementation::
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 8f4ba70..79af058 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -25,6 +25,7 @@
     srcs: [
         "DataSourceBase.cpp",
         "MediaBuffer.cpp",
+        "MediaBufferBase.cpp",
         "MediaBufferGroup.cpp",
         "MediaSourceBase.cpp",
         "MediaSource.cpp",
diff --git a/media/libmediaextractor/MediaBuffer.cpp b/media/libmediaextractor/MediaBuffer.cpp
index 28fc760..dac3d50 100644
--- a/media/libmediaextractor/MediaBuffer.cpp
+++ b/media/libmediaextractor/MediaBuffer.cpp
@@ -177,7 +177,7 @@
     mObserver = observer;
 }
 
-MediaBuffer *MediaBuffer::clone() {
+MediaBufferBase *MediaBuffer::clone() {
     MediaBuffer *buffer = new MediaBuffer(mData, mSize);
     buffer->set_range(mRangeOffset, mRangeLength);
     buffer->mMetaData = new MetaData(*mMetaData.get());
diff --git a/media/libmediaextractor/MediaBufferBase.cpp b/media/libmediaextractor/MediaBufferBase.cpp
new file mode 100644
index 0000000..a553289
--- /dev/null
+++ b/media/libmediaextractor/MediaBufferBase.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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_TAG "MediaBufferBase"
+#include <utils/Log.h>
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferBase.h>
+
+namespace android {
+
+//static
+MediaBufferBase *MediaBufferBase::Create(size_t size) {
+    return new (std::nothrow) MediaBuffer(size);
+}
+
+}  // android
diff --git a/media/libmediaextractor/MediaBufferGroup.cpp b/media/libmediaextractor/MediaBufferGroup.cpp
index cb62d92..2a8dd41 100644
--- a/media/libmediaextractor/MediaBufferGroup.cpp
+++ b/media/libmediaextractor/MediaBufferGroup.cpp
@@ -17,9 +17,13 @@
 #define LOG_TAG "MediaBufferGroup"
 #include <utils/Log.h>
 
+#include <list>
+
+#include <binder/MemoryDealer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
+#include <utils/threads.h>
 
 namespace android {
 
@@ -32,17 +36,26 @@
 static const size_t kSharedMemoryThreshold = MIN(
         (size_t)MediaBuffer::kSharedMemThreshold, (size_t)(4 * 1024));
 
-MediaBufferGroup::MediaBufferGroup(size_t growthLimit) :
-    mGrowthLimit(growthLimit) {
+struct MediaBufferGroup::InternalData {
+    Mutex mLock;
+    Condition mCondition;
+    size_t mGrowthLimit;  // Do not automatically grow group larger than this.
+    std::list<MediaBufferBase *> mBuffers;
+};
+
+MediaBufferGroup::MediaBufferGroup(size_t growthLimit)
+    : mInternal(new InternalData()) {
+    mInternal->mGrowthLimit = growthLimit;
 }
 
 MediaBufferGroup::MediaBufferGroup(size_t buffers, size_t buffer_size, size_t growthLimit)
-    : mGrowthLimit(growthLimit) {
+    : mInternal(new InternalData()) {
+    mInternal->mGrowthLimit = growthLimit;
 
-    if (mGrowthLimit > 0 && buffers > mGrowthLimit) {
+    if (mInternal->mGrowthLimit > 0 && buffers > mInternal->mGrowthLimit) {
         ALOGW("Preallocated buffers %zu > growthLimit %zu, increasing growthLimit",
-                buffers, mGrowthLimit);
-        mGrowthLimit = buffers;
+                buffers, mInternal->mGrowthLimit);
+        mInternal->mGrowthLimit = buffers;
     }
 
     if (buffer_size >= kSharedMemoryThreshold) {
@@ -81,7 +94,7 @@
 }
 
 MediaBufferGroup::~MediaBufferGroup() {
-    for (MediaBuffer *buffer : mBuffers) {
+    for (MediaBufferBase *buffer : mInternal->mBuffers) {
         if (buffer->refcount() != 0) {
             const int localRefcount = buffer->localRefcount();
             const int remoteRefcount = buffer->remoteRefcount();
@@ -103,34 +116,35 @@
         buffer->setObserver(nullptr);
         buffer->release();
     }
+    delete mInternal;
 }
 
-void MediaBufferGroup::add_buffer(MediaBuffer *buffer) {
-    Mutex::Autolock autoLock(mLock);
+void MediaBufferGroup::add_buffer(MediaBufferBase *buffer) {
+    Mutex::Autolock autoLock(mInternal->mLock);
 
     // if we're above our growth limit, release buffers if we can
-    for (auto it = mBuffers.begin();
-            mGrowthLimit > 0
-            && mBuffers.size() >= mGrowthLimit
-            && it != mBuffers.end();) {
+    for (auto it = mInternal->mBuffers.begin();
+            mInternal->mGrowthLimit > 0
+            && mInternal->mBuffers.size() >= mInternal->mGrowthLimit
+            && it != mInternal->mBuffers.end();) {
         if ((*it)->refcount() == 0) {
             (*it)->setObserver(nullptr);
             (*it)->release();
-            it = mBuffers.erase(it);
+            it = mInternal->mBuffers.erase(it);
         } else {
             ++it;
         }
     }
 
     buffer->setObserver(this);
-    mBuffers.emplace_back(buffer);
+    mInternal->mBuffers.emplace_back(buffer);
 }
 
 bool MediaBufferGroup::has_buffers() {
-    if (mBuffers.size() < mGrowthLimit) {
+    if (mInternal->mBuffers.size() < mInternal->mGrowthLimit) {
         return true; // We can add more buffers internally.
     }
-    for (MediaBuffer *buffer : mBuffers) {
+    for (MediaBufferBase *buffer : mInternal->mBuffers) {
         if (buffer->refcount() == 0) {
             return true;
         }
@@ -139,13 +153,13 @@
 }
 
 status_t MediaBufferGroup::acquire_buffer(
-        MediaBuffer **out, bool nonBlocking, size_t requestedSize) {
-    Mutex::Autolock autoLock(mLock);
+        MediaBufferBase **out, bool nonBlocking, size_t requestedSize) {
+    Mutex::Autolock autoLock(mInternal->mLock);
     for (;;) {
         size_t smallest = requestedSize;
-        MediaBuffer *buffer = nullptr;
-        auto free = mBuffers.end();
-        for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+        MediaBufferBase *buffer = nullptr;
+        auto free = mInternal->mBuffers.end();
+        for (auto it = mInternal->mBuffers.begin(); it != mInternal->mBuffers.end(); ++it) {
             if ((*it)->refcount() == 0) {
                 const size_t size = (*it)->size();
                 if (size >= requestedSize) {
@@ -159,7 +173,8 @@
             }
         }
         if (buffer == nullptr
-                && (free != mBuffers.end() || mBuffers.size() < mGrowthLimit)) {
+                && (free != mInternal->mBuffers.end()
+                    || mInternal->mBuffers.size() < mInternal->mGrowthLimit)) {
             // We alloc before we free so failure leaves group unchanged.
             const size_t allocateSize = requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ?
                     requestedSize * 3 / 2 : requestedSize;
@@ -170,7 +185,7 @@
                 buffer = nullptr;
             } else {
                 buffer->setObserver(this);
-                if (free != mBuffers.end()) {
+                if (free != mInternal->mBuffers.end()) {
                     ALOGV("reallocate buffer, requested size %zu vs available %zu",
                             requestedSize, (*free)->size());
                     (*free)->setObserver(nullptr);
@@ -178,7 +193,7 @@
                     *free = buffer; // in-place replace
                 } else {
                     ALOGV("allocate buffer, requested size %zu", requestedSize);
-                    mBuffers.emplace_back(buffer);
+                    mInternal->mBuffers.emplace_back(buffer);
                 }
             }
         }
@@ -193,14 +208,18 @@
             return WOULD_BLOCK;
         }
         // All buffers are in use, block until one of them is returned.
-        mCondition.wait(mLock);
+        mInternal->mCondition.wait(mInternal->mLock);
     }
     // Never gets here.
 }
 
-void MediaBufferGroup::signalBufferReturned(MediaBuffer *) {
-    Mutex::Autolock autoLock(mLock);
-    mCondition.signal();
+size_t MediaBufferGroup::buffers() const {
+    return mInternal->mBuffers.size();
+}
+
+void MediaBufferGroup::signalBufferReturned(MediaBufferBase *) {
+    Mutex::Autolock autoLock(mInternal->mLock);
+    mInternal->mCondition.signal();
 }
 
 }  // namespace android
diff --git a/media/libmediaextractor/MetaData.cpp b/media/libmediaextractor/MetaData.cpp
index 98cddbe..69beea1 100644
--- a/media/libmediaextractor/MetaData.cpp
+++ b/media/libmediaextractor/MetaData.cpp
@@ -146,7 +146,7 @@
 /**
  * Note that the returned pointer becomes invalid when additional metadata is set.
  */
-bool MetaData::findCString(uint32_t key, const char **value) {
+bool MetaData::findCString(uint32_t key, const char **value) const {
     uint32_t type;
     const void *data;
     size_t size;
@@ -159,7 +159,7 @@
     return true;
 }
 
-bool MetaData::findInt32(uint32_t key, int32_t *value) {
+bool MetaData::findInt32(uint32_t key, int32_t *value) const {
     uint32_t type = 0;
     const void *data;
     size_t size;
@@ -174,7 +174,7 @@
     return true;
 }
 
-bool MetaData::findInt64(uint32_t key, int64_t *value) {
+bool MetaData::findInt64(uint32_t key, int64_t *value) const {
     uint32_t type = 0;
     const void *data;
     size_t size;
@@ -189,7 +189,7 @@
     return true;
 }
 
-bool MetaData::findFloat(uint32_t key, float *value) {
+bool MetaData::findFloat(uint32_t key, float *value) const {
     uint32_t type = 0;
     const void *data;
     size_t size;
@@ -204,7 +204,7 @@
     return true;
 }
 
-bool MetaData::findPointer(uint32_t key, void **value) {
+bool MetaData::findPointer(uint32_t key, void **value) const {
     uint32_t type = 0;
     const void *data;
     size_t size;
@@ -222,7 +222,7 @@
 bool MetaData::findRect(
         uint32_t key,
         int32_t *left, int32_t *top,
-        int32_t *right, int32_t *bottom) {
+        int32_t *right, int32_t *bottom) const {
     uint32_t type = 0;
     const void *data;
     size_t size;
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libmediaextractor/include/media/DataSourceBase.h
index f964137..8028dd7 100644
--- a/media/libmediaextractor/include/media/DataSourceBase.h
+++ b/media/libmediaextractor/include/media/DataSourceBase.h
@@ -58,20 +58,6 @@
     bool getUInt32Var(off64_t offset, uint32_t *x, size_t size);
     bool getUInt64Var(off64_t offset, uint64_t *x, size_t size);
 
-    // Reads in "count" entries of type T into vector *x.
-    // Returns true if "count" entries can be read.
-    // If fewer than "count" entries can be read, return false. In this case,
-    // the output vector *x will still have those entries that were read. Call
-    // x->size() to obtain the number of entries read.
-    // The optional parameter chunkSize specifies how many entries should be
-    // read from the data source at one time into a temporary buffer. Increasing
-    // chunkSize can improve the performance at the cost of extra memory usage.
-    // The default value for chunkSize is set to read at least 4k bytes at a
-    // time, depending on sizeof(T).
-    template <typename T>
-    bool getVector(off64_t offset, Vector<T>* x, size_t count,
-                   size_t chunkSize = (4095 / sizeof(T)) + 1);
-
     // May return ERROR_UNSUPPORTED.
     virtual status_t getSize(off64_t *size);
 
@@ -110,51 +96,6 @@
     DataSourceBase &operator=(const DataSourceBase &);
 };
 
-template <typename T>
-bool DataSourceBase::getVector(off64_t offset, Vector<T>* x, size_t count,
-                           size_t chunkSize)
-{
-    x->clear();
-    if (chunkSize == 0) {
-        return false;
-    }
-    if (count == 0) {
-        return true;
-    }
-
-    T tmp[chunkSize];
-    ssize_t numBytesRead;
-    size_t numBytesPerChunk = chunkSize * sizeof(T);
-    size_t i;
-
-    for (i = 0; i + chunkSize < count; i += chunkSize) {
-        // This loops is executed when more than chunkSize records need to be
-        // read.
-        numBytesRead = this->readAt(offset, (void*)&tmp, numBytesPerChunk);
-        if (numBytesRead == -1) { // If readAt() returns -1, there is an error.
-            return false;
-        }
-        if (static_cast<size_t>(numBytesRead) < numBytesPerChunk) {
-            // This case is triggered when the stream ends before the whole
-            // chunk is read.
-            x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
-            return false;
-        }
-        x->appendArray(tmp, chunkSize);
-        offset += numBytesPerChunk;
-    }
-
-    // There are (count - i) more records to read.
-    // Right now, (count - i) <= chunkSize.
-    // We do the same thing as above, but with chunkSize replaced by count - i.
-    numBytesRead = this->readAt(offset, (void*)&tmp, (count - i) * sizeof(T));
-    if (numBytesRead == -1) {
-        return false;
-    }
-    x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
-    return x->size() == count;
-}
-
 }  // namespace android
 
 #endif  // DATA_SOURCE_BASE_H_
diff --git a/media/libmediaextractor/include/media/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
index 73c5f10..c329903 100644
--- a/media/libmediaextractor/include/media/MediaExtractor.h
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -29,8 +29,6 @@
 
 class DataSourceBase;
 class MetaData;
-class String8;
-struct AMessage;
 struct MediaSourceBase;
 
 
@@ -74,12 +72,6 @@
     // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
     virtual uint32_t flags() const;
 
-    // for DRM
-    virtual char* getDrmTrackInfo(size_t /*trackID*/, int * /*len*/) {
-        return NULL;
-    }
-    virtual void setUID(uid_t /*uid*/) {
-    }
     virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
         return INVALID_OPERATION;
     }
@@ -87,14 +79,16 @@
     virtual const char * name() { return "<unspecified>"; }
 
     typedef MediaExtractor* (*CreatorFunc)(
-            DataSourceBase *source, const sp<AMessage> &meta);
+            DataSourceBase *source, void *meta);
+    typedef void (*FreeMetaFunc)(void *meta);
 
-    // The sniffer can optionally fill in "meta" with an AMessage containing
-    // a dictionary of values that helps the corresponding extractor initialize
-    // its state without duplicating effort already exerted by the sniffer.
+    // The sniffer can optionally fill in an opaque object, "meta", that helps
+    // the corresponding extractor initialize its state without duplicating
+    // effort already exerted by the sniffer. If "freeMeta" is given, it will be
+    // called against the opaque object when it is no longer used.
     typedef CreatorFunc (*SnifferFunc)(
-            DataSourceBase *source, String8 *mimeType,
-            float *confidence, sp<AMessage> *meta);
+            DataSourceBase *source, float *confidence,
+            void **meta, FreeMetaFunc *freeMeta);
 
     typedef struct {
         const uint8_t b[16];
diff --git a/media/libmediaextractor/include/media/MediaSourceBase.h b/media/libmediaextractor/include/media/MediaSourceBase.h
index 9db6099..ab56613 100644
--- a/media/libmediaextractor/include/media/MediaSourceBase.h
+++ b/media/libmediaextractor/include/media/MediaSourceBase.h
@@ -30,7 +30,7 @@
 
 namespace android {
 
-class MediaBuffer;
+class MediaBufferBase;
 
 class SourceBaseAllocTracker {
 public:
@@ -111,7 +111,7 @@
     // MediaSource has changed mid-stream, the client can continue reading
     // but should be prepared for buffers of the new configuration.
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+            MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
 
     // Causes this source to suspend pulling data from its upstream source
     // until a subsequent read-with-seek. This is currently not supported
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
index a8f8375..85b4521 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
@@ -26,6 +26,7 @@
 #include <binder/MemoryDealer.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <media/stagefright/MediaBufferBase.h>
 
 namespace android {
 
@@ -34,19 +35,7 @@
 class MediaBufferObserver;
 class MetaData;
 
-class MediaBufferObserver {
-public:
-    MediaBufferObserver() {}
-    virtual ~MediaBufferObserver() {}
-
-    virtual void signalBufferReturned(MediaBuffer *buffer) = 0;
-
-private:
-    MediaBufferObserver(const MediaBufferObserver &);
-    MediaBufferObserver &operator=(const MediaBufferObserver &);
-};
-
-class MediaBuffer {
+class MediaBuffer : public MediaBufferBase {
 public:
     // allocations larger than or equal to this will use shared memory.
     static const size_t kSharedMemThreshold = 64 * 1024;
@@ -70,42 +59,42 @@
     //
     // If no MediaBufferGroup is set, the local reference count must be zero
     // when called, whereupon the MediaBuffer is deleted.
-    void release();
+    virtual void release();
 
     // Increments the local reference count.
     // Use only when MediaBufferGroup is set.
-    void add_ref();
+    virtual void add_ref();
 
-    void *data() const;
-    size_t size() const;
+    virtual void *data() const;
+    virtual size_t size() const;
 
-    size_t range_offset() const;
-    size_t range_length() const;
+    virtual size_t range_offset() const;
+    virtual size_t range_length() const;
 
-    void set_range(size_t offset, size_t length);
+    virtual void set_range(size_t offset, size_t length);
 
-    sp<MetaData> meta_data();
+    virtual sp<MetaData> meta_data();
 
     // Clears meta data and resets the range to the full extent.
-    void reset();
+    virtual void reset();
 
-    void setObserver(MediaBufferObserver *group);
+    virtual void setObserver(MediaBufferObserver *group);
 
     // Returns a clone of this MediaBuffer increasing its reference count.
     // The clone references the same data but has its own range and
     // MetaData.
-    MediaBuffer *clone();
+    virtual MediaBufferBase *clone();
 
     // sum of localRefcount() and remoteRefcount()
-    int refcount() const {
+    virtual int refcount() const {
         return localRefcount() + remoteRefcount();
     }
 
-    int localRefcount() const {
+    virtual int localRefcount() const {
         return mRefCount;
     }
 
-    int remoteRefcount() const {
+    virtual int remoteRefcount() const {
         if (mMemory.get() == nullptr || mMemory->pointer() == nullptr) return 0;
         int32_t remoteRefcount =
                 reinterpret_cast<SharedControl *>(mMemory->pointer())->getRemoteRefcount();
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h b/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
new file mode 100644
index 0000000..81dd7d9
--- /dev/null
+++ b/media/libmediaextractor/include/media/stagefright/MediaBufferBase.h
@@ -0,0 +1,86 @@
+/*
+ * 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 MEDIA_BUFFER_BASE_H_
+
+#define MEDIA_BUFFER_BASE_H_
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class MediaBufferBase;
+class MetaData;
+
+class MediaBufferObserver {
+public:
+    MediaBufferObserver() {}
+    virtual ~MediaBufferObserver() {}
+
+    virtual void signalBufferReturned(MediaBufferBase *buffer) = 0;
+
+private:
+    MediaBufferObserver(const MediaBufferObserver &);
+    MediaBufferObserver &operator=(const MediaBufferObserver &);
+};
+
+class MediaBufferBase {
+public:
+    static MediaBufferBase *Create(size_t size);
+
+    // If MediaBufferGroup is set, decrement the local reference count;
+    // if the local reference count drops to 0, return the buffer to the
+    // associated MediaBufferGroup.
+    //
+    // If no MediaBufferGroup is set, the local reference count must be zero
+    // when called, whereupon the MediaBuffer is deleted.
+    virtual void release() = 0;
+
+    // Increments the local reference count.
+    // Use only when MediaBufferGroup is set.
+    virtual void add_ref() = 0;
+
+    virtual void *data() const = 0;
+    virtual size_t size() const = 0;
+
+    virtual size_t range_offset() const = 0;
+    virtual size_t range_length() const = 0;
+
+    virtual void set_range(size_t offset, size_t length) = 0;
+
+    virtual sp<MetaData> meta_data() = 0;
+
+    // Clears meta data and resets the range to the full extent.
+    virtual void reset() = 0;
+
+    virtual void setObserver(MediaBufferObserver *group) = 0;
+
+    // Returns a clone of this MediaBufferBase increasing its reference
+    // count. The clone references the same data but has its own range and
+    // MetaData.
+    virtual MediaBufferBase *clone() = 0;
+
+    virtual int refcount() const = 0;
+
+    virtual int localRefcount() const = 0;
+    virtual int remoteRefcount() const = 0;
+
+    virtual ~MediaBufferBase() {};
+};
+
+}  // namespace android
+
+#endif  // MEDIA_BUFFER_BASE_H_
diff --git a/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h b/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
index 3041181..75d5df7 100644
--- a/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
@@ -18,13 +18,15 @@
 
 #define MEDIA_BUFFER_GROUP_H_
 
-#include <media/stagefright/MediaBuffer.h>
+#include <list>
+
+#include <media/stagefright/MediaBufferBase.h>
 #include <utils/Errors.h>
 #include <utils/threads.h>
 
 namespace android {
 
-class MediaBuffer;
+class MediaBufferBase;
 
 class MediaBufferGroup : public MediaBufferObserver {
 public:
@@ -35,7 +37,7 @@
 
     ~MediaBufferGroup();
 
-    void add_buffer(MediaBuffer *buffer);
+    void add_buffer(MediaBufferBase *buffer);
 
     bool has_buffers();
 
@@ -48,20 +50,16 @@
     // If requestedSize is > 0, the returned MediaBuffer should have buffer
     // size of at least requstedSize.
     status_t acquire_buffer(
-            MediaBuffer **buffer, bool nonBlocking = false, size_t requestedSize = 0);
+            MediaBufferBase **buffer, bool nonBlocking = false, size_t requestedSize = 0);
 
-    size_t buffers() const { return mBuffers.size(); }
+    size_t buffers() const;
 
     // If buffer is nullptr, have acquire_buffer() check for remote release.
-    virtual void signalBufferReturned(MediaBuffer *buffer);
+    virtual void signalBufferReturned(MediaBufferBase *buffer);
 
 private:
-    friend class MediaBuffer;
-
-    Mutex mLock;
-    Condition mCondition;
-    size_t mGrowthLimit;  // Do not automatically grow group larger than this.
-    std::list<MediaBuffer *> mBuffers;
+    struct InternalData;
+    InternalData *mInternal;
 
     MediaBufferGroup(const MediaBufferGroup &);
     MediaBufferGroup &operator=(const MediaBufferGroup &);
diff --git a/media/libmediaextractor/include/media/stagefright/MetaData.h b/media/libmediaextractor/include/media/stagefright/MetaData.h
index e4a84b7..7562a72 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaData.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaData.h
@@ -149,8 +149,6 @@
     // To store the timed text format data
     kKeyTextFormatData    = 'text',  // raw data
 
-    kKeyRequiresSecureBuffers = 'secu',  // bool (int32_t)
-
     kKeyIsADTS            = 'adts',  // bool (int32_t)
     kKeyAACAOT            = 'aaot',  // int32_t
 
@@ -258,16 +256,16 @@
             int32_t left, int32_t top,
             int32_t right, int32_t bottom);
 
-    bool findCString(uint32_t key, const char **value);
-    bool findInt32(uint32_t key, int32_t *value);
-    bool findInt64(uint32_t key, int64_t *value);
-    bool findFloat(uint32_t key, float *value);
-    bool findPointer(uint32_t key, void **value);
+    bool findCString(uint32_t key, const char **value) const;
+    bool findInt32(uint32_t key, int32_t *value) const;
+    bool findInt64(uint32_t key, int64_t *value) const;
+    bool findFloat(uint32_t key, float *value) const;
+    bool findPointer(uint32_t key, void **value) const;
 
     bool findRect(
             uint32_t key,
             int32_t *left, int32_t *top,
-            int32_t *right, int32_t *bottom);
+            int32_t *right, int32_t *bottom) const;
 
     bool setData(uint32_t key, uint32_t type, const void *data, size_t size);
 
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 17fa01c..1fa8789 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -9,7 +9,7 @@
 
     srcs: [
         "JAudioTrack.cpp",
-        "MediaPlayer2Manager.cpp",
+        "MediaPlayer2AudioOutput.cpp",
         "mediaplayer2.cpp",
     ],
 
diff --git a/media/libmediaplayer2/JAudioTrack.cpp b/media/libmediaplayer2/JAudioTrack.cpp
index 6d9605a..ac0cc57 100644
--- a/media/libmediaplayer2/JAudioTrack.cpp
+++ b/media/libmediaplayer2/JAudioTrack.cpp
@@ -32,6 +32,8 @@
         uint32_t sampleRate,                          // AudioFormat && bufferSizeInBytes
         audio_format_t format,                        // AudioFormat && bufferSizeInBytes
         audio_channel_mask_t channelMask,             // AudioFormat && bufferSizeInBytes
+        callback_t cbf,                               // Offload
+        void* user,                                   // Offload
         size_t frameCount,                            // bufferSizeInBytes
         audio_session_t sessionId,                    // AudioTrack
         const audio_attributes_t* pAttributes,        // AudioAttributes
@@ -90,8 +92,27 @@
         jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
     }
 
+    if (cbf != NULL) {
+        jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
+                "(Z)Landroid/media/AudioTrack$Builder;");
+        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
+        mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+    }
+
     jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
     mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
+
+    if (cbf != NULL) {
+        // Set offload mode callback
+        jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
+        jobject jExecutorObj = createCallbackExecutor();
+        jmethodID jSetStreamEventCallback = env->GetMethodID(
+                jAudioTrackCls,
+                "setStreamEventCallback",
+                "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
+        env->CallVoidMethod(
+                mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
+    }
 }
 
 JAudioTrack::~JAudioTrack() {
@@ -160,6 +181,11 @@
     return true;
 }
 
+status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
+    // TODO: Implement this after appropriate Java AudioTrack method is available.
+    return NO_ERROR;
+}
+
 status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
     // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
     // Should we do the same thing?
@@ -442,6 +468,80 @@
     return routedDeviceId;
 }
 
+audio_session_t JAudioTrack::getAudioSessionId() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
+    jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
+    return (audio_session_t) sessionId;
+}
+
+status_t JAudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass jMP2ImplCls = env->FindClass("android/media/MediaPlayer2Impl");
+    jmethodID jSetAudioOutputDeviceById = env->GetMethodID(
+            jMP2ImplCls, "setAudioOutputDeviceById", "(Landroid/media/AudioTrack;I)Z");
+    jboolean result = env->CallStaticBooleanMethod(
+            jMP2ImplCls, jSetAudioOutputDeviceById, mAudioTrackObj, deviceId);
+    return result == true ? NO_ERROR : BAD_VALUE;
+}
+
+status_t JAudioTrack::pendingDuration(int32_t *msec) {
+    if (msec == nullptr) {
+        return BAD_VALUE;
+    }
+
+    bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
+    if (!isPurePcmData) {
+        return INVALID_OPERATION;
+    }
+
+    // TODO: Need to know the difference btw. client and server time.
+    // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
+    // (copied from AudioTrack.cpp)
+
+//    ExtendedTimestamp ets;
+//    ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
+//    if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
+//        int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
+//                - ets.mPosition[location];
+//        if (diff < 0) {
+//            *msec = 0;
+//        } else {
+//            // ms is the playback time by frames
+//            int64_t ms = (int64_t)((double)diff * 1000 /
+//                    ((double)mSampleRate * mPlaybackRate.mSpeed));
+//            // clockdiff is the timestamp age (negative)
+//            int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
+//                    ets.mTimeNs[location]
+//                    + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
+//                    - systemTime(SYSTEM_TIME_MONOTONIC);
+//
+//            //ALOGV("ms: %lld  clockdiff: %lld", (long long)ms, (long long)clockdiff);
+//            static const int NANOS_PER_MILLIS = 1000000;
+//            *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
+//        }
+//        return NO_ERROR;
+//    }
+
+    return NO_ERROR;
+}
+
+status_t JAudioTrack::addAudioDeviceCallback(
+        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
+    // TODO: Implement this after appropriate Java AudioTrack method is available.
+    return NO_ERROR;
+}
+
+status_t JAudioTrack::removeAudioDeviceCallback(
+        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
+    // TODO: Implement this after appropriate Java AudioTrack method is available.
+    return NO_ERROR;
+}
+
+/////////////////////////////////////////////////////////////
+///                Private method begins                  ///
+/////////////////////////////////////////////////////////////
+
 jobject JAudioTrack::createVolumeShaperConfigurationObj(
         const sp<media::VolumeShaper::Configuration>& config) {
 
@@ -546,6 +646,24 @@
     return env->CallObjectMethod(jBuilderObj, jBuild);
 }
 
+jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2Impl$StreamEventCallback");
+    jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
+    jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
+    return jCallbackObj;
+}
+
+jobject JAudioTrack::createCallbackExecutor() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
+    jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
+            "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
+    jobject jSingleThreadExecutorObj =
+            env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
+    return jSingleThreadExecutorObj;
+}
+
 status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
     switch (javaStatus) {
     case AUDIO_JAVA_SUCCESS:
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
new file mode 100644
index 0000000..a8e1d1f
--- /dev/null
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -0,0 +1,727 @@
+/*
+**
+** 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 "MediaPlayer2AudioOutput"
+#include <mediaplayer2/MediaPlayer2AudioOutput.h>
+
+#include <cutils/properties.h> // for property_get
+#include <utils/Log.h>
+
+#include <media/AudioPolicyHelper.h>
+#include <media/AudioTrack.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace {
+
+const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
+
+} // anonymous namespace
+
+namespace android {
+
+// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
+/* static */ int MediaPlayer2AudioOutput::mMinBufferCount = 4;
+/* static */ bool MediaPlayer2AudioOutput::mIsOnEmulator = false;
+
+status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) const {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    result.append(" MediaPlayer2AudioOutput\n");
+    snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n",
+            mStreamType, mLeftVolume, mRightVolume);
+    result.append(buffer);
+    snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
+            mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
+    result.append(buffer);
+    snprintf(buffer, 255, "  aux effect id(%d), send level (%f)\n",
+            mAuxEffectId, mSendLevel);
+    result.append(buffer);
+
+    ::write(fd, result.string(), result.size());
+    if (mTrack != 0) {
+        mTrack->dump(fd, args);
+    }
+    return NO_ERROR;
+}
+
+MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
+        const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
+    : mCallback(NULL),
+      mCallbackCookie(NULL),
+      mCallbackData(NULL),
+      mStreamType(AUDIO_STREAM_MUSIC),
+      mLeftVolume(1.0),
+      mRightVolume(1.0),
+      mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
+      mSampleRateHz(0),
+      mMsecsPerFrame(0),
+      mFrameSize(0),
+      mSessionId(sessionId),
+      mUid(uid),
+      mPid(pid),
+      mSendLevel(0.0),
+      mAuxEffectId(0),
+      mFlags(AUDIO_OUTPUT_FLAG_NONE),
+      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+      mDeviceCallbackEnabled(false),
+      mDeviceCallback(deviceCallback) {
+    ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
+    if (attr != NULL) {
+        mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+        if (mAttributes != NULL) {
+            memcpy(mAttributes, attr, sizeof(audio_attributes_t));
+            mStreamType = audio_attributes_to_stream_type(attr);
+        }
+    } else {
+        mAttributes = NULL;
+    }
+
+    setMinBufferCount();
+}
+
+MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
+    close();
+    free(mAttributes);
+    delete mCallbackData;
+}
+
+//static
+void MediaPlayer2AudioOutput::setMinBufferCount() {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("ro.kernel.qemu", value, 0)) {
+        mIsOnEmulator = true;
+        mMinBufferCount = 12;  // to prevent systematic buffer underrun for emulator
+    }
+}
+
+// static
+bool MediaPlayer2AudioOutput::isOnEmulator() {
+    setMinBufferCount();  // benign race wrt other threads
+    return mIsOnEmulator;
+}
+
+// static
+int MediaPlayer2AudioOutput::getMinBufferCount() {
+    setMinBufferCount();  // benign race wrt other threads
+    return mMinBufferCount;
+}
+
+ssize_t MediaPlayer2AudioOutput::bufferSize() const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    return mTrack->frameCount() * mFrameSize;
+}
+
+ssize_t MediaPlayer2AudioOutput::frameCount() const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    return mTrack->frameCount();
+}
+
+ssize_t MediaPlayer2AudioOutput::channelCount() const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    return mTrack->channelCount();
+}
+
+ssize_t MediaPlayer2AudioOutput::frameSize() const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    return mFrameSize;
+}
+
+uint32_t MediaPlayer2AudioOutput::latency () const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return 0;
+    }
+    return mTrack->latency();
+}
+
+float MediaPlayer2AudioOutput::msecsPerFrame() const {
+    Mutex::Autolock lock(mLock);
+    return mMsecsPerFrame;
+}
+
+status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    return mTrack->getPosition(position);
+}
+
+status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    return mTrack->getTimestamp(ts);
+}
+
+// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
+// as it acquires locks and may query the audio driver.
+//
+// Some calls could conceivably retrieve extrapolated data instead of
+// accessing getTimestamp() or getPosition() every time a data buffer with
+// a media time is received.
+//
+// Calculate duration of played samples if played at normal rate (i.e., 1.0).
+int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0 || mSampleRateHz == 0) {
+        return 0;
+    }
+
+    uint32_t numFramesPlayed;
+    int64_t numFramesPlayedAtUs;
+    AudioTimestamp ts;
+
+    status_t res = mTrack->getTimestamp(ts);
+    if (res == OK) {                 // case 1: mixing audio tracks and offloaded tracks.
+        numFramesPlayed = ts.mPosition;
+        numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+        //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
+    } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+        numFramesPlayed = 0;
+        numFramesPlayedAtUs = nowUs;
+        //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
+        //        numFramesPlayed, (long long)numFramesPlayedAtUs);
+    } else {                         // case 3: transitory at new track or audio fast tracks.
+        res = mTrack->getPosition(&numFramesPlayed);
+        CHECK_EQ(res, (status_t)OK);
+        numFramesPlayedAtUs = nowUs;
+        numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
+        //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
+    }
+
+    // CHECK_EQ(numFramesPlayed & (1 << 31), 0);  // can't be negative until 12.4 hrs, test
+    // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+    int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
+            + nowUs - numFramesPlayedAtUs;
+    if (durationUs < 0) {
+        // Occurs when numFramesPlayed position is very small and the following:
+        // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
+        //     numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
+        // (2) In case 3, using getPosition and adding mAudioSink->latency() to
+        //     numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
+        //
+        // Both of these are transitory conditions.
+        ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
+        durationUs = 0;
+    }
+    ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
+            (long long)durationUs, (long long)nowUs,
+            numFramesPlayed, (long long)numFramesPlayedAtUs);
+    return durationUs;
+}
+
+status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    ExtendedTimestamp ets;
+    status_t status = mTrack->getTimestamp(&ets);
+    if (status == OK || status == WOULD_BLOCK) {
+        *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
+    }
+    return status;
+}
+
+status_t MediaPlayer2AudioOutput::setParameters(const String8& keyValuePairs) {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    return mTrack->setParameters(keyValuePairs);
+}
+
+String8  MediaPlayer2AudioOutput::getParameters(const String8& keys) {
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return String8::empty();
+    }
+    return mTrack->getParameters(keys);
+}
+
+void MediaPlayer2AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
+    Mutex::Autolock lock(mLock);
+    if (attributes == NULL) {
+        free(mAttributes);
+        mAttributes = NULL;
+    } else {
+        if (mAttributes == NULL) {
+            mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+        }
+        memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
+        mStreamType = audio_attributes_to_stream_type(attributes);
+    }
+}
+
+void MediaPlayer2AudioOutput::setAudioStreamType(audio_stream_type_t streamType) {
+    Mutex::Autolock lock(mLock);
+    // do not allow direct stream type modification if attributes have been set
+    if (mAttributes == NULL) {
+        mStreamType = streamType;
+    }
+}
+
+void MediaPlayer2AudioOutput::close_l() {
+    mTrack.clear();
+}
+
+status_t MediaPlayer2AudioOutput::open(
+        uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
+        audio_format_t format, int bufferCount,
+        AudioCallback cb, void *cookie,
+        audio_output_flags_t flags,
+        const audio_offload_info_t *offloadInfo,
+        bool doNotReconnect,
+        uint32_t suggestedFrameCount) {
+    ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
+                format, bufferCount, mSessionId, flags);
+
+    // offloading is only supported in callback mode for now.
+    // offloadInfo must be present if offload flag is set
+    if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
+            ((cb == NULL) || (offloadInfo == NULL))) {
+        return BAD_VALUE;
+    }
+
+    // compute frame count for the AudioTrack internal buffer
+    size_t frameCount;
+    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+        frameCount = 0; // AudioTrack will get frame count from AudioFlinger
+    } else {
+        // try to estimate the buffer processing fetch size from AudioFlinger.
+        // framesPerBuffer is approximate and generally correct, except when it's not :-).
+        uint32_t afSampleRate;
+        size_t afFrameCount;
+        if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
+            return NO_INIT;
+        }
+        if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
+            return NO_INIT;
+        }
+        const size_t framesPerBuffer =
+                (unsigned long long)sampleRate * afFrameCount / afSampleRate;
+
+        if (bufferCount == 0) {
+            // use suggestedFrameCount
+            bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
+        }
+        // Check argument bufferCount against the mininum buffer count
+        if (bufferCount != 0 && bufferCount < mMinBufferCount) {
+            ALOGV("bufferCount (%d) increased to %d", bufferCount, mMinBufferCount);
+            bufferCount = mMinBufferCount;
+        }
+        // if frameCount is 0, then AudioTrack will get frame count from AudioFlinger
+        // which will be the minimum size permitted.
+        frameCount = bufferCount * framesPerBuffer;
+    }
+
+    if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
+        channelMask = audio_channel_out_mask_from_count(channelCount);
+        if (0 == channelMask) {
+            ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
+            return NO_INIT;
+        }
+    }
+
+    Mutex::Autolock lock(mLock);
+    mCallback = cb;
+    mCallbackCookie = cookie;
+
+    sp<AudioTrack> t;
+    CallbackData *newcbd = NULL;
+
+    ALOGV("creating new AudioTrack");
+
+    if (mCallback != NULL) {
+        newcbd = new CallbackData(this);
+        t = new AudioTrack(
+                mStreamType,
+                sampleRate,
+                format,
+                channelMask,
+                frameCount,
+                flags,
+                CallbackWrapper,
+                newcbd,
+                0,  // notification frames
+                mSessionId,
+                AudioTrack::TRANSFER_CALLBACK,
+                offloadInfo,
+                mUid,
+                mPid,
+                mAttributes,
+                doNotReconnect,
+                1.0f,  // default value for maxRequiredSpeed
+                mSelectedDeviceId);
+    } else {
+        // TODO: Due to buffer memory concerns, we use a max target playback speed
+        // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
+        // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
+        const float targetSpeed =
+                std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
+        ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
+                "track target speed:%f clamped from playback speed:%f",
+                targetSpeed, mPlaybackRate.mSpeed);
+        t = new AudioTrack(
+                mStreamType,
+                sampleRate,
+                format,
+                channelMask,
+                frameCount,
+                flags,
+                NULL, // callback
+                NULL, // user data
+                0, // notification frames
+                mSessionId,
+                AudioTrack::TRANSFER_DEFAULT,
+                NULL, // offload info
+                mUid,
+                mPid,
+                mAttributes,
+                doNotReconnect,
+                targetSpeed,
+                mSelectedDeviceId);
+    }
+
+    if ((t == 0) || (t->initCheck() != NO_ERROR)) {
+        ALOGE("Unable to create audio track");
+        delete newcbd;
+        // t goes out of scope, so reference count drops to zero
+        return NO_INIT;
+    } else {
+        // successful AudioTrack initialization implies a legacy stream type was generated
+        // from the audio attributes
+        mStreamType = t->streamType();
+    }
+
+    CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
+
+    mCallbackData = newcbd;
+    ALOGV("setVolume");
+    t->setVolume(mLeftVolume, mRightVolume);
+
+    mSampleRateHz = sampleRate;
+    mFlags = flags;
+    mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
+    mFrameSize = t->frameSize();
+    mTrack = t;
+
+    return updateTrack_l();
+}
+
+status_t MediaPlayer2AudioOutput::updateTrack_l() {
+    if (mTrack == NULL) {
+        return NO_ERROR;
+    }
+
+    status_t res = NO_ERROR;
+    // Note some output devices may give us a direct track even though we don't specify it.
+    // Example: Line application b/17459982.
+    if ((mTrack->getFlags()
+            & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
+        res = mTrack->setPlaybackRate(mPlaybackRate);
+        if (res == NO_ERROR) {
+            mTrack->setAuxEffectSendLevel(mSendLevel);
+            res = mTrack->attachAuxEffect(mAuxEffectId);
+        }
+    }
+    mTrack->setOutputDevice(mSelectedDeviceId);
+    if (mDeviceCallbackEnabled) {
+        mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+    }
+    ALOGV("updateTrack_l() DONE status %d", res);
+    return res;
+}
+
+status_t MediaPlayer2AudioOutput::start() {
+    ALOGV("start");
+    Mutex::Autolock lock(mLock);
+    if (mCallbackData != NULL) {
+        mCallbackData->endTrackSwitch();
+    }
+    if (mTrack != 0) {
+        mTrack->setVolume(mLeftVolume, mRightVolume);
+        mTrack->setAuxEffectSendLevel(mSendLevel);
+        status_t status = mTrack->start();
+        return status;
+    }
+    return NO_INIT;
+}
+
+ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
+    Mutex::Autolock lock(mLock);
+    LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+
+    //ALOGV("write(%p, %u)", buffer, size);
+    if (mTrack != 0) {
+        return mTrack->write(buffer, size, blocking);
+    }
+    return NO_INIT;
+}
+
+void MediaPlayer2AudioOutput::stop() {
+    ALOGV("stop");
+    Mutex::Autolock lock(mLock);
+    if (mTrack != 0) {
+        mTrack->stop();
+    }
+}
+
+void MediaPlayer2AudioOutput::flush() {
+    ALOGV("flush");
+    Mutex::Autolock lock(mLock);
+    if (mTrack != 0) {
+        mTrack->flush();
+    }
+}
+
+void MediaPlayer2AudioOutput::pause() {
+    ALOGV("pause");
+    Mutex::Autolock lock(mLock);
+    if (mTrack != 0) {
+        mTrack->pause();
+    }
+}
+
+void MediaPlayer2AudioOutput::close() {
+    ALOGV("close");
+    sp<AudioTrack> track;
+    {
+        Mutex::Autolock lock(mLock);
+        track = mTrack;
+        close_l(); // clears mTrack
+    }
+    // destruction of the track occurs outside of mutex.
+}
+
+void MediaPlayer2AudioOutput::setVolume(float left, float right) {
+    ALOGV("setVolume(%f, %f)", left, right);
+    Mutex::Autolock lock(mLock);
+    mLeftVolume = left;
+    mRightVolume = right;
+    if (mTrack != 0) {
+        mTrack->setVolume(left, right);
+    }
+}
+
+status_t MediaPlayer2AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) {
+    ALOGV("setPlaybackRate(%f %f %d %d)",
+                rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        // remember rate so that we can set it when the track is opened
+        mPlaybackRate = rate;
+        return OK;
+    }
+    status_t res = mTrack->setPlaybackRate(rate);
+    if (res != NO_ERROR) {
+        return res;
+    }
+    // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
+    CHECK_GT(rate.mSpeed, 0.f);
+    mPlaybackRate = rate;
+    if (mSampleRateHz != 0) {
+        mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
+    }
+    return res;
+}
+
+status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
+    ALOGV("setPlaybackRate");
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return NO_INIT;
+    }
+    *rate = mTrack->getPlaybackRate();
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::setAuxEffectSendLevel(float level) {
+    ALOGV("setAuxEffectSendLevel(%f)", level);
+    Mutex::Autolock lock(mLock);
+    mSendLevel = level;
+    if (mTrack != 0) {
+        return mTrack->setAuxEffectSendLevel(level);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::attachAuxEffect(int effectId) {
+    ALOGV("attachAuxEffect(%d)", effectId);
+    Mutex::Autolock lock(mLock);
+    mAuxEffectId = effectId;
+    if (mTrack != 0) {
+        return mTrack->attachAuxEffect(effectId);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::setOutputDevice(audio_port_handle_t deviceId) {
+    ALOGV("setOutputDevice(%d)", deviceId);
+    Mutex::Autolock lock(mLock);
+    mSelectedDeviceId = deviceId;
+    if (mTrack != 0) {
+        return mTrack->setOutputDevice(deviceId);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId) {
+    ALOGV("getRoutedDeviceId");
+    Mutex::Autolock lock(mLock);
+    if (mTrack != 0) {
+        mRoutedDeviceId = mTrack->getRoutedDeviceId();
+    }
+    *deviceId = mRoutedDeviceId;
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::enableAudioDeviceCallback(bool enabled) {
+    ALOGV("enableAudioDeviceCallback, %d", enabled);
+    Mutex::Autolock lock(mLock);
+    mDeviceCallbackEnabled = enabled;
+    if (mTrack != 0) {
+        status_t status;
+        if (enabled) {
+            status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+        } else {
+            status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
+        }
+        return status;
+    }
+    return NO_ERROR;
+}
+
+// static
+void MediaPlayer2AudioOutput::CallbackWrapper(
+        int event, void *cookie, void *info) {
+    //ALOGV("callbackwrapper");
+    CallbackData *data = (CallbackData*)cookie;
+    // lock to ensure we aren't caught in the middle of a track switch.
+    data->lock();
+    MediaPlayer2AudioOutput *me = data->getOutput();
+    AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+    if (me == NULL) {
+        // no output set, likely because the track was scheduled to be reused
+        // by another player, but the format turned out to be incompatible.
+        data->unlock();
+        if (buffer != NULL) {
+            buffer->size = 0;
+        }
+        return;
+    }
+
+    switch(event) {
+    case AudioTrack::EVENT_MORE_DATA: {
+        size_t actualSize = (*me->mCallback)(
+                me, buffer->raw, buffer->size, me->mCallbackCookie,
+                CB_EVENT_FILL_BUFFER);
+
+        // Log when no data is returned from the callback.
+        // (1) We may have no data (especially with network streaming sources).
+        // (2) We may have reached the EOS and the audio track is not stopped yet.
+        // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
+        // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
+        //
+        // This is a benign busy-wait, with the next data request generated 10 ms or more later;
+        // nevertheless for power reasons, we don't want to see too many of these.
+
+        ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned");
+
+        buffer->size = actualSize;
+        } break;
+
+    case AudioTrack::EVENT_STREAM_END:
+        // currently only occurs for offloaded callbacks
+        ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
+        (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+                me->mCallbackCookie, CB_EVENT_STREAM_END);
+        break;
+
+    case AudioTrack::EVENT_NEW_IAUDIOTRACK :
+        ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
+        (*me->mCallback)(me,  NULL /* buffer */, 0 /* size */,
+                me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
+        break;
+
+    case AudioTrack::EVENT_UNDERRUN:
+        // This occurs when there is no data available, typically
+        // when there is a failure to supply data to the AudioTrack.  It can also
+        // occur in non-offloaded mode when the audio device comes out of standby.
+        //
+        // If an AudioTrack underruns it outputs silence. Since this happens suddenly
+        // it may sound like an audible pop or glitch.
+        //
+        // The underrun event is sent once per track underrun; the condition is reset
+        // when more data is sent to the AudioTrack.
+        ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
+        break;
+
+    default:
+        ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
+    }
+
+    data->unlock();
+}
+
+audio_session_t MediaPlayer2AudioOutput::getSessionId() const
+{
+    Mutex::Autolock lock(mLock);
+    return mSessionId;
+}
+
+uint32_t MediaPlayer2AudioOutput::getSampleRate() const
+{
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return 0;
+    }
+    return mTrack->getSampleRate();
+}
+
+int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const
+{
+    Mutex::Autolock lock(mLock);
+    if (mTrack == 0) {
+        return 0;
+    }
+    int64_t duration;
+    if (mTrack->getBufferDurationInUs(&duration) != OK) {
+        return 0;
+    }
+    return duration;
+}
+
+} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.cpp b/media/libmediaplayer2/MediaPlayer2Manager.cpp
deleted file mode 100644
index 44df2ac..0000000
--- a/media/libmediaplayer2/MediaPlayer2Manager.cpp
+++ /dev/null
@@ -1,2086 +0,0 @@
-/*
-**
-** Copyright 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.
-*/
-
-// Proxy for media player implementations
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2Manager"
-#include <utils/Log.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#include <string.h>
-
-#include <cutils/atomic.h>
-#include <cutils/properties.h> // for property_get
-
-#include <utils/misc.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
-#include <utils/Errors.h>  // for status_t
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <media/AudioPolicyHelper.h>
-#include <media/DataSourceDesc.h>
-#include <media/MediaHTTPService.h>
-#include <media/Metadata.h>
-#include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/NdkWrapper.h>
-
-#include <media/stagefright/InterfaceUtils.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 <media/stagefright/SurfaceUtils.h>
-#include <mediautils/BatteryNotifier.h>
-
-#include <mediaplayer2/MediaPlayer2EngineClient.h>
-#include <mediaplayer2/MediaPlayer2Interface.h>
-
-#include <memunreachable/memunreachable.h>
-#include <system/audio.h>
-#include <system/window.h>
-
-#include <private/android_filesystem_config.h>
-
-#include <nuplayer2/NuPlayer2Driver.h>
-#include "MediaPlayer2Manager.h"
-
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleepUs = 20000;
-
-namespace {
-using android::media::Metadata;
-using android::status_t;
-using android::OK;
-using android::BAD_VALUE;
-using android::NOT_ENOUGH_DATA;
-using android::Parcel;
-
-// Max number of entries in the filter.
-const int kMaxFilterSize = 64;  // I pulled that out of thin air.
-
-const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
-
-// FIXME: Move all the metadata related function in the Metadata.cpp
-
-
-// Unmarshall a filter from a Parcel.
-// Filter format in a parcel:
-//
-//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       number of entries (n)                   |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       metadata type 1                         |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       metadata type 2                         |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//  ....
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       metadata type n                         |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-// @param p Parcel that should start with a filter.
-// @param[out] filter On exit contains the list of metadata type to be
-//                    filtered.
-// @param[out] status On exit contains the status code to be returned.
-// @return true if the parcel starts with a valid filter.
-bool unmarshallFilter(const Parcel& p,
-                      Metadata::Filter *filter,
-                      status_t *status)
-{
-    int32_t val;
-    if (p.readInt32(&val) != OK)
-    {
-        ALOGE("Failed to read filter's length");
-        *status = NOT_ENOUGH_DATA;
-        return false;
-    }
-
-    if( val > kMaxFilterSize || val < 0)
-    {
-        ALOGE("Invalid filter len %d", val);
-        *status = BAD_VALUE;
-        return false;
-    }
-
-    const size_t num = val;
-
-    filter->clear();
-    filter->setCapacity(num);
-
-    size_t size = num * sizeof(Metadata::Type);
-
-
-    if (p.dataAvail() < size)
-    {
-        ALOGE("Filter too short expected %zu but got %zu", size, p.dataAvail());
-        *status = NOT_ENOUGH_DATA;
-        return false;
-    }
-
-    const Metadata::Type *data =
-            static_cast<const Metadata::Type*>(p.readInplace(size));
-
-    if (NULL == data)
-    {
-        ALOGE("Filter had no data");
-        *status = BAD_VALUE;
-        return false;
-    }
-
-    // TODO: The stl impl of vector would be more efficient here
-    // because it degenerates into a memcpy on pod types. Try to
-    // replace later or use stl::set.
-    for (size_t i = 0; i < num; ++i)
-    {
-        filter->add(*data);
-        ++data;
-    }
-    *status = OK;
-    return true;
-}
-
-// @param filter Of metadata type.
-// @param val To be searched.
-// @return true if a match was found.
-bool findMetadata(const Metadata::Filter& filter, const int32_t val)
-{
-    // Deal with empty and ANY right away
-    if (filter.isEmpty()) return false;
-    if (filter[0] == Metadata::kAny) return true;
-
-    return filter.indexOf(val) >= 0;
-}
-
-}  // anonymous namespace
-
-
-namespace {
-using android::Parcel;
-using android::String16;
-
-// marshalling tag indicating flattened utf16 tags
-// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java
-const int32_t kAudioAttributesMarshallTagFlattenTags = 1;
-
-// Audio attributes format in a parcel:
-//
-//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       usage                                   |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       content_type                            |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       source                                  |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       flags                                   |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       kAudioAttributesMarshallTagFlattenTags  | // ignore tags if not found
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |                       flattened tags in UTF16                 |
-// |                         ...                                   |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-// @param p Parcel that contains audio attributes.
-// @param[out] attributes On exit points to an initialized audio_attributes_t structure
-// @param[out] status On exit contains the status code to be returned.
-void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes)
-{
-    attributes->usage = (audio_usage_t) parcel.readInt32();
-    attributes->content_type = (audio_content_type_t) parcel.readInt32();
-    attributes->source = (audio_source_t) parcel.readInt32();
-    attributes->flags = (audio_flags_mask_t) parcel.readInt32();
-    const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags);
-    if (hasFlattenedTag) {
-        // the tags are UTF16, convert to UTF8
-        String16 tags = parcel.readString16();
-        ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size());
-        if (realTagSize <= 0) {
-            strcpy(attributes->tags, "");
-        } else {
-            // copy the flattened string into the attributes as the destination for the conversion:
-            // copying array size -1, array for tags was calloc'd, no need to NULL-terminate it
-            size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ?
-                    AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize;
-            utf16_to_utf8(tags.string(), tagSize, attributes->tags,
-                    sizeof(attributes->tags) / sizeof(attributes->tags[0]));
-        }
-    } else {
-        ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values");
-        strcpy(attributes->tags, "");
-    }
-}
-} // anonymous namespace
-
-
-namespace android {
-
-extern ALooperRoster gLooperRoster;
-
-MediaPlayer2Manager gMediaPlayer2Manager;
-
-// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
-/* static */ int MediaPlayer2Manager::AudioOutput::mMinBufferCount = 4;
-/* static */ bool MediaPlayer2Manager::AudioOutput::mIsOnEmulator = false;
-
-// static
-MediaPlayer2Manager& MediaPlayer2Manager::get() {
-    return gMediaPlayer2Manager;
-}
-
-MediaPlayer2Manager::MediaPlayer2Manager() {
-    ALOGV("MediaPlayer2Manager created");
-    // TODO: remove all unnecessary pid/uid handling.
-    mPid = IPCThreadState::self()->getCallingPid();
-    mUid = IPCThreadState::self()->getCallingUid();
-    mNextConnId = 1;
-}
-
-MediaPlayer2Manager::~MediaPlayer2Manager() {
-    ALOGV("MediaPlayer2Manager destroyed");
-}
-
-sp<MediaPlayer2Engine> MediaPlayer2Manager::create(
-        const sp<MediaPlayer2EngineClient>& client,
-        audio_session_t audioSessionId)
-{
-    int32_t connId = android_atomic_inc(&mNextConnId);
-
-    sp<Client> c = new Client(
-            mPid, connId, client, audioSessionId, mUid);
-
-    if (!c->init()) {
-        return NULL;
-    }
-
-    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, mPid, mUid);
-
-    wp<Client> w = c;
-    {
-        Mutex::Autolock lock(mLock);
-        mClients.add(w);
-    }
-    return c;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::dump(int fd, const Vector<String16>& args) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    result.append(" AudioOutput\n");
-    snprintf(buffer, 255, "  stream type(%d), left - right volume(%f, %f)\n",
-            mStreamType, mLeftVolume, mRightVolume);
-    result.append(buffer);
-    snprintf(buffer, 255, "  msec per frame(%f), latency (%d)\n",
-            mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
-    result.append(buffer);
-    snprintf(buffer, 255, "  aux effect id(%d), send level (%f)\n",
-            mAuxEffectId, mSendLevel);
-    result.append(buffer);
-
-    ::write(fd, result.string(), result.size());
-    if (mTrack != 0) {
-        mTrack->dump(fd, args);
-    }
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::dump(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    result.append(" Client\n");
-    snprintf(buffer, 255, "  pid(%d), connId(%d), status(%d), looping(%s)\n",
-            mPid, mConnId, mStatus, mLoop?"true": "false");
-    result.append(buffer);
-
-    sp<MediaPlayer2Interface> p;
-    sp<AudioOutput> audioOutput;
-    bool locked = false;
-    for (int i = 0; i < kDumpLockRetries; ++i) {
-        if (mLock.tryLock() == NO_ERROR) {
-            locked = true;
-            break;
-        }
-        usleep(kDumpLockSleepUs);
-    }
-
-    if (locked) {
-        p = mPlayer;
-        audioOutput = mAudioOutput;
-        mLock.unlock();
-    } else {
-        result.append("  lock is taken, no dump from player and audio output\n");
-    }
-    write(fd, result.string(), result.size());
-
-    if (p != NULL) {
-        p->dump(fd, args);
-    }
-    if (audioOutput != 0) {
-        audioOutput->dump(fd, args);
-    }
-    write(fd, "\n", 1);
-    return NO_ERROR;
-}
-
-/**
- * The only arguments this understands right now are -c, -von and -voff,
- * which are parsed by ALooperRoster::dump()
- */
-status_t MediaPlayer2Manager::dump(int fd, const Vector<String16>& args)
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    SortedVector< sp<Client> > clients; //to serialise the mutex unlock & client destruction.
-
-    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: "
-                "can't dump MediaPlayer2Manager from pid=%d, uid=%d\n",
-                mPid, mUid);
-        result.append(buffer);
-    } else {
-        Mutex::Autolock lock(mLock);
-        for (int i = 0, n = mClients.size(); i < n; ++i) {
-            sp<Client> c = mClients[i].promote();
-            if (c != 0) c->dump(fd, args);
-            clients.add(c);
-        }
-
-        result.append(" Files opened and/or mapped:\n");
-        snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
-        FILE *f = fopen(buffer, "r");
-        if (f) {
-            while (!feof(f)) {
-                fgets(buffer, SIZE, f);
-                if (strstr(buffer, " /storage/") ||
-                    strstr(buffer, " /system/sounds/") ||
-                    strstr(buffer, " /data/") ||
-                    strstr(buffer, " /system/media/")) {
-                    result.append("  ");
-                    result.append(buffer);
-                }
-            }
-            fclose(f);
-        } else {
-            result.append("couldn't open ");
-            result.append(buffer);
-            result.append("\n");
-        }
-
-        snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
-        DIR *d = opendir(buffer);
-        if (d) {
-            struct dirent *ent;
-            while((ent = readdir(d)) != NULL) {
-                if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
-                    snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
-                    struct stat s;
-                    if (lstat(buffer, &s) == 0) {
-                        if ((s.st_mode & S_IFMT) == S_IFLNK) {
-                            char linkto[256];
-                            int len = readlink(buffer, linkto, sizeof(linkto));
-                            if(len > 0) {
-                                if(len > 255) {
-                                    linkto[252] = '.';
-                                    linkto[253] = '.';
-                                    linkto[254] = '.';
-                                    linkto[255] = 0;
-                                } else {
-                                    linkto[len] = 0;
-                                }
-                                if (strstr(linkto, "/storage/") == linkto ||
-                                    strstr(linkto, "/system/sounds/") == linkto ||
-                                    strstr(linkto, "/data/") == linkto ||
-                                    strstr(linkto, "/system/media/") == linkto) {
-                                    result.append("  ");
-                                    result.append(buffer);
-                                    result.append(" -> ");
-                                    result.append(linkto);
-                                    result.append("\n");
-                                }
-                            }
-                        } else {
-                            result.append("  unexpected type for ");
-                            result.append(buffer);
-                            result.append("\n");
-                        }
-                    }
-                }
-            }
-            closedir(d);
-        } else {
-            result.append("couldn't open ");
-            result.append(buffer);
-            result.append("\n");
-        }
-
-        gLooperRoster.dump(fd, args);
-
-        bool dumpMem = false;
-        bool unreachableMemory = false;
-        for (size_t i = 0; i < args.size(); i++) {
-            if (args[i] == String16("-m")) {
-                dumpMem = true;
-            } else if (args[i] == String16("--unreachable")) {
-                unreachableMemory = true;
-            }
-        }
-        if (dumpMem) {
-            result.append("\nDumping memory:\n");
-            std::string s = dumpMemoryAddresses(100 /* limit */);
-            result.append(s.c_str(), s.size());
-        }
-        if (unreachableMemory) {
-            result.append("\nDumping unreachable memory:\n");
-            // TODO - should limit be an argument parameter?
-            // TODO: enable GetUnreachableMemoryString if it's part of stable API
-            //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
-            //result.append(s.c_str(), s.size());
-        }
-    }
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-void MediaPlayer2Manager::removeClient(const wp<Client>& client)
-{
-    Mutex::Autolock lock(mLock);
-    mClients.remove(client);
-}
-
-bool MediaPlayer2Manager::hasClient(wp<Client> client)
-{
-    Mutex::Autolock lock(mLock);
-    return mClients.indexOf(client) != NAME_NOT_FOUND;
-}
-
-MediaPlayer2Manager::Client::Client(
-        pid_t pid,
-        int32_t connId,
-        const sp<MediaPlayer2EngineClient>& client,
-        audio_session_t audioSessionId,
-        uid_t uid)
-{
-    ALOGV("Client(%d) constructor", connId);
-    mPid = pid;
-    mConnId = connId;
-    mClient = client;
-    mLoop = false;
-    mStatus = NO_INIT;
-    mAudioSessionId = audioSessionId;
-    mUid = uid;
-    mAudioAttributes = NULL;
-
-#if CALLBACK_ANTAGONIZER
-    ALOGD("create Antagonizer");
-    mAntagonizer = new Antagonizer(notify, this);
-#endif
-}
-
-bool MediaPlayer2Manager::Client::init() {
-    sp<MediaPlayer2Interface> p = new NuPlayer2Driver(mPid, mUid);
-    status_t init_result = p->initCheck();
-    if (init_result != NO_ERROR) {
-        ALOGE("Failed to create player object, initCheck failed(%d)", init_result);
-        return false;
-    }
-
-    p->setNotifyCallback(this, notify);
-    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
-    mAudioOutput = new AudioOutput(mAudioSessionId, mUid,
-            mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
-    p->setAudioSink(mAudioOutput);
-
-    mPlayer = p;
-    return true;
-}
-
-MediaPlayer2Manager::Client::~Client()
-{
-    ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
-    mAudioOutput.clear();
-    wp<Client> client(this);
-    disconnect();
-    gMediaPlayer2Manager.removeClient(client);
-    if (mAudioAttributes != NULL) {
-        free(mAudioAttributes);
-    }
-    mAudioDeviceUpdatedListener.clear();
-}
-
-void MediaPlayer2Manager::Client::disconnect()
-{
-    ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
-    // grab local reference and clear main reference to prevent future
-    // access to object
-    sp<MediaPlayer2Interface> p;
-    {
-        Mutex::Autolock l(mLock);
-        p = mPlayer;
-        mClient.clear();
-        mPlayer.clear();
-    }
-
-    // clear the notification to prevent callbacks to dead client
-    // and reset the player. We assume the player will serialize
-    // access to itself if necessary.
-    if (p != 0) {
-        p->setNotifyCallback(0, 0);
-#if CALLBACK_ANTAGONIZER
-        ALOGD("kill Antagonizer");
-        mAntagonizer->kill();
-#endif
-        p->reset();
-    }
-
-    {
-        Mutex::Autolock l(mLock);
-        disconnectNativeWindow_l();
-    }
-
-    IPCThreadState::self()->flushCommands();
-}
-
-void MediaPlayer2Manager::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
-        audio_io_handle_t audioIo,
-        audio_port_handle_t deviceId) {
-    sp<MediaPlayer2Interface> listener = mListener.promote();
-    if (listener != NULL) {
-        listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
-    } else {
-        ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
-    }
-}
-
-status_t MediaPlayer2Manager::Client::setDataSource(
-        const sp<DataSourceDesc> &dsd) {
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == NULL) {
-        return NO_INIT;
-    }
-
-    if (dsd == NULL) {
-        return BAD_VALUE;
-    }
-
-    status_t status = p->setDataSource(dsd);
-    if (status != OK) {
-        ALOGE("setDataSource error: %d", status);
-        return status;
-    }
-
-    return status;
-}
-
-void MediaPlayer2Manager::Client::disconnectNativeWindow_l() {
-    if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
-        status_t err = native_window_api_disconnect(
-                mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
-        if (err != OK) {
-            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
-                    strerror(-err), err);
-        }
-    }
-    mConnectedWindow.clear();
-}
-
-status_t MediaPlayer2Manager::Client::setVideoSurfaceTexture(
-        const sp<ANativeWindowWrapper>& nww)
-{
-    ALOGV("[%d] setVideoSurfaceTexture(%p)",
-          mConnId,
-          (nww == NULL ? NULL : nww->getANativeWindow()));
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-
-    if (nww != NULL && nww->getANativeWindow() != NULL) {
-        if (mConnectedWindow != NULL
-            && mConnectedWindow->getANativeWindow() == nww->getANativeWindow()) {
-            return OK;
-        }
-        status_t err = native_window_api_connect(
-                nww->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
-        if (err != OK) {
-            ALOGE("setVideoSurfaceTexture failed: %d", err);
-            // Note that we must do the reset before disconnecting from the ANW.
-            // Otherwise queue/dequeue calls could be made on the disconnected
-            // ANW, which may result in errors.
-            reset();
-
-            Mutex::Autolock lock(mLock);
-            disconnectNativeWindow_l();
-
-            return err;
-        }
-    }
-
-    // Note that we must set the player's new GraphicBufferProducer before
-    // disconnecting the old one.  Otherwise queue/dequeue calls could be made
-    // on the disconnected ANW, which may result in errors.
-    status_t err = p->setVideoSurfaceTexture(nww);
-
-    mLock.lock();
-    disconnectNativeWindow_l();
-
-    if (err == OK) {
-        mConnectedWindow = nww;
-        mLock.unlock();
-    } else if (nww != NULL) {
-        mLock.unlock();
-        status_t err = native_window_api_disconnect(
-                nww->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
-        if (err != OK) {
-            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
-                    strerror(-err), err);
-        }
-    }
-
-    return err;
-}
-
-status_t MediaPlayer2Manager::Client::invoke(const Parcel& request,
-                                            Parcel *reply)
-{
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == NULL) return UNKNOWN_ERROR;
-    return p->invoke(request, reply);
-}
-
-// This call doesn't need to access the native player.
-status_t MediaPlayer2Manager::Client::setMetadataFilter(const Parcel& filter)
-{
-    status_t status;
-    media::Metadata::Filter allow, drop;
-
-    if (unmarshallFilter(filter, &allow, &status) &&
-        unmarshallFilter(filter, &drop, &status)) {
-        Mutex::Autolock lock(mLock);
-
-        mMetadataAllow = allow;
-        mMetadataDrop = drop;
-    }
-    return status;
-}
-
-status_t MediaPlayer2Manager::Client::getMetadata(
-        bool update_only, bool /*apply_filter*/, Parcel *reply)
-{
-    sp<MediaPlayer2Interface> player = getPlayer();
-    if (player == 0) return UNKNOWN_ERROR;
-
-    status_t status;
-    // Placeholder for the return code, updated by the caller.
-    reply->writeInt32(-1);
-
-    media::Metadata::Filter ids;
-
-    // We don't block notifications while we fetch the data. We clear
-    // mMetadataUpdated first so we don't lose notifications happening
-    // during the rest of this call.
-    {
-        Mutex::Autolock lock(mLock);
-        if (update_only) {
-            ids = mMetadataUpdated;
-        }
-        mMetadataUpdated.clear();
-    }
-
-    media::Metadata metadata(reply);
-
-    metadata.appendHeader();
-    status = player->getMetadata(ids, reply);
-
-    if (status != OK) {
-        metadata.resetParcel();
-        ALOGE("getMetadata failed %d", status);
-        return status;
-    }
-
-    // FIXME: ement filtering on the result. Not critical since
-    // filtering takes place on the update notifications already. This
-    // would be when all the metadata are fetch and a filter is set.
-
-    // Everything is fine, update the metadata length.
-    metadata.updateLength();
-    return OK;
-}
-
-status_t MediaPlayer2Manager::Client::setBufferingSettings(
-        const BufferingSettings& buffering)
-{
-    ALOGV("[%d] setBufferingSettings{%s}",
-            mConnId, buffering.toString().string());
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->setBufferingSettings(buffering);
-}
-
-status_t MediaPlayer2Manager::Client::getBufferingSettings(
-        BufferingSettings* buffering /* nonnull */)
-{
-    sp<MediaPlayer2Interface> p = getPlayer();
-    // TODO: create mPlayer on demand.
-    if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->getBufferingSettings(buffering);
-    if (ret == NO_ERROR) {
-        ALOGV("[%d] getBufferingSettings{%s}",
-                mConnId, buffering->toString().string());
-    } else {
-        ALOGE("[%d] getBufferingSettings returned %d", mConnId, ret);
-    }
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::prepareAsync()
-{
-    ALOGV("[%d] prepareAsync", mConnId);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->prepareAsync();
-#if CALLBACK_ANTAGONIZER
-    ALOGD("start Antagonizer");
-    if (ret == NO_ERROR) mAntagonizer->start();
-#endif
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::start()
-{
-    ALOGV("[%d] start", mConnId);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    p->setLooping(mLoop);
-    return p->start();
-}
-
-status_t MediaPlayer2Manager::Client::stop()
-{
-    ALOGV("[%d] stop", mConnId);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->stop();
-}
-
-status_t MediaPlayer2Manager::Client::pause()
-{
-    ALOGV("[%d] pause", mConnId);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->pause();
-}
-
-status_t MediaPlayer2Manager::Client::isPlaying(bool* state)
-{
-    *state = false;
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    *state = p->isPlaying();
-    ALOGV("[%d] isPlaying: %d", mConnId, *state);
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setPlaybackSettings(const AudioPlaybackRate& rate)
-{
-    ALOGV("[%d] setPlaybackSettings(%f, %f, %d, %d)",
-            mConnId, rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->setPlaybackSettings(rate);
-}
-
-status_t MediaPlayer2Manager::Client::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
-{
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->getPlaybackSettings(rate);
-    if (ret == NO_ERROR) {
-        ALOGV("[%d] getPlaybackSettings(%f, %f, %d, %d)",
-                mConnId, rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
-    } else {
-        ALOGV("[%d] getPlaybackSettings returned %d", mConnId, ret);
-    }
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::setSyncSettings(
-        const AVSyncSettings& sync, float videoFpsHint)
-{
-    ALOGV("[%d] setSyncSettings(%u, %u, %f, %f)",
-            mConnId, sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t MediaPlayer2Manager::Client::getSyncSettings(
-        AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
-{
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->getSyncSettings(sync, videoFps);
-    if (ret == NO_ERROR) {
-        ALOGV("[%d] getSyncSettings(%u, %u, %f, %f)",
-                mConnId, sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
-    } else {
-        ALOGV("[%d] getSyncSettings returned %d", mConnId, ret);
-    }
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::getCurrentPosition(int *msec)
-{
-    ALOGV("getCurrentPosition");
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->getCurrentPosition(msec);
-    if (ret == NO_ERROR) {
-        ALOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
-    } else {
-        ALOGE("getCurrentPosition returned %d", ret);
-    }
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::getDuration(int *msec)
-{
-    ALOGV("getDuration");
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    status_t ret = p->getDuration(msec);
-    if (ret == NO_ERROR) {
-        ALOGV("[%d] getDuration = %d", mConnId, *msec);
-    } else {
-        ALOGE("getDuration returned %d", ret);
-    }
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::setNextPlayer(const sp<MediaPlayer2Engine>& player) {
-    ALOGV("setNextPlayer");
-    Mutex::Autolock l(mLock);
-    sp<Client> c = static_cast<Client*>(player.get());
-    if (c != NULL && !gMediaPlayer2Manager.hasClient(c)) {
-      return BAD_VALUE;
-    }
-
-    mNextClient = c;
-
-    if (c != NULL) {
-        if (mAudioOutput != NULL) {
-            mAudioOutput->setNextOutput(c->mAudioOutput);
-        } else {
-            ALOGE("no current audio output");
-        }
-
-        if ((mPlayer != NULL) && (mNextClient->getPlayer() != NULL)) {
-            mPlayer->setNextPlayer(mNextClient->getPlayer());
-        }
-    }
-
-    return OK;
-}
-
-status_t MediaPlayer2Manager::Client::seekTo(int msec, MediaPlayer2SeekMode mode)
-{
-    ALOGV("[%d] seekTo(%d, %d)", mConnId, msec, mode);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->seekTo(msec, mode);
-}
-
-status_t MediaPlayer2Manager::Client::reset()
-{
-    ALOGV("[%d] reset", mConnId);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->reset();
-}
-
-status_t MediaPlayer2Manager::Client::notifyAt(int64_t mediaTimeUs)
-{
-    ALOGV("[%d] notifyAt(%lld)", mConnId, (long long)mediaTimeUs);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->notifyAt(mediaTimeUs);
-}
-
-status_t MediaPlayer2Manager::Client::setAudioStreamType(audio_stream_type_t type)
-{
-    ALOGV("[%d] setAudioStreamType(%d)", mConnId, type);
-    // TODO: for hardware output, call player instead
-    Mutex::Autolock l(mLock);
-    if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setAudioAttributes_l(const Parcel &parcel)
-{
-    if (mAudioAttributes != NULL) { free(mAudioAttributes); }
-    mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-    if (mAudioAttributes == NULL) {
-        return NO_MEMORY;
-    }
-    unmarshallAudioAttributes(parcel, mAudioAttributes);
-
-    ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s",
-            mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags,
-            mAudioAttributes->tags);
-
-    if (mAudioOutput != 0) {
-        mAudioOutput->setAudioAttributes(mAudioAttributes);
-    }
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setLooping(int loop)
-{
-    ALOGV("[%d] setLooping(%d)", mConnId, loop);
-    mLoop = loop;
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p != 0) return p->setLooping(loop);
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setVolume(float leftVolume, float rightVolume)
-{
-    ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
-
-    // for hardware output, call player instead
-    sp<MediaPlayer2Interface> p = getPlayer();
-    {
-      Mutex::Autolock l(mLock);
-      if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
-    }
-
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setAuxEffectSendLevel(float level)
-{
-    ALOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
-    Mutex::Autolock l(mLock);
-    if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::attachAuxEffect(int effectId)
-{
-    ALOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
-    Mutex::Autolock l(mLock);
-    if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setParameter(int key, const Parcel &request) {
-    ALOGV("[%d] setParameter(%d)", mConnId, key);
-    switch (key) {
-    case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
-    {
-        Mutex::Autolock l(mLock);
-        return setAudioAttributes_l(request);
-    }
-    default:
-        sp<MediaPlayer2Interface> p = getPlayer();
-        if (p == 0) { return UNKNOWN_ERROR; }
-        return p->setParameter(key, request);
-    }
-}
-
-status_t MediaPlayer2Manager::Client::getParameter(int key, Parcel *reply) {
-    ALOGV("[%d] getParameter(%d)", mConnId, key);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-    return p->getParameter(key, reply);
-}
-
-void MediaPlayer2Manager::Client::notify(
-        const wp<MediaPlayer2Engine> &listener, int64_t srcId,
-        int msg, int ext1, int ext2, const Parcel *obj)
-{
-    sp<MediaPlayer2Engine> spListener = listener.promote();
-    if (spListener == NULL) {
-        return;
-    }
-    Client* client = static_cast<Client*>(spListener.get());
-
-    sp<MediaPlayer2EngineClient> c;
-    sp<Client> nextClient;
-    status_t errStartNext = NO_ERROR;
-    {
-        Mutex::Autolock l(client->mLock);
-        c = client->mClient;
-        if (msg == MEDIA2_PLAYBACK_COMPLETE && client->mNextClient != NULL) {
-            nextClient = client->mNextClient;
-
-            if (client->mAudioOutput != NULL)
-                client->mAudioOutput->switchToNextOutput();
-
-            errStartNext = nextClient->start();
-        }
-    }
-
-    if (nextClient != NULL) {
-        sp<MediaPlayer2EngineClient> nc;
-        {
-            Mutex::Autolock l(nextClient->mLock);
-            nc = nextClient->mClient;
-        }
-        if (nc != NULL) {
-            if (errStartNext == NO_ERROR) {
-                nc->notify(srcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0, obj);
-            } else {
-                nc->notify(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN , 0, obj);
-                ALOGE("gapless:start playback for next track failed, err(%d)", errStartNext);
-            }
-        }
-    }
-
-    if (MEDIA2_INFO == msg &&
-        MEDIA2_INFO_METADATA_UPDATE == ext1) {
-        const media::Metadata::Type metadata_type = ext2;
-
-        if(client->shouldDropMetadata(metadata_type)) {
-            return;
-        }
-
-        // Update the list of metadata that have changed. getMetadata
-        // also access mMetadataUpdated and clears it.
-        client->addNewMetadataUpdate(metadata_type);
-    }
-
-    if (c != NULL) {
-        ALOGV("[%d] notify (%p, %lld, %d, %d, %d)", client->mConnId, spListener.get(),
-              (long long)srcId, msg, ext1, ext2);
-        c->notify(srcId, msg, ext1, ext2, obj);
-    }
-}
-
-
-bool MediaPlayer2Manager::Client::shouldDropMetadata(media::Metadata::Type code) const
-{
-    Mutex::Autolock lock(mLock);
-
-    if (findMetadata(mMetadataDrop, code)) {
-        return true;
-    }
-
-    if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
-        return false;
-    } else {
-        return true;
-    }
-}
-
-
-void MediaPlayer2Manager::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
-    Mutex::Autolock lock(mLock);
-    if (mMetadataUpdated.indexOf(metadata_type) < 0) {
-        mMetadataUpdated.add(metadata_type);
-    }
-}
-
-// Modular DRM
-status_t MediaPlayer2Manager::Client::prepareDrm(const uint8_t uuid[16],
-        const Vector<uint8_t>& drmSessionId)
-{
-    ALOGV("[%d] prepareDrm", mConnId);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-
-    status_t ret = p->prepareDrm(uuid, drmSessionId);
-    ALOGV("prepareDrm ret: %d", ret);
-
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::releaseDrm()
-{
-    ALOGV("[%d] releaseDrm", mConnId);
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == 0) return UNKNOWN_ERROR;
-
-    status_t ret = p->releaseDrm();
-    ALOGV("releaseDrm ret: %d", ret);
-
-    return ret;
-}
-
-status_t MediaPlayer2Manager::Client::setOutputDevice(audio_port_handle_t deviceId)
-{
-    ALOGV("[%d] setOutputDevice", mConnId);
-    {
-        Mutex::Autolock l(mLock);
-        if (mAudioOutput.get() != nullptr) {
-            return mAudioOutput->setOutputDevice(deviceId);
-        }
-    }
-    return NO_INIT;
-}
-
-status_t MediaPlayer2Manager::Client::getRoutedDeviceId(audio_port_handle_t* deviceId)
-{
-    ALOGV("[%d] getRoutedDeviceId", mConnId);
-    {
-        Mutex::Autolock l(mLock);
-        if (mAudioOutput.get() != nullptr) {
-            return mAudioOutput->getRoutedDeviceId(deviceId);
-        }
-    }
-    return NO_INIT;
-}
-
-status_t MediaPlayer2Manager::Client::enableAudioDeviceCallback(bool enabled)
-{
-    ALOGV("[%d] enableAudioDeviceCallback, %d", mConnId, enabled);
-    {
-        Mutex::Autolock l(mLock);
-        if (mAudioOutput.get() != nullptr) {
-            return mAudioOutput->enableAudioDeviceCallback(enabled);
-        }
-    }
-    return NO_INIT;
-}
-
-#if CALLBACK_ANTAGONIZER
-const int Antagonizer::interval = 10000; // 10 msecs
-
-Antagonizer::Antagonizer(
-        MediaPlayer2Manager::NotifyCallback cb,
-        const wp<MediaPlayer2Engine> &client) :
-    mExit(false), mActive(false), mClient(client), mCb(cb)
-{
-    createThread(callbackThread, this);
-}
-
-void Antagonizer::kill()
-{
-    Mutex::Autolock _l(mLock);
-    mActive = false;
-    mExit = true;
-    mCondition.wait(mLock);
-}
-
-int Antagonizer::callbackThread(void* user)
-{
-    ALOGD("Antagonizer started");
-    Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
-    while (!p->mExit) {
-        if (p->mActive) {
-            ALOGV("send event");
-            p->mCb(p->mClient, 0, 0, 0);
-        }
-        usleep(interval);
-    }
-    Mutex::Autolock _l(p->mLock);
-    p->mCondition.signal();
-    ALOGD("Antagonizer stopped");
-    return 0;
-}
-#endif
-
-#undef LOG_TAG
-#define LOG_TAG "AudioSink"
-MediaPlayer2Manager::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
-        const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
-    : mCallback(NULL),
-      mCallbackCookie(NULL),
-      mCallbackData(NULL),
-      mStreamType(AUDIO_STREAM_MUSIC),
-      mLeftVolume(1.0),
-      mRightVolume(1.0),
-      mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
-      mSampleRateHz(0),
-      mMsecsPerFrame(0),
-      mFrameSize(0),
-      mSessionId(sessionId),
-      mUid(uid),
-      mPid(pid),
-      mSendLevel(0.0),
-      mAuxEffectId(0),
-      mFlags(AUDIO_OUTPUT_FLAG_NONE),
-      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
-      mDeviceCallbackEnabled(false),
-      mDeviceCallback(deviceCallback)
-{
-    ALOGV("AudioOutput(%d)", sessionId);
-    if (attr != NULL) {
-        mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-        if (mAttributes != NULL) {
-            memcpy(mAttributes, attr, sizeof(audio_attributes_t));
-            mStreamType = audio_attributes_to_stream_type(attr);
-        }
-    } else {
-        mAttributes = NULL;
-    }
-
-    setMinBufferCount();
-}
-
-MediaPlayer2Manager::AudioOutput::~AudioOutput()
-{
-    close();
-    free(mAttributes);
-    delete mCallbackData;
-}
-
-//static
-void MediaPlayer2Manager::AudioOutput::setMinBufferCount()
-{
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("ro.kernel.qemu", value, 0)) {
-        mIsOnEmulator = true;
-        mMinBufferCount = 12;  // to prevent systematic buffer underrun for emulator
-    }
-}
-
-// static
-bool MediaPlayer2Manager::AudioOutput::isOnEmulator()
-{
-    setMinBufferCount(); // benign race wrt other threads
-    return mIsOnEmulator;
-}
-
-// static
-int MediaPlayer2Manager::AudioOutput::getMinBufferCount()
-{
-    setMinBufferCount(); // benign race wrt other threads
-    return mMinBufferCount;
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::bufferSize() const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    return mTrack->frameCount() * mFrameSize;
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::frameCount() const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    return mTrack->frameCount();
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::channelCount() const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    return mTrack->channelCount();
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::frameSize() const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    return mFrameSize;
-}
-
-uint32_t MediaPlayer2Manager::AudioOutput::latency () const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return 0;
-    return mTrack->latency();
-}
-
-float MediaPlayer2Manager::AudioOutput::msecsPerFrame() const
-{
-    Mutex::Autolock lock(mLock);
-    return mMsecsPerFrame;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getPosition(uint32_t *position) const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    return mTrack->getPosition(position);
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getTimestamp(AudioTimestamp &ts) const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    return mTrack->getTimestamp(ts);
-}
-
-// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t MediaPlayer2Manager::AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0 || mSampleRateHz == 0) {
-        return 0;
-    }
-
-    uint32_t numFramesPlayed;
-    int64_t numFramesPlayedAtUs;
-    AudioTimestamp ts;
-
-    status_t res = mTrack->getTimestamp(ts);
-    if (res == OK) {                 // case 1: mixing audio tracks and offloaded tracks.
-        numFramesPlayed = ts.mPosition;
-        numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
-        //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
-    } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
-        numFramesPlayed = 0;
-        numFramesPlayedAtUs = nowUs;
-        //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
-        //        numFramesPlayed, (long long)numFramesPlayedAtUs);
-    } else {                         // case 3: transitory at new track or audio fast tracks.
-        res = mTrack->getPosition(&numFramesPlayed);
-        CHECK_EQ(res, (status_t)OK);
-        numFramesPlayedAtUs = nowUs;
-        numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
-        //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
-    }
-
-    // CHECK_EQ(numFramesPlayed & (1 << 31), 0);  // can't be negative until 12.4 hrs, test
-    // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
-    int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
-            + nowUs - numFramesPlayedAtUs;
-    if (durationUs < 0) {
-        // Occurs when numFramesPlayed position is very small and the following:
-        // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
-        //     numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
-        // (2) In case 3, using getPosition and adding mAudioSink->latency() to
-        //     numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
-        //
-        // Both of these are transitory conditions.
-        ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
-        durationUs = 0;
-    }
-    ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
-            (long long)durationUs, (long long)nowUs,
-            numFramesPlayed, (long long)numFramesPlayedAtUs);
-    return durationUs;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    ExtendedTimestamp ets;
-    status_t status = mTrack->getTimestamp(&ets);
-    if (status == OK || status == WOULD_BLOCK) {
-        *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
-    }
-    return status;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setParameters(const String8& keyValuePairs)
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return NO_INIT;
-    return mTrack->setParameters(keyValuePairs);
-}
-
-String8  MediaPlayer2Manager::AudioOutput::getParameters(const String8& keys)
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return String8::empty();
-    return mTrack->getParameters(keys);
-}
-
-void MediaPlayer2Manager::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
-    Mutex::Autolock lock(mLock);
-    if (attributes == NULL) {
-        free(mAttributes);
-        mAttributes = NULL;
-    } else {
-        if (mAttributes == NULL) {
-            mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-        }
-        memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
-        mStreamType = audio_attributes_to_stream_type(attributes);
-    }
-}
-
-void MediaPlayer2Manager::AudioOutput::setAudioStreamType(audio_stream_type_t streamType)
-{
-    Mutex::Autolock lock(mLock);
-    // do not allow direct stream type modification if attributes have been set
-    if (mAttributes == NULL) {
-        mStreamType = streamType;
-    }
-}
-
-void MediaPlayer2Manager::AudioOutput::deleteRecycledTrack_l()
-{
-    ALOGV("deleteRecycledTrack_l");
-    if (mRecycledTrack != 0) {
-
-        if (mCallbackData != NULL) {
-            mCallbackData->setOutput(NULL);
-            mCallbackData->endTrackSwitch();
-        }
-
-        if ((mRecycledTrack->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
-            int32_t msec = 0;
-            if (!mRecycledTrack->stopped()) { // check if active
-                 (void)mRecycledTrack->pendingDuration(&msec);
-            }
-            mRecycledTrack->stop(); // ensure full data drain
-            ALOGD("deleting recycled track, waiting for data drain (%d msec)", msec);
-            if (msec > 0) {
-                static const int32_t WAIT_LIMIT_MS = 3000;
-                if (msec > WAIT_LIMIT_MS) {
-                    msec = WAIT_LIMIT_MS;
-                }
-                usleep(msec * 1000LL);
-            }
-        }
-        // An offloaded track isn't flushed because the STREAM_END is reported
-        // slightly prematurely to allow time for the gapless track switch
-        // but this means that if we decide not to recycle the track there
-        // could be a small amount of residual data still playing. We leave
-        // AudioFlinger to drain the track.
-
-        mRecycledTrack.clear();
-        close_l();
-        delete mCallbackData;
-        mCallbackData = NULL;
-    }
-}
-
-void MediaPlayer2Manager::AudioOutput::close_l()
-{
-    mTrack.clear();
-}
-
-status_t MediaPlayer2Manager::AudioOutput::open(
-        uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
-        audio_format_t format, int bufferCount,
-        AudioCallback cb, void *cookie,
-        audio_output_flags_t flags,
-        const audio_offload_info_t *offloadInfo,
-        bool doNotReconnect,
-        uint32_t suggestedFrameCount)
-{
-    ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
-                format, bufferCount, mSessionId, flags);
-
-    // offloading is only supported in callback mode for now.
-    // offloadInfo must be present if offload flag is set
-    if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
-            ((cb == NULL) || (offloadInfo == NULL))) {
-        return BAD_VALUE;
-    }
-
-    // compute frame count for the AudioTrack internal buffer
-    size_t frameCount;
-    if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
-        frameCount = 0; // AudioTrack will get frame count from AudioFlinger
-    } else {
-        // try to estimate the buffer processing fetch size from AudioFlinger.
-        // framesPerBuffer is approximate and generally correct, except when it's not :-).
-        uint32_t afSampleRate;
-        size_t afFrameCount;
-        if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
-            return NO_INIT;
-        }
-        if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
-            return NO_INIT;
-        }
-        const size_t framesPerBuffer =
-                (unsigned long long)sampleRate * afFrameCount / afSampleRate;
-
-        if (bufferCount == 0) {
-            // use suggestedFrameCount
-            bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
-        }
-        // Check argument bufferCount against the mininum buffer count
-        if (bufferCount != 0 && bufferCount < mMinBufferCount) {
-            ALOGV("bufferCount (%d) increased to %d", bufferCount, mMinBufferCount);
-            bufferCount = mMinBufferCount;
-        }
-        // if frameCount is 0, then AudioTrack will get frame count from AudioFlinger
-        // which will be the minimum size permitted.
-        frameCount = bufferCount * framesPerBuffer;
-    }
-
-    if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
-        channelMask = audio_channel_out_mask_from_count(channelCount);
-        if (0 == channelMask) {
-            ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
-            return NO_INIT;
-        }
-    }
-
-    Mutex::Autolock lock(mLock);
-    mCallback = cb;
-    mCallbackCookie = cookie;
-
-    // Check whether we can recycle the track
-    bool reuse = false;
-    bool bothOffloaded = false;
-
-    if (mRecycledTrack != 0) {
-        // check whether we are switching between two offloaded tracks
-        bothOffloaded = (flags & mRecycledTrack->getFlags()
-                                & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0;
-
-        // check if the existing track can be reused as-is, or if a new track needs to be created.
-        reuse = true;
-
-        if ((mCallbackData == NULL && mCallback != NULL) ||
-                (mCallbackData != NULL && mCallback == NULL)) {
-            // recycled track uses callbacks but the caller wants to use writes, or vice versa
-            ALOGV("can't chain callback and write");
-            reuse = false;
-        } else if ((mRecycledTrack->getSampleRate() != sampleRate) ||
-                (mRecycledTrack->channelCount() != (uint32_t)channelCount) ) {
-            ALOGV("samplerate, channelcount differ: %u/%u Hz, %u/%d ch",
-                  mRecycledTrack->getSampleRate(), sampleRate,
-                  mRecycledTrack->channelCount(), channelCount);
-            reuse = false;
-        } else if (flags != mFlags) {
-            ALOGV("output flags differ %08x/%08x", flags, mFlags);
-            reuse = false;
-        } else if (mRecycledTrack->format() != format) {
-            reuse = false;
-        }
-    } else {
-        ALOGV("no track available to recycle");
-    }
-
-    ALOGV_IF(bothOffloaded, "both tracks offloaded");
-
-    // If we can't recycle and both tracks are offloaded
-    // we must close the previous output before opening a new one
-    if (bothOffloaded && !reuse) {
-        ALOGV("both offloaded and not recycling");
-        deleteRecycledTrack_l();
-    }
-
-    sp<AudioTrack> t;
-    CallbackData *newcbd = NULL;
-
-    // We don't attempt to create a new track if we are recycling an
-    // offloaded track. But, if we are recycling a non-offloaded or we
-    // are switching where one is offloaded and one isn't then we create
-    // the new track in advance so that we can read additional stream info
-
-    if (!(reuse && bothOffloaded)) {
-        ALOGV("creating new AudioTrack");
-
-        if (mCallback != NULL) {
-            newcbd = new CallbackData(this);
-            t = new AudioTrack(
-                    mStreamType,
-                    sampleRate,
-                    format,
-                    channelMask,
-                    frameCount,
-                    flags,
-                    CallbackWrapper,
-                    newcbd,
-                    0,  // notification frames
-                    mSessionId,
-                    AudioTrack::TRANSFER_CALLBACK,
-                    offloadInfo,
-                    mUid,
-                    mPid,
-                    mAttributes,
-                    doNotReconnect,
-                    1.0f,  // default value for maxRequiredSpeed
-                    mSelectedDeviceId);
-        } else {
-            // TODO: Due to buffer memory concerns, we use a max target playback speed
-            // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
-            // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
-            const float targetSpeed =
-                    std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
-            ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
-                    "track target speed:%f clamped from playback speed:%f",
-                    targetSpeed, mPlaybackRate.mSpeed);
-            t = new AudioTrack(
-                    mStreamType,
-                    sampleRate,
-                    format,
-                    channelMask,
-                    frameCount,
-                    flags,
-                    NULL, // callback
-                    NULL, // user data
-                    0, // notification frames
-                    mSessionId,
-                    AudioTrack::TRANSFER_DEFAULT,
-                    NULL, // offload info
-                    mUid,
-                    mPid,
-                    mAttributes,
-                    doNotReconnect,
-                    targetSpeed,
-                    mSelectedDeviceId);
-        }
-
-        if ((t == 0) || (t->initCheck() != NO_ERROR)) {
-            ALOGE("Unable to create audio track");
-            delete newcbd;
-            // t goes out of scope, so reference count drops to zero
-            return NO_INIT;
-        } else {
-            // successful AudioTrack initialization implies a legacy stream type was generated
-            // from the audio attributes
-            mStreamType = t->streamType();
-        }
-    }
-
-    if (reuse) {
-        CHECK(mRecycledTrack != NULL);
-
-        if (!bothOffloaded) {
-            if (mRecycledTrack->frameCount() != t->frameCount()) {
-                ALOGV("framecount differs: %zu/%zu frames",
-                      mRecycledTrack->frameCount(), t->frameCount());
-                reuse = false;
-            }
-        }
-
-        if (reuse) {
-            ALOGV("chaining to next output and recycling track");
-            close_l();
-            mTrack = mRecycledTrack;
-            mRecycledTrack.clear();
-            if (mCallbackData != NULL) {
-                mCallbackData->setOutput(this);
-            }
-            delete newcbd;
-            return updateTrack();
-        }
-    }
-
-    // we're not going to reuse the track, unblock and flush it
-    // this was done earlier if both tracks are offloaded
-    if (!bothOffloaded) {
-        deleteRecycledTrack_l();
-    }
-
-    CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
-
-    mCallbackData = newcbd;
-    ALOGV("setVolume");
-    t->setVolume(mLeftVolume, mRightVolume);
-
-    mSampleRateHz = sampleRate;
-    mFlags = flags;
-    mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
-    mFrameSize = t->frameSize();
-    mTrack = t;
-
-    return updateTrack();
-}
-
-status_t MediaPlayer2Manager::AudioOutput::updateTrack() {
-    if (mTrack == NULL) {
-        return NO_ERROR;
-    }
-
-    status_t res = NO_ERROR;
-    // Note some output devices may give us a direct track even though we don't specify it.
-    // Example: Line application b/17459982.
-    if ((mTrack->getFlags()
-            & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
-        res = mTrack->setPlaybackRate(mPlaybackRate);
-        if (res == NO_ERROR) {
-            mTrack->setAuxEffectSendLevel(mSendLevel);
-            res = mTrack->attachAuxEffect(mAuxEffectId);
-        }
-    }
-    mTrack->setOutputDevice(mSelectedDeviceId);
-    if (mDeviceCallbackEnabled) {
-        mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
-    }
-    ALOGV("updateTrack() DONE status %d", res);
-    return res;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::start()
-{
-    ALOGV("start");
-    Mutex::Autolock lock(mLock);
-    if (mCallbackData != NULL) {
-        mCallbackData->endTrackSwitch();
-    }
-    if (mTrack != 0) {
-        mTrack->setVolume(mLeftVolume, mRightVolume);
-        mTrack->setAuxEffectSendLevel(mSendLevel);
-        status_t status = mTrack->start();
-        return status;
-    }
-    return NO_INIT;
-}
-
-void MediaPlayer2Manager::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) {
-    Mutex::Autolock lock(mLock);
-    mNextOutput = nextOutput;
-}
-
-void MediaPlayer2Manager::AudioOutput::switchToNextOutput() {
-    ALOGV("switchToNextOutput");
-
-    // Try to acquire the callback lock before moving track (without incurring deadlock).
-    const unsigned kMaxSwitchTries = 100;
-    Mutex::Autolock lock(mLock);
-    for (unsigned tries = 0;;) {
-        if (mTrack == 0) {
-            return;
-        }
-        if (mNextOutput != NULL && mNextOutput != this) {
-            if (mCallbackData != NULL) {
-                // two alternative approaches
-#if 1
-                CallbackData *callbackData = mCallbackData;
-                mLock.unlock();
-                // proper acquisition sequence
-                callbackData->lock();
-                mLock.lock();
-                // Caution: it is unlikely that someone deleted our callback or changed our target
-                if (callbackData != mCallbackData || mNextOutput == NULL || mNextOutput == this) {
-                    // fatal if we are starved out.
-                    LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
-                            "switchToNextOutput() cannot obtain correct lock sequence");
-                    callbackData->unlock();
-                    continue;
-                }
-                callbackData->mSwitching = true; // begin track switch
-                callbackData->setOutput(NULL);
-#else
-                // tryBeginTrackSwitch() returns false if the callback has the lock.
-                if (!mCallbackData->tryBeginTrackSwitch()) {
-                    // fatal if we are starved out.
-                    LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
-                            "switchToNextOutput() cannot obtain callback lock");
-                    mLock.unlock();
-                    usleep(5 * 1000 /* usec */); // allow callback to use AudioOutput
-                    mLock.lock();
-                    continue;
-                }
-#endif
-            }
-
-            Mutex::Autolock nextLock(mNextOutput->mLock);
-
-            // If the next output track is not NULL, then it has been
-            // opened already for playback.
-            // This is possible even without the next player being started,
-            // for example, the next player could be prepared and seeked.
-            //
-            // Presuming it isn't advisable to force the track over.
-             if (mNextOutput->mTrack == NULL) {
-                ALOGD("Recycling track for gapless playback");
-                delete mNextOutput->mCallbackData;
-                mNextOutput->mCallbackData = mCallbackData;
-                mNextOutput->mRecycledTrack = mTrack;
-                mNextOutput->mSampleRateHz = mSampleRateHz;
-                mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
-                mNextOutput->mFlags = mFlags;
-                mNextOutput->mFrameSize = mFrameSize;
-                close_l();
-                mCallbackData = NULL;  // destruction handled by mNextOutput
-            } else {
-                ALOGW("Ignoring gapless playback because next player has already started");
-                // remove track in case resource needed for future players.
-                if (mCallbackData != NULL) {
-                    mCallbackData->endTrackSwitch();  // release lock for callbacks before close.
-                }
-                close_l();
-            }
-        }
-        break;
-    }
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::write(const void* buffer, size_t size, bool blocking)
-{
-    Mutex::Autolock lock(mLock);
-    LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
-
-    //ALOGV("write(%p, %u)", buffer, size);
-    if (mTrack != 0) {
-        return mTrack->write(buffer, size, blocking);
-    }
-    return NO_INIT;
-}
-
-void MediaPlayer2Manager::AudioOutput::stop()
-{
-    ALOGV("stop");
-    Mutex::Autolock lock(mLock);
-    if (mTrack != 0) mTrack->stop();
-}
-
-void MediaPlayer2Manager::AudioOutput::flush()
-{
-    ALOGV("flush");
-    Mutex::Autolock lock(mLock);
-    if (mTrack != 0) mTrack->flush();
-}
-
-void MediaPlayer2Manager::AudioOutput::pause()
-{
-    ALOGV("pause");
-    Mutex::Autolock lock(mLock);
-    if (mTrack != 0) mTrack->pause();
-}
-
-void MediaPlayer2Manager::AudioOutput::close()
-{
-    ALOGV("close");
-    sp<AudioTrack> track;
-    {
-        Mutex::Autolock lock(mLock);
-        track = mTrack;
-        close_l(); // clears mTrack
-    }
-    // destruction of the track occurs outside of mutex.
-}
-
-void MediaPlayer2Manager::AudioOutput::setVolume(float left, float right)
-{
-    ALOGV("setVolume(%f, %f)", left, right);
-    Mutex::Autolock lock(mLock);
-    mLeftVolume = left;
-    mRightVolume = right;
-    if (mTrack != 0) {
-        mTrack->setVolume(left, right);
-    }
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate)
-{
-    ALOGV("setPlaybackRate(%f %f %d %d)",
-                rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
-        // remember rate so that we can set it when the track is opened
-        mPlaybackRate = rate;
-        return OK;
-    }
-    status_t res = mTrack->setPlaybackRate(rate);
-    if (res != NO_ERROR) {
-        return res;
-    }
-    // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
-    CHECK_GT(rate.mSpeed, 0.f);
-    mPlaybackRate = rate;
-    if (mSampleRateHz != 0) {
-        mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
-    }
-    return res;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate)
-{
-    ALOGV("setPlaybackRate");
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
-        return NO_INIT;
-    }
-    *rate = mTrack->getPlaybackRate();
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setAuxEffectSendLevel(float level)
-{
-    ALOGV("setAuxEffectSendLevel(%f)", level);
-    Mutex::Autolock lock(mLock);
-    mSendLevel = level;
-    if (mTrack != 0) {
-        return mTrack->setAuxEffectSendLevel(level);
-    }
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::attachAuxEffect(int effectId)
-{
-    ALOGV("attachAuxEffect(%d)", effectId);
-    Mutex::Autolock lock(mLock);
-    mAuxEffectId = effectId;
-    if (mTrack != 0) {
-        return mTrack->attachAuxEffect(effectId);
-    }
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setOutputDevice(audio_port_handle_t deviceId)
-{
-    ALOGV("setOutputDevice(%d)", deviceId);
-    Mutex::Autolock lock(mLock);
-    mSelectedDeviceId = deviceId;
-    if (mTrack != 0) {
-        return mTrack->setOutputDevice(deviceId);
-    }
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId)
-{
-    ALOGV("getRoutedDeviceId");
-    Mutex::Autolock lock(mLock);
-    if (mTrack != 0) {
-        mRoutedDeviceId = mTrack->getRoutedDeviceId();
-    }
-    *deviceId = mRoutedDeviceId;
-    return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::enableAudioDeviceCallback(bool enabled)
-{
-    ALOGV("enableAudioDeviceCallback, %d", enabled);
-    Mutex::Autolock lock(mLock);
-    mDeviceCallbackEnabled = enabled;
-    if (mTrack != 0) {
-        status_t status;
-        if (enabled) {
-            status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
-        } else {
-            status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
-        }
-        return status;
-    }
-    return NO_ERROR;
-}
-
-// static
-void MediaPlayer2Manager::AudioOutput::CallbackWrapper(
-        int event, void *cookie, void *info) {
-    //ALOGV("callbackwrapper");
-    CallbackData *data = (CallbackData*)cookie;
-    // lock to ensure we aren't caught in the middle of a track switch.
-    data->lock();
-    AudioOutput *me = data->getOutput();
-    AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
-    if (me == NULL) {
-        // no output set, likely because the track was scheduled to be reused
-        // by another player, but the format turned out to be incompatible.
-        data->unlock();
-        if (buffer != NULL) {
-            buffer->size = 0;
-        }
-        return;
-    }
-
-    switch(event) {
-    case AudioTrack::EVENT_MORE_DATA: {
-        size_t actualSize = (*me->mCallback)(
-                me, buffer->raw, buffer->size, me->mCallbackCookie,
-                CB_EVENT_FILL_BUFFER);
-
-        // Log when no data is returned from the callback.
-        // (1) We may have no data (especially with network streaming sources).
-        // (2) We may have reached the EOS and the audio track is not stopped yet.
-        // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
-        // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
-        //
-        // This is a benign busy-wait, with the next data request generated 10 ms or more later;
-        // nevertheless for power reasons, we don't want to see too many of these.
-
-        ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned");
-
-        buffer->size = actualSize;
-        } break;
-
-    case AudioTrack::EVENT_STREAM_END:
-        // currently only occurs for offloaded callbacks
-        ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
-        (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
-                me->mCallbackCookie, CB_EVENT_STREAM_END);
-        break;
-
-    case AudioTrack::EVENT_NEW_IAUDIOTRACK :
-        ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
-        (*me->mCallback)(me,  NULL /* buffer */, 0 /* size */,
-                me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
-        break;
-
-    case AudioTrack::EVENT_UNDERRUN:
-        // This occurs when there is no data available, typically
-        // when there is a failure to supply data to the AudioTrack.  It can also
-        // occur in non-offloaded mode when the audio device comes out of standby.
-        //
-        // If an AudioTrack underruns it outputs silence. Since this happens suddenly
-        // it may sound like an audible pop or glitch.
-        //
-        // The underrun event is sent once per track underrun; the condition is reset
-        // when more data is sent to the AudioTrack.
-        ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
-        break;
-
-    default:
-        ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
-    }
-
-    data->unlock();
-}
-
-audio_session_t MediaPlayer2Manager::AudioOutput::getSessionId() const
-{
-    Mutex::Autolock lock(mLock);
-    return mSessionId;
-}
-
-uint32_t MediaPlayer2Manager::AudioOutput::getSampleRate() const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) return 0;
-    return mTrack->getSampleRate();
-}
-
-int64_t MediaPlayer2Manager::AudioOutput::getBufferDurationInUs() const
-{
-    Mutex::Autolock lock(mLock);
-    if (mTrack == 0) {
-        return 0;
-    }
-    int64_t duration;
-    if (mTrack->getBufferDurationInUs(&duration) != OK) {
-        return 0;
-    }
-    return duration;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.h b/media/libmediaplayer2/MediaPlayer2Manager.h
deleted file mode 100644
index 7e6f0de..0000000
--- a/media/libmediaplayer2/MediaPlayer2Manager.h
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
-**
-** Copyright 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 ANDROID_MEDIAPLAYER2MANAGER_H
-#define ANDROID_MEDIAPLAYER2MANAGER_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-#include <media/Metadata.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/MediaPlayer2Engine.h>
-#include <mediaplayer2/MediaPlayer2Interface.h>
-
-#include <system/audio.h>
-
-namespace android {
-
-struct ANativeWindowWrapper;
-struct AudioPlaybackRate;
-class AudioTrack;
-struct AVSyncSettings;
-class DataSource;
-struct MediaHTTPService;
-class MediaPlayer2EngineClient;
-
-#define CALLBACK_ANTAGONIZER 0
-#if CALLBACK_ANTAGONIZER
-class Antagonizer {
-public:
-    Antagonizer(
-            MediaPlayer2Interface::NotifyCallback cb,
-            const wp<MediaPlayer2Engine> &client);
-    void start() { mActive = true; }
-    void stop() { mActive = false; }
-    void kill();
-private:
-    static const int interval;
-    Antagonizer();
-    static int callbackThread(void *cookie);
-    Mutex                            mLock;
-    Condition                        mCondition;
-    bool                             mExit;
-    bool                             mActive;
-    wp<MediaPlayer2Engine>           mClient;
-    MediaPlayer2Interface::NotifyCallback mCb;
-};
-#endif
-
-class MediaPlayer2Manager {
-    class Client;
-
-    class AudioOutput : public MediaPlayer2Interface::AudioSink
-    {
-        class CallbackData;
-
-     public:
-                                AudioOutput(
-                                        audio_session_t sessionId,
-                                        uid_t uid,
-                                        int pid,
-                                        const audio_attributes_t * attr,
-                                        const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
-        virtual                 ~AudioOutput();
-
-        virtual bool            ready() const { return mTrack != 0; }
-        virtual ssize_t         bufferSize() const;
-        virtual ssize_t         frameCount() const;
-        virtual ssize_t         channelCount() const;
-        virtual ssize_t         frameSize() const;
-        virtual uint32_t        latency() const;
-        virtual float           msecsPerFrame() const;
-        virtual status_t        getPosition(uint32_t *position) const;
-        virtual status_t        getTimestamp(AudioTimestamp &ts) const;
-        virtual int64_t         getPlayedOutDurationUs(int64_t nowUs) const;
-        virtual status_t        getFramesWritten(uint32_t *frameswritten) const;
-        virtual audio_session_t getSessionId() const;
-        virtual uint32_t        getSampleRate() const;
-        virtual int64_t         getBufferDurationInUs() const;
-
-        virtual status_t        open(
-                uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
-                audio_format_t format, int bufferCount,
-                AudioCallback cb, void *cookie,
-                audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
-                const audio_offload_info_t *offloadInfo = NULL,
-                bool doNotReconnect = false,
-                uint32_t suggestedFrameCount = 0);
-
-        virtual status_t        start();
-        virtual ssize_t         write(const void* buffer, size_t size, bool blocking = true);
-        virtual void            stop();
-        virtual void            flush();
-        virtual void            pause();
-        virtual void            close();
-                void            setAudioStreamType(audio_stream_type_t streamType);
-        virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; }
-                void            setAudioAttributes(const audio_attributes_t * attributes);
-
-                void            setVolume(float left, float right);
-        virtual status_t        setPlaybackRate(const AudioPlaybackRate& rate);
-        virtual status_t        getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
-
-                status_t        setAuxEffectSendLevel(float level);
-                status_t        attachAuxEffect(int effectId);
-        virtual status_t        dump(int fd, const Vector<String16>& args) const;
-
-        static bool             isOnEmulator();
-        static int              getMinBufferCount();
-                void            setNextOutput(const sp<AudioOutput>& nextOutput);
-                void            switchToNextOutput();
-        virtual bool            needsTrailingPadding() { return mNextOutput == NULL; }
-        virtual status_t        setParameters(const String8& keyValuePairs);
-        virtual String8         getParameters(const String8& keys);
-
-        // AudioRouting
-        virtual status_t        setOutputDevice(audio_port_handle_t deviceId);
-        virtual status_t        getRoutedDeviceId(audio_port_handle_t* deviceId);
-        virtual status_t        enableAudioDeviceCallback(bool enabled);
-
-    private:
-        static void             setMinBufferCount();
-        static void             CallbackWrapper(
-                int event, void *me, void *info);
-               void             deleteRecycledTrack_l();
-               void             close_l();
-           status_t             updateTrack();
-
-        sp<AudioTrack>          mTrack;
-        sp<AudioTrack>          mRecycledTrack;
-        sp<AudioOutput>         mNextOutput;
-        AudioCallback           mCallback;
-        void *                  mCallbackCookie;
-        CallbackData *          mCallbackData;
-        audio_stream_type_t     mStreamType;
-        audio_attributes_t *    mAttributes;
-        float                   mLeftVolume;
-        float                   mRightVolume;
-        AudioPlaybackRate       mPlaybackRate;
-        uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
-        float                   mMsecsPerFrame;
-        size_t                  mFrameSize;
-        audio_session_t         mSessionId;
-        uid_t                   mUid;
-        int                     mPid;
-        float                   mSendLevel;
-        int                     mAuxEffectId;
-        audio_output_flags_t    mFlags;
-        audio_port_handle_t     mSelectedDeviceId;
-        audio_port_handle_t     mRoutedDeviceId;
-        bool                    mDeviceCallbackEnabled;
-        wp<AudioSystem::AudioDeviceCallback>        mDeviceCallback;
-        mutable Mutex           mLock;
-
-        // static variables below not protected by mutex
-        static bool             mIsOnEmulator;
-        static int              mMinBufferCount;  // 12 for emulator; otherwise 4
-
-        // CallbackData is what is passed to the AudioTrack as the "user" data.
-        // We need to be able to target this to a different Output on the fly,
-        // so we can't use the Output itself for this.
-        class CallbackData {
-            friend AudioOutput;
-        public:
-            explicit CallbackData(AudioOutput *cookie) {
-                mData = cookie;
-                mSwitching = false;
-            }
-            AudioOutput *   getOutput() const { return mData; }
-            void            setOutput(AudioOutput* newcookie) { mData = newcookie; }
-            // lock/unlock are used by the callback before accessing the payload of this object
-            void            lock() const { mLock.lock(); }
-            void            unlock() const { mLock.unlock(); }
-
-            // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
-            // to the next sink.
-
-            // tryBeginTrackSwitch() returns true only if it obtains the lock.
-            bool            tryBeginTrackSwitch() {
-                LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
-                if (mLock.tryLock() != OK) {
-                    return false;
-                }
-                mSwitching = true;
-                return true;
-            }
-            void            endTrackSwitch() {
-                if (mSwitching) {
-                    mLock.unlock();
-                }
-                mSwitching = false;
-            }
-        private:
-            AudioOutput *   mData;
-            mutable Mutex   mLock; // a recursive mutex might make this unnecessary.
-            bool            mSwitching;
-            DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
-        };
-
-    }; // AudioOutput
-
-
-public:
-    MediaPlayer2Manager();
-    virtual ~MediaPlayer2Manager();
-
-    static MediaPlayer2Manager& get();
-
-    // MediaPlayer2Manager interface
-    virtual sp<MediaPlayer2Engine> create(const sp<MediaPlayer2EngineClient>& client,
-                                          audio_session_t audioSessionId);
-
-    virtual status_t            dump(int fd, const Vector<String16>& args);
-
-            void                removeClient(const wp<Client>& client);
-            bool                hasClient(wp<Client> client);
-
-private:
-    class Client : public MediaPlayer2Engine {
-        // MediaPlayer2Engine interface
-        virtual void            disconnect();
-        virtual status_t        setVideoSurfaceTexture(
-                const sp<ANativeWindowWrapper>& nww) override;
-        virtual status_t        setBufferingSettings(const BufferingSettings& buffering) override;
-        virtual status_t        getBufferingSettings(
-                                        BufferingSettings* buffering /* nonnull */) override;
-        virtual status_t        prepareAsync();
-        virtual status_t        start();
-        virtual status_t        stop();
-        virtual status_t        pause();
-        virtual status_t        isPlaying(bool* state);
-        virtual status_t        setPlaybackSettings(const AudioPlaybackRate& rate);
-        virtual status_t        getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
-        virtual status_t        setSyncSettings(const AVSyncSettings& rate, float videoFpsHint);
-        virtual status_t        getSyncSettings(AVSyncSettings* rate /* nonnull */,
-                                                float* videoFps /* nonnull */);
-        virtual status_t        seekTo(
-                int msec,
-                MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
-        virtual status_t        getCurrentPosition(int* msec);
-        virtual status_t        getDuration(int* msec);
-        virtual status_t        reset();
-        virtual status_t        notifyAt(int64_t mediaTimeUs);
-        virtual status_t        setAudioStreamType(audio_stream_type_t type);
-        virtual status_t        setLooping(int loop);
-        virtual status_t        setVolume(float leftVolume, float rightVolume);
-        virtual status_t        invoke(const Parcel& request, Parcel *reply);
-        virtual status_t        setMetadataFilter(const Parcel& filter);
-        virtual status_t        getMetadata(bool update_only,
-                                            bool apply_filter,
-                                            Parcel *reply);
-        virtual status_t        setAuxEffectSendLevel(float level);
-        virtual status_t        attachAuxEffect(int effectId);
-        virtual status_t        setParameter(int key, const Parcel &request);
-        virtual status_t        getParameter(int key, Parcel *reply);
-        virtual status_t        setNextPlayer(const sp<MediaPlayer2Engine>& player);
-
-        virtual status_t        setDataSource(const sp<DataSourceDesc> &dsd);
-
-        static  void            notify(const wp<MediaPlayer2Engine> &listener, int64_t srcId,
-                                       int msg, int ext1, int ext2, const Parcel *obj);
-
-                pid_t           pid() const { return mPid; }
-        virtual status_t        dump(int fd, const Vector<String16>& args);
-
-                audio_session_t getAudioSessionId() { return mAudioSessionId; }
-        // Modular DRM
-        virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
-        virtual status_t releaseDrm();
-        // AudioRouting
-        virtual status_t setOutputDevice(audio_port_handle_t deviceId);
-        virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
-        virtual status_t enableAudioDeviceCallback(bool enabled);
-
-    private:
-        class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
-        {
-        public:
-            AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener) {
-                mListener = listener;
-            }
-            ~AudioDeviceUpdatedNotifier() {}
-
-            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
-                                             audio_port_handle_t deviceId);
-
-        private:
-            wp<MediaPlayer2Interface> mListener;
-        };
-
-        friend class MediaPlayer2Manager;
-                                Client(pid_t pid,
-                                       int32_t connId,
-                                       const sp<MediaPlayer2EngineClient>& client,
-                                       audio_session_t audioSessionId,
-                                       uid_t uid);
-                                Client();
-        virtual                 ~Client();
-        bool init();
-
-                void            deletePlayer();
-
-        sp<MediaPlayer2Interface> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
-
-
-
-        // @param type Of the metadata to be tested.
-        // @return true if the metadata should be dropped according to
-        //              the filters.
-        bool shouldDropMetadata(media::Metadata::Type type) const;
-
-        // Add a new element to the set of metadata updated. Noop if
-        // the element exists already.
-        // @param type Of the metadata to be recorded.
-        void addNewMetadataUpdate(media::Metadata::Type type);
-
-        // Disconnect from the currently connected ANativeWindow.
-        void disconnectNativeWindow_l();
-
-        status_t setAudioAttributes_l(const Parcel &request);
-
-        mutable     Mutex                        mLock;
-                    sp<MediaPlayer2Interface>    mPlayer;
-                    sp<MediaPlayer2EngineClient> mClient;
-                    sp<AudioOutput>              mAudioOutput;
-                    pid_t                        mPid;
-                    status_t                     mStatus;
-                    bool                         mLoop;
-                    int32_t                      mConnId;
-                    audio_session_t              mAudioSessionId;
-                    audio_attributes_t *         mAudioAttributes;
-                    uid_t                        mUid;
-                    sp<ANativeWindowWrapper>     mConnectedWindow;
-                    sp<Client>                   mNextClient;
-
-        // Metadata filters.
-        media::Metadata::Filter mMetadataAllow;  // protected by mLock
-        media::Metadata::Filter mMetadataDrop;  // protected by mLock
-
-        // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
-        // notification we try to update mMetadataUpdated which is a
-        // set: no duplicate.
-        // getMetadata clears this set.
-        media::Metadata::Filter mMetadataUpdated;  // protected by mLock
-
-        sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
-#if CALLBACK_ANTAGONIZER
-                    Antagonizer*                mAntagonizer;
-#endif
-    }; // Client
-
-// ----------------------------------------------------------------------------
-
-    pid_t mPid;
-    uid_t mUid;
-
-    mutable Mutex mLock;
-    SortedVector< wp<Client> > mClients;
-    int32_t mNextConnId;
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2MANAGER_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
index 10fa5e8..301825b 100644
--- a/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
+++ b/media/libmediaplayer2/include/mediaplayer2/JAudioTrack.h
@@ -19,6 +19,7 @@
 
 #include <jni.h>
 #include <media/AudioResamplerPublic.h>
+#include <media/AudioSystem.h>
 #include <media/VolumeShaper.h>
 #include <system/audio.h>
 #include <utils/Errors.h>
@@ -31,6 +32,42 @@
 class JAudioTrack {
 public:
 
+    /* Events used by AudioTrack callback function (callback_t).
+     * Keep in sync with frameworks/base/media/java/android/media/AudioTrack.java NATIVE_EVENT_*.
+     */
+    enum event_type {
+        EVENT_MORE_DATA = 0,        // Request to write more data to buffer.
+        EVENT_NEW_IAUDIOTRACK = 6,  // IAudioTrack was re-created, either due to re-routing and
+                                    // voluntary invalidation by mediaserver, or mediaserver crash.
+        EVENT_STREAM_END = 7,       // Sent after all the buffers queued in AF and HW are played
+                                    // back (after stop is called) for an offloaded track.
+    };
+
+    class Buffer
+    {
+    public:
+        size_t      mSize;        // input/output in bytes.
+        void*       mData;        // pointer to the audio data.
+    };
+
+    /* As a convenience, if a callback is supplied, a handler thread
+     * is automatically created with the appropriate priority. This thread
+     * invokes the callback when a new buffer becomes available or various conditions occur.
+     *
+     * Parameters:
+     *
+     * event:   type of event notified (see enum AudioTrack::event_type).
+     * user:    Pointer to context for use by the callback receiver.
+     * info:    Pointer to optional parameter according to event type:
+     *          - EVENT_MORE_DATA: pointer to JAudioTrack::Buffer struct. The callback must not
+     *            write more bytes than indicated by 'size' field and update 'size' if fewer bytes
+     *            are written.
+     *          - EVENT_NEW_IAUDIOTRACK: unused.
+     *          - EVENT_STREAM_END: unused.
+     */
+
+    typedef void (*callback_t)(int event, void* user, void *info);
+
     /* Creates an JAudioTrack object for non-offload mode.
      * Once created, the track needs to be started before it can be used.
      * Unspecified values are set to appropriate default values.
@@ -49,6 +86,9 @@
      *                     output sink.
      *                     (TODO: How can we check whether a format is supported?)
      * channelMask:        Channel mask, such that audio_is_output_channel(channelMask) is true.
+     * cbf:                Callback function. If not null, this function is called periodically
+     *                     to provide new data and inform of marker, position updates, etc.
+     * user:               Context for use by the callback receiver.
      * frameCount:         Minimum size of track PCM buffer in frames. This defines the
      *                     application's contribution to the latency of the track.
      *                     The actual size selected by the JAudioTrack could be larger if the
@@ -68,35 +108,20 @@
                 uint32_t sampleRate,
                 audio_format_t format,
                 audio_channel_mask_t channelMask,
+                callback_t cbf,
+                void* user,
                 size_t frameCount = 0,
                 audio_session_t sessionId  = AUDIO_SESSION_ALLOCATE,
                 const audio_attributes_t* pAttributes = NULL,
                 float maxRequiredSpeed = 1.0f);
 
     /*
-       Temporarily removed constructor arguments:
-
-       // Q. Values are in audio-base.h, but where can we find explanation for them?
-       audio_output_flags_t flags,
-
        // Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
        audio_port_handle_t selectedDeviceId,
 
-       // Should be deleted, since we don't use Binder anymore.
-       bool doNotReconnect,
-
-       // Do we need UID and PID?
-       uid_t uid,
-       pid_t pid,
-
-       // TODO: Uses these values when Java AudioTrack supports the offload mode.
-       callback_t cbf,
-       void* user,
+       // TODO: No place to use these values.
        int32_t notificationFrames,
        const audio_offload_info_t *offloadInfo,
-
-       // Fixed to false, but what is this?
-       threadCanCallJava
     */
 
     virtual ~JAudioTrack();
@@ -138,6 +163,46 @@
      */
     bool getTimestamp(AudioTimestamp& timestamp);
 
+    // TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
+    /* Return the extended timestamp, with additional timebase info and improved drain behavior.
+     *
+     * This is similar to the AudioTrack.java API:
+     * getTimestamp(@NonNull AudioTimestamp timestamp, @AudioTimestamp.Timebase int timebase)
+     *
+     * Some differences between this method and the getTimestamp(AudioTimestamp& timestamp) method
+     *
+     *   1. stop() by itself does not reset the frame position.
+     *      A following start() resets the frame position to 0.
+     *   2. flush() by itself does not reset the frame position.
+     *      The frame position advances by the number of frames flushed,
+     *      when the first frame after flush reaches the audio sink.
+     *   3. BOOTTIME clock offsets are provided to help synchronize with
+     *      non-audio streams, e.g. sensor data.
+     *   4. Position is returned with 64 bits of resolution.
+     *
+     * Parameters:
+     *  timestamp: A pointer to the caller allocated ExtendedTimestamp.
+     *
+     * Returns NO_ERROR    on success; timestamp is filled with valid data.
+     *         BAD_VALUE   if timestamp is NULL.
+     *         WOULD_BLOCK if called immediately after start() when the number
+     *                     of frames consumed is less than the
+     *                     overall hardware latency to physical output. In WOULD_BLOCK cases,
+     *                     one might poll again, or use getPosition(), or use 0 position and
+     *                     current time for the timestamp.
+     *                     If WOULD_BLOCK is returned, the timestamp is still
+     *                     modified with the LOCATION_CLIENT portion filled.
+     *         DEAD_OBJECT if AudioFlinger dies or the output device changes and
+     *                     the track cannot be automatically restored.
+     *                     The application needs to recreate the AudioTrack
+     *                     because the audio device changed or AudioFlinger died.
+     *                     This typically occurs for direct or offloaded tracks
+     *                     or if mDoNotReconnect is true.
+     *         INVALID_OPERATION  if called on a offloaded or direct track.
+     *                     Use getTimestamp(AudioTimestamp& timestamp) instead.
+     */
+    status_t getTimestamp(ExtendedTimestamp *timestamp);
+
     /* Set source playback rate for timestretch
      * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster
      * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch
@@ -270,7 +335,65 @@
      */
     audio_port_handle_t getRoutedDeviceId();
 
+    /* Returns the ID of the audio session this AudioTrack belongs to. */
+    audio_session_t getAudioSessionId();
+
+    /* Selects the audio device to use for output of this AudioTrack. A value of
+     * AUDIO_PORT_HANDLE_NONE indicates default routing.
+     *
+     * Parameters:
+     *  The device ID of the selected device (as returned by the AudioDevicesManager API).
+     *
+     * Returned value:
+     *  - NO_ERROR: successful operation
+     *  - BAD_VALUE: failed to find the valid output device with given device Id.
+     */
+    status_t setOutputDevice(audio_port_handle_t deviceId);
+
+    // TODO: Add AUDIO_OUTPUT_FLAG_DIRECT when it is possible to check.
+    // TODO: Add AUDIO_FLAG_HW_AV_SYNC when it is possible to check.
+    /* Returns the flags */
+    audio_output_flags_t getFlags() const { return mFlags; }
+
+    /* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
+     * AudioTrack.
+     *
+     * Returns NO_ERROR if successful.
+     *         INVALID_OPERATION if the AudioTrack does not contain pure PCM data.
+     *         BAD_VALUE if msec is nullptr.
+     */
+    status_t pendingDuration(int32_t *msec);
+
+    /* Adds an AudioDeviceCallback. The caller will be notified when the audio device to which this
+     * AudioTrack is routed is updated.
+     * Replaces any previously installed callback.
+     *
+     * Parameters:
+     *
+     * callback: The callback interface
+     *
+     * Returns NO_ERROR if successful.
+     *         INVALID_OPERATION if the same callback is already installed.
+     *         NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+     *         BAD_VALUE if the callback is NULL
+     */
+    status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+
+    /* Removes an AudioDeviceCallback.
+     *
+     * Parameters:
+     *
+     * callback: The callback interface
+     *
+     * Returns NO_ERROR if successful.
+     *         INVALID_OPERATION if the callback is not installed
+     *         BAD_VALUE if the callback is NULL
+     */
+    status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+
 private:
+    audio_output_flags_t mFlags;
+
     jclass mAudioTrackCls;
     jobject mAudioTrackObj;
 
@@ -282,6 +405,12 @@
     jobject createVolumeShaperOperationObj(
             const sp<media::VolumeShaper::Operation>& operation);
 
+    /* Creates a Java StreamEventCallback object */
+    jobject createStreamEventCallback(callback_t cbf, void* user);
+
+    /* Creates a Java Executor object for running a callback */
+    jobject createCallbackExecutor();
+
     status_t javaToNativeStatus(int javaStatus);
 };
 
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
new file mode 100644
index 0000000..5d5b8e4
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -0,0 +1,191 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
+#define ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
+
+#include <mediaplayer2/MediaPlayer2Interface.h>
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class AudioTrack;
+
+class MediaPlayer2AudioOutput : public MediaPlayer2Interface::AudioSink
+{
+    class CallbackData;
+
+public:
+    MediaPlayer2AudioOutput(audio_session_t sessionId,
+                            uid_t uid,
+                            int pid,
+                            const audio_attributes_t * attr,
+                            const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
+    virtual ~MediaPlayer2AudioOutput();
+
+    virtual bool ready() const {
+        return mTrack != 0;
+    }
+    virtual ssize_t bufferSize() const;
+    virtual ssize_t frameCount() const;
+    virtual ssize_t channelCount() const;
+    virtual ssize_t frameSize() const;
+    virtual uint32_t latency() const;
+    virtual float msecsPerFrame() const;
+    virtual status_t getPosition(uint32_t *position) const;
+    virtual status_t getTimestamp(AudioTimestamp &ts) const;
+    virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
+    virtual status_t getFramesWritten(uint32_t *frameswritten) const;
+    virtual audio_session_t getSessionId() const;
+    virtual uint32_t getSampleRate() const;
+    virtual int64_t getBufferDurationInUs() const;
+
+    virtual status_t open(
+            uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
+            audio_format_t format, int bufferCount,
+            AudioCallback cb, void *cookie,
+            audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+            const audio_offload_info_t *offloadInfo = NULL,
+            bool doNotReconnect = false,
+            uint32_t suggestedFrameCount = 0);
+
+    virtual status_t start();
+    virtual ssize_t write(const void* buffer, size_t size, bool blocking = true);
+    virtual void stop();
+    virtual void flush();
+    virtual void pause();
+    virtual void close();
+    void setAudioStreamType(audio_stream_type_t streamType);
+    virtual audio_stream_type_t getAudioStreamType() const {
+        return mStreamType;
+    }
+    void setAudioAttributes(const audio_attributes_t * attributes);
+
+    void setVolume(float left, float right);
+    virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
+    virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
+
+    status_t setAuxEffectSendLevel(float level);
+    status_t attachAuxEffect(int effectId);
+    virtual status_t dump(int fd, const Vector<String16>& args) const;
+
+    static bool isOnEmulator();
+    static int getMinBufferCount();
+    virtual bool needsTrailingPadding() {
+        return true;
+        // TODO: return correct value.
+        //return mNextOutput == NULL;
+    }
+    virtual status_t setParameters(const String8& keyValuePairs);
+    virtual String8 getParameters(const String8& keys);
+
+    // AudioRouting
+    virtual status_t setOutputDevice(audio_port_handle_t deviceId);
+    virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+    virtual status_t enableAudioDeviceCallback(bool enabled);
+
+private:
+    static void setMinBufferCount();
+    static void CallbackWrapper(int event, void *me, void *info);
+    void deleteRecycledTrack_l();
+    void close_l();
+    status_t updateTrack_l();
+
+    sp<AudioTrack>          mTrack;
+    AudioCallback           mCallback;
+    void *                  mCallbackCookie;
+    CallbackData *          mCallbackData;
+    audio_stream_type_t     mStreamType;
+    audio_attributes_t *    mAttributes;
+    float                   mLeftVolume;
+    float                   mRightVolume;
+    AudioPlaybackRate       mPlaybackRate;
+    uint32_t                mSampleRateHz; // sample rate of the content, as set in open()
+    float                   mMsecsPerFrame;
+    size_t                  mFrameSize;
+    audio_session_t         mSessionId;
+    uid_t                   mUid;
+    int                     mPid;
+    float                   mSendLevel;
+    int                     mAuxEffectId;
+    audio_output_flags_t    mFlags;
+    audio_port_handle_t     mSelectedDeviceId;
+    audio_port_handle_t     mRoutedDeviceId;
+    bool                    mDeviceCallbackEnabled;
+    wp<AudioSystem::AudioDeviceCallback>        mDeviceCallback;
+    mutable Mutex           mLock;
+
+    // static variables below not protected by mutex
+    static bool             mIsOnEmulator;
+    static int              mMinBufferCount;  // 12 for emulator; otherwise 4
+
+    // CallbackData is what is passed to the AudioTrack as the "user" data.
+    // We need to be able to target this to a different Output on the fly,
+    // so we can't use the Output itself for this.
+    class CallbackData {
+        friend MediaPlayer2AudioOutput;
+    public:
+        explicit CallbackData(MediaPlayer2AudioOutput *cookie) {
+            mData = cookie;
+            mSwitching = false;
+        }
+        MediaPlayer2AudioOutput *getOutput() const {
+            return mData;
+        }
+        void setOutput(MediaPlayer2AudioOutput* newcookie) {
+            mData = newcookie;
+        }
+        // lock/unlock are used by the callback before accessing the payload of this object
+        void lock() const {
+            mLock.lock();
+        }
+        void unlock() const {
+            mLock.unlock();
+        }
+
+        // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
+        // to the next sink.
+
+        // tryBeginTrackSwitch() returns true only if it obtains the lock.
+        bool tryBeginTrackSwitch() {
+            LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
+            if (mLock.tryLock() != OK) {
+                return false;
+            }
+            mSwitching = true;
+            return true;
+        }
+        void endTrackSwitch() {
+            if (mSwitching) {
+                mLock.unlock();
+            }
+            mSwitching = false;
+        }
+
+    private:
+        MediaPlayer2AudioOutput *mData;
+        mutable Mutex mLock; // a recursive mutex might make this unnecessary.
+        bool mSwitching;
+        DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
+    };
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
deleted file mode 100644
index 2d1a24b..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 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 ANDROID_MEDIAPLAYER2ENGINE_H
-#define ANDROID_MEDIAPLAYER2ENGINE_H
-
-#include <utils/RefBase.h>
-#include <binder/Parcel.h>
-#include <utils/KeyedVector.h>
-#include <system/audio.h>
-
-#include <media/MediaSource.h>
-
-// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
-// global, and not in android::
-struct sockaddr_in;
-
-namespace android {
-
-struct ANativeWindowWrapper;
-struct AVSyncSettings;
-struct AudioPlaybackRate;
-struct BufferingSettings;
-class DataSource;
-struct DataSourceDesc;
-struct IStreamSource;
-struct MediaHTTPService;
-class Parcel;
-
-typedef MediaSource::ReadOptions::SeekMode MediaPlayer2SeekMode;
-
-class MediaPlayer2Engine: public RefBase
-{
-public:
-    virtual void            disconnect() = 0;
-
-    virtual status_t        setDataSource(const sp<DataSourceDesc>& source) = 0;
-    virtual status_t        setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
-    virtual status_t        getBufferingSettings(
-                                    BufferingSettings* buffering /* nonnull */) = 0;
-    virtual status_t        setBufferingSettings(const BufferingSettings& buffering) = 0;
-    virtual status_t        prepareAsync() = 0;
-    virtual status_t        start() = 0;
-    virtual status_t        stop() = 0;
-    virtual status_t        pause() = 0;
-    virtual status_t        isPlaying(bool* state) = 0;
-    virtual status_t        setPlaybackSettings(const AudioPlaybackRate& rate) = 0;
-    virtual status_t        getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) = 0;
-    virtual status_t        setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) = 0;
-    virtual status_t        getSyncSettings(AVSyncSettings* sync /* nonnull */,
-                                            float* videoFps /* nonnull */) = 0;
-    virtual status_t        seekTo(
-            int msec,
-            MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
-    virtual status_t        getCurrentPosition(int* msec) = 0;
-    virtual status_t        getDuration(int* msec) = 0;
-    virtual status_t        notifyAt(int64_t mediaTimeUs) = 0;
-    virtual status_t        reset() = 0;
-    virtual status_t        setAudioStreamType(audio_stream_type_t type) = 0;
-    virtual status_t        setLooping(int loop) = 0;
-    virtual status_t        setVolume(float leftVolume, float rightVolume) = 0;
-    virtual status_t        setAuxEffectSendLevel(float level) = 0;
-    virtual status_t        attachAuxEffect(int effectId) = 0;
-    virtual status_t        setParameter(int key, const Parcel& request) = 0;
-    virtual status_t        getParameter(int key, Parcel* reply) = 0;
-    virtual status_t        setNextPlayer(const sp<MediaPlayer2Engine>& next) = 0;
-
-    // Modular DRM
-    virtual status_t        prepareDrm(const uint8_t uuid[16],
-                                    const Vector<uint8_t>& drmSessionId) = 0;
-    virtual status_t        releaseDrm() = 0;
-
-    // Invoke a generic method on the player by using opaque parcels
-    // for the request and reply.
-    // @param request Parcel that must start with the media player
-    // interface token.
-    // @param[out] reply Parcel to hold the reply data. Cannot be null.
-    // @return OK if the invocation was made successfully.
-    virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;
-
-    // Set a new metadata filter.
-    // @param filter A set of allow and drop rules serialized in a Parcel.
-    // @return OK if the invocation was made successfully.
-    virtual status_t        setMetadataFilter(const Parcel& filter) = 0;
-
-    // Retrieve a set of metadata.
-    // @param update_only Include only the metadata that have changed
-    //                    since the last invocation of getMetadata.
-    //                    The set is built using the unfiltered
-    //                    notifications the native player sent to the
-    //                    MediaPlayer2Manager during that period of
-    //                    time. If false, all the metadatas are considered.
-    // @param apply_filter If true, once the metadata set has been built based
-    //                     on the value update_only, the current filter is
-    //                     applied.
-    // @param[out] metadata On exit contains a set (possibly empty) of metadata.
-    //                      Valid only if the call returned OK.
-    // @return OK if the invocation was made successfully.
-    virtual status_t        getMetadata(bool update_only,
-                                        bool apply_filter,
-                                        Parcel *metadata) = 0;
-
-    // AudioRouting
-    virtual status_t        setOutputDevice(audio_port_handle_t deviceId) = 0;
-    virtual status_t        getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
-    virtual status_t        enableAudioDeviceCallback(bool enabled) = 0;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2ENGINE_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
deleted file mode 100644
index 0b066aa..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 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 ANDROID_MEDIAPLAYER2ENGINECLIENT_H
-#define ANDROID_MEDIAPLAYER2ENGINECLIENT_H
-
-#include <utils/RefBase.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class MediaPlayer2EngineClient: public RefBase
-{
-public:
-    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2ENGINECLIENT_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index b1cdf96..02bf891 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -21,18 +21,17 @@
 
 #include <sys/types.h>
 #include <utils/Errors.h>
-#include <utils/KeyedVector.h>
 #include <utils/String8.h>
 #include <utils/RefBase.h>
 
+#include <media/AVSyncSettings.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTimestamp.h>
-#include <media/AVSyncSettings.h>
 #include <media/BufferingSettings.h>
 #include <media/Metadata.h>
 #include <media/stagefright/foundation/AHandler.h>
-#include <mediaplayer2/mediaplayer2.h>
+#include <mediaplayer2/MediaPlayer2Types.h>
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
 // global, and not in android::
@@ -40,14 +39,10 @@
 
 namespace android {
 
-class DataSource;
 struct DataSourceDesc;
-struct MediaHTTPService;
 class Parcel;
 struct ANativeWindowWrapper;
 
-template<typename T> class SortedVector;
-
 #define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
 #define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
 #define DEFAULT_AUDIOSINK_SAMPLERATE 44100
@@ -58,14 +53,14 @@
 // duration below which we do not allow deep audio buffering
 #define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
 
-// abstract base class - use MediaPlayer2Interface
-class MediaPlayer2Interface : public AHandler
+class MediaPlayer2InterfaceListener: public RefBase
 {
 public:
-    // callback mechanism for passing messages to MediaPlayer2 object
-    typedef void (*NotifyCallback)(const wp<MediaPlayer2Engine> &listener,
-            int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj);
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
+};
 
+class MediaPlayer2Interface : public AHandler {
+public:
     // AudioSink: abstraction layer for audio output
     class AudioSink : public RefBase {
     public:
@@ -79,29 +74,28 @@
 
         // Callback returns the number of bytes actually written to the buffer.
         typedef size_t (*AudioCallback)(
-                AudioSink *audioSink, void *buffer, size_t size, void *cookie,
-                        cb_event_t event);
+                AudioSink *audioSink, void *buffer, size_t size, void *cookie, cb_event_t event);
 
-        virtual             ~AudioSink() {}
-        virtual bool        ready() const = 0; // audio output is open and ready
-        virtual ssize_t     bufferSize() const = 0;
-        virtual ssize_t     frameCount() const = 0;
-        virtual ssize_t     channelCount() const = 0;
-        virtual ssize_t     frameSize() const = 0;
-        virtual uint32_t    latency() const = 0;
-        virtual float       msecsPerFrame() const = 0;
-        virtual status_t    getPosition(uint32_t *position) const = 0;
-        virtual status_t    getTimestamp(AudioTimestamp &ts) const = 0;
-        virtual int64_t     getPlayedOutDurationUs(int64_t nowUs) const = 0;
-        virtual status_t    getFramesWritten(uint32_t *frameswritten) const = 0;
+        virtual ~AudioSink() {}
+        virtual bool ready() const = 0; // audio output is open and ready
+        virtual ssize_t bufferSize() const = 0;
+        virtual ssize_t frameCount() const = 0;
+        virtual ssize_t channelCount() const = 0;
+        virtual ssize_t frameSize() const = 0;
+        virtual uint32_t latency() const = 0;
+        virtual float msecsPerFrame() const = 0;
+        virtual status_t getPosition(uint32_t *position) const = 0;
+        virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
+        virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
+        virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
         virtual audio_session_t getSessionId() const = 0;
         virtual audio_stream_type_t getAudioStreamType() const = 0;
-        virtual uint32_t    getSampleRate() const = 0;
-        virtual int64_t     getBufferDurationInUs() const = 0;
+        virtual uint32_t getSampleRate() const = 0;
+        virtual int64_t getBufferDurationInUs() const = 0;
 
         // If no callback is specified, use the "write" API below to submit
         // audio data.
-        virtual status_t    open(
+        virtual status_t open(
                 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
                 audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
                 int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
@@ -112,7 +106,7 @@
                 bool doNotReconnect = false,
                 uint32_t suggestedFrameCount = 0) = 0;
 
-        virtual status_t    start() = 0;
+        virtual status_t start() = 0;
 
         /* Input parameter |size| is in byte units stored in |buffer|.
          * Data is copied over and actual number of bytes written (>= 0)
@@ -124,19 +118,25 @@
          * buffer, unless an error occurs or the copy operation is
          * prematurely stopped.
          */
-        virtual ssize_t     write(const void* buffer, size_t size, bool blocking = true) = 0;
+        virtual ssize_t write(const void* buffer, size_t size, bool blocking = true) = 0;
 
-        virtual void        stop() = 0;
-        virtual void        flush() = 0;
-        virtual void        pause() = 0;
-        virtual void        close() = 0;
+        virtual void stop() = 0;
+        virtual void flush() = 0;
+        virtual void pause() = 0;
+        virtual void close() = 0;
 
-        virtual status_t    setPlaybackRate(const AudioPlaybackRate& rate) = 0;
-        virtual status_t    getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
-        virtual bool        needsTrailingPadding() { return true; }
+        virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0;
+        virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
+        virtual bool needsTrailingPadding() {
+            return true;
+        }
 
-        virtual status_t    setParameters(const String8& /* keyValuePairs */) { return NO_ERROR; }
-        virtual String8     getParameters(const String8& /* keys */) { return String8::empty(); }
+        virtual status_t setParameters(const String8& /* keyValuePairs */) {
+            return NO_ERROR;
+        }
+        virtual String8 getParameters(const String8& /* keys */) {
+            return String8::empty();
+        }
 
         // AudioRouting
         virtual status_t    setOutputDevice(audio_port_handle_t deviceId);
@@ -144,46 +144,48 @@
         virtual status_t    enableAudioDeviceCallback(bool enabled);
     };
 
-                        MediaPlayer2Interface() : mClient(0), mNotify(0) { }
-    virtual             ~MediaPlayer2Interface() { }
-    virtual status_t    initCheck() = 0;
+    MediaPlayer2Interface() : mListener(NULL) { }
+    virtual ~MediaPlayer2Interface() { }
+    virtual status_t initCheck() = 0;
 
-    virtual void        setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
-
-    virtual status_t    setDataSource(const sp<DataSourceDesc>& /* dsd */) {
-        return INVALID_OPERATION;
+    virtual void setAudioSink(const sp<AudioSink>& audioSink) {
+        mAudioSink = audioSink;
     }
 
-    // pass the buffered native window to the media player service
-    virtual status_t    setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
+    virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) = 0;
 
-    virtual status_t    getBufferingSettings(
-                                BufferingSettings* buffering /* nonnull */) {
+    virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) = 0;
+
+    virtual status_t playNextDataSource(int64_t srcId) = 0;
+
+    // pass the buffered native window to the media player service
+    virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
+
+    virtual status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
         *buffering = BufferingSettings();
         return OK;
     }
-    virtual status_t    setBufferingSettings(const BufferingSettings& /* buffering */) {
+    virtual status_t setBufferingSettings(const BufferingSettings& /* buffering */) {
         return OK;
     }
 
-    virtual status_t    prepare() = 0;
-    virtual status_t    prepareAsync() = 0;
-    virtual status_t    start() = 0;
-    virtual status_t    stop() = 0;
-    virtual status_t    pause() = 0;
-    virtual bool        isPlaying() = 0;
-    virtual status_t    setPlaybackSettings(const AudioPlaybackRate& rate) {
+    virtual status_t prepareAsync() = 0;
+    virtual status_t start() = 0;
+    virtual status_t stop() = 0;
+    virtual status_t pause() = 0;
+    virtual bool isPlaying() = 0;
+    virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
         // by default, players only support setting rate to the default
         if (!isAudioPlaybackRateEqual(rate, AUDIO_PLAYBACK_RATE_DEFAULT)) {
             return BAD_VALUE;
         }
         return OK;
     }
-    virtual status_t    getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
+    virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
         *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
         return OK;
     }
-    virtual status_t    setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
+    virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
         // By default, players only support setting sync source to default; all other sync
         // settings are ignored. There is no requirement for getters to return set values.
         if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
@@ -191,27 +193,23 @@
         }
         return OK;
     }
-    virtual status_t    getSyncSettings(
-                                AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
+    virtual status_t getSyncSettings(
+            AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
         *sync = AVSyncSettings();
         *videoFps = -1.f;
         return OK;
     }
-    virtual status_t    seekTo(
-            int msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
-    virtual status_t    getCurrentPosition(int *msec) = 0;
-    virtual status_t    getDuration(int *msec) = 0;
-    virtual status_t    reset() = 0;
-    virtual status_t    notifyAt(int64_t /* mediaTimeUs */) {
+    virtual status_t seekTo(
+            int64_t msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
+    virtual status_t getCurrentPosition(int64_t *msec) = 0;
+    virtual status_t getDuration(int64_t *msec) = 0;
+    virtual status_t reset() = 0;
+    virtual status_t notifyAt(int64_t /* mediaTimeUs */) {
         return INVALID_OPERATION;
     }
-    virtual status_t    setLooping(int loop) = 0;
-    virtual status_t    setParameter(int key, const Parcel &request) = 0;
-    virtual status_t    getParameter(int key, Parcel *reply) = 0;
-
-    virtual status_t setNextPlayer(const sp<MediaPlayer2Interface>& /* next */) {
-        return OK;
-    }
+    virtual status_t setLooping(int loop) = 0;
+    virtual status_t setParameter(int key, const Parcel &request) = 0;
+    virtual status_t getParameter(int key, Parcel *reply) = 0;
 
     // Invoke a generic method on the player by using opaque parcels
     // for the request and reply.
@@ -220,7 +218,7 @@
     //                data sent by the java layer.
     // @param[out] reply Parcel to hold the reply data. Cannot be null.
     // @return OK if the call was successful.
-    virtual status_t    invoke(const Parcel& request, Parcel *reply) = 0;
+    virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
 
     // The Client in the MetadataPlayerService calls this method on
     // the native player to retrieve all or a subset of metadata.
@@ -229,28 +227,26 @@
     //            the known metadata should be returned.
     // @param[inout] records Parcel where the player appends its metadata.
     // @return OK if the call was successful.
-    virtual status_t    getMetadata(const media::Metadata::Filter& /* ids */,
-                                    Parcel* /* records */) {
+    virtual status_t getMetadata(const media::Metadata::Filter& /* ids */,
+                                 Parcel* /* records */) {
         return INVALID_OPERATION;
     };
 
-    void        setNotifyCallback(
-            const wp<MediaPlayer2Engine> &client, NotifyCallback notifyFunc) {
-        Mutex::Autolock autoLock(mNotifyLock);
-        mClient = client; mNotify = notifyFunc;
+    void setListener(const sp<MediaPlayer2InterfaceListener> &listener) {
+        Mutex::Autolock autoLock(mListenerLock);
+        mListener = listener;
     }
 
-    void        sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0,
-                          const Parcel *obj=NULL) {
-        NotifyCallback notifyCB;
-        wp<MediaPlayer2Engine> client;
+    void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0, const Parcel *obj=NULL) {
+        sp<MediaPlayer2InterfaceListener> listener;
         {
-            Mutex::Autolock autoLock(mNotifyLock);
-            notifyCB = mNotify;
-            client = mClient;
+            Mutex::Autolock autoLock(mListenerLock);
+            listener = mListener;
         }
 
-        if (notifyCB) notifyCB(client, srcId, msg, ext1, ext2, obj);
+        if (listener) {
+            listener->notify(srcId, msg, ext1, ext2, obj);
+        }
     }
 
     virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
@@ -260,7 +256,8 @@
     virtual void onMessageReceived(const sp<AMessage> & /* msg */) override { }
 
     // Modular DRM
-    virtual status_t prepareDrm(const uint8_t /* uuid */[16], const Vector<uint8_t>& /* drmSessionId */) {
+    virtual status_t prepareDrm(const uint8_t /* uuid */[16],
+                                const Vector<uint8_t>& /* drmSessionId */) {
         return INVALID_OPERATION;
     }
     virtual status_t releaseDrm() {
@@ -268,14 +265,11 @@
     }
 
 protected:
-    sp<AudioSink>       mAudioSink;
+    sp<AudioSink> mAudioSink;
 
 private:
-    friend class MediaPlayer2Manager;
-
-    Mutex                  mNotifyLock;
-    wp<MediaPlayer2Engine> mClient;
-    NotifyCallback         mNotify;
+    Mutex mListenerLock;
+    sp<MediaPlayer2InterfaceListener> mListener;
 };
 
 }; // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
new file mode 100644
index 0000000..260c7ed
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIAPLAYER2_TYPES_H
+#define ANDROID_MEDIAPLAYER2_TYPES_H
+
+#include <media/mediaplayer_common.h>
+
+#include <media/MediaSource.h>
+
+namespace android {
+
+typedef MediaSource::ReadOptions::SeekMode MediaPlayer2SeekMode;
+
+enum media2_event_type {
+    MEDIA2_NOP               = 0, // interface test message
+    MEDIA2_PREPARED          = 1,
+    MEDIA2_PLAYBACK_COMPLETE = 2,
+    MEDIA2_BUFFERING_UPDATE  = 3,
+    MEDIA2_SEEK_COMPLETE     = 4,
+    MEDIA2_SET_VIDEO_SIZE    = 5,
+    MEDIA2_STARTED           = 6,
+    MEDIA2_PAUSED            = 7,
+    MEDIA2_STOPPED           = 8,
+    MEDIA2_SKIPPED           = 9,
+    MEDIA2_NOTIFY_TIME       = 98,
+    MEDIA2_TIMED_TEXT        = 99,
+    MEDIA2_ERROR             = 100,
+    MEDIA2_INFO              = 200,
+    MEDIA2_SUBTITLE_DATA     = 201,
+    MEDIA2_META_DATA         = 202,
+    MEDIA2_DRM_INFO          = 210,
+    MEDIA2_AUDIO_ROUTING_CHANGED = 10000,
+};
+
+// Generic error codes for the media player framework.  Errors are fatal, the
+// playback must abort.
+//
+// Errors are communicated back to the client using the
+// MediaPlayer2Listener::notify method defined below.
+// In this situation, 'notify' is invoked with the following:
+//   'msg' is set to MEDIA_ERROR.
+//   'ext1' should be a value from the enum media2_error_type.
+//   'ext2' contains an implementation dependant error code to provide
+//          more details. Should default to 0 when not used.
+//
+// The codes are distributed as follow:
+//   0xx: Reserved
+//   1xx: Android Player errors. Something went wrong inside the MediaPlayer2.
+//   2xx: Media errors (e.g Codec not supported). There is a problem with the
+//        media itself.
+//   3xx: Runtime errors. Some extraordinary condition arose making the playback
+//        impossible.
+//
+enum media2_error_type {
+    // 0xx
+    MEDIA2_ERROR_UNKNOWN = 1,
+    // 1xx
+    // MEDIA2_ERROR_SERVER_DIED = 100,
+    // 2xx
+    MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
+    // 3xx
+    MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
+};
+
+
+// Info and warning codes for the media player framework.  These are non fatal,
+// the playback is going on but there might be some user visible issues.
+//
+// Info and warning messages are communicated back to the client using the
+// MediaPlayer2Listener::notify method defined below.  In this situation,
+// 'notify' is invoked with the following:
+//   'msg' is set to MEDIA_INFO.
+//   'ext1' should be a value from the enum media2_info_type.
+//   'ext2' contains an implementation dependant info code to provide
+//          more details. Should default to 0 when not used.
+//
+// The codes are distributed as follow:
+//   0xx: Reserved
+//   7xx: Android Player info/warning (e.g player lagging behind.)
+//   8xx: Media info/warning (e.g media badly interleaved.)
+//
+enum media2_info_type {
+    // 0xx
+    MEDIA2_INFO_UNKNOWN = 1,
+    // The player was started because it was used as the next player for another
+    // player, which just completed playback
+    MEDIA2_INFO_STARTED_AS_NEXT = 2,
+    // The player just pushed the very first video frame for rendering
+    MEDIA2_INFO_VIDEO_RENDERING_START = 3,
+    // The player just pushed the very first audio frame for rendering
+    MEDIA2_INFO_AUDIO_RENDERING_START = 4,
+    // The player just completed the playback of this data source
+    MEDIA2_INFO_PLAYBACK_COMPLETE = 5,
+    // The player just completed the playback of the full play list
+    MEDIA2_INFO_PLAYLIST_END = 6,
+
+    //1xx
+    // The player just prepared a data source.
+    MEDIA2_INFO_PREPARED = 100,
+    // The player just completed a call play().
+    MEDIA2_INFO_COMPLETE_CALL_PLAY = 101,
+    // The player just completed a call pause().
+    MEDIA2_INFO_COMPLETE_CALL_PAUSE = 102,
+    // The player just completed a call seekTo.
+    MEDIA2_INFO_COMPLETE_CALL_SEEK = 103,
+
+    // 7xx
+    // The video is too complex for the decoder: it can't decode frames fast
+    // enough. Possibly only the audio plays fine at this stage.
+    MEDIA2_INFO_VIDEO_TRACK_LAGGING = 700,
+    // MediaPlayer2 is temporarily pausing playback internally in order to
+    // buffer more data.
+    MEDIA2_INFO_BUFFERING_START = 701,
+    // MediaPlayer2 is resuming playback after filling buffers.
+    MEDIA2_INFO_BUFFERING_END = 702,
+    // Bandwidth in recent past
+    MEDIA2_INFO_NETWORK_BANDWIDTH = 703,
+
+    // 8xx
+    // Bad interleaving means that a media has been improperly interleaved or not
+    // interleaved at all, e.g has all the video samples first then all the audio
+    // ones. Video is playing but a lot of disk seek may be happening.
+    MEDIA2_INFO_BAD_INTERLEAVING = 800,
+    // The media is not seekable (e.g live stream).
+    MEDIA2_INFO_NOT_SEEKABLE = 801,
+    // New media metadata is available.
+    MEDIA2_INFO_METADATA_UPDATE = 802,
+    // Audio can not be played.
+    MEDIA2_INFO_PLAY_AUDIO_ERROR = 804,
+    // Video can not be played.
+    MEDIA2_INFO_PLAY_VIDEO_ERROR = 805,
+
+    //9xx
+    MEDIA2_INFO_TIMED_TEXT_ERROR = 900,
+};
+
+enum media_player2_states {
+    MEDIA_PLAYER2_STATE_ERROR        = 0,
+    MEDIA_PLAYER2_IDLE               = 1 << 0,
+    MEDIA_PLAYER2_INITIALIZED        = 1 << 1,
+    MEDIA_PLAYER2_PREPARING          = 1 << 2,
+    MEDIA_PLAYER2_PREPARED           = 1 << 3,
+    MEDIA_PLAYER2_STARTED            = 1 << 4,
+    MEDIA_PLAYER2_PAUSED             = 1 << 5,
+    MEDIA_PLAYER2_STOPPED            = 1 << 6,
+    MEDIA_PLAYER2_PLAYBACK_COMPLETE  = 1 << 7
+};
+
+// Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
+// The same enum space is used for both set and get, in case there are future keys that
+// can be both set and get.  But as of now, all parameters are either set only or get only.
+enum media2_parameter_keys {
+    // Streaming/buffering parameters
+    MEDIA2_KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100,            // set only
+
+    // Return a Parcel containing a single int, which is the channel count of the
+    // audio track, or zero for error (e.g. no audio track) or unknown.
+    MEDIA2_KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200,                   // get only
+
+    // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
+    // values used for rewinding or reverse playback.
+    MEDIA2_KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300,                // set only
+
+    // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
+    MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400                       // set only
+};
+
+// Keep INVOKE_ID_* in sync with MediaPlayer2.java.
+enum media_player2_invoke_ids {
+    MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO = 1,
+    MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
+    MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
+    MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK = 4,
+    MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK = 5,
+    MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
+    MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK = 7
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAPLAYER2_TYPES_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index e9d6f84..3433cb1 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -17,179 +17,27 @@
 #ifndef ANDROID_MEDIAPLAYER2_H
 #define ANDROID_MEDIAPLAYER2_H
 
-#include <media/mediaplayer_common.h>
-
-#include <arpa/inet.h>
-
+#include <media/AVSyncSettings.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/BufferingSettings.h>
-#include <mediaplayer2/MediaPlayer2EngineClient.h>
-#include <mediaplayer2/MediaPlayer2Engine.h>
+#include <media/Metadata.h>
+#include <media/mediaplayer_common.h>
+#include <mediaplayer2/MediaPlayer2Interface.h>
+#include <mediaplayer2/MediaPlayer2Types.h>
 
-#include <utils/Condition.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/ThreadDefs.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+#include <system/audio-base.h>
 
 namespace android {
 
-struct AVSyncSettings;
 struct ANativeWindowWrapper;
-class DataSource;
 struct DataSourceDesc;
-struct MediaHTTPService;
+class MediaPlayer2AudioOutput;
 
-enum media2_event_type {
-    MEDIA2_NOP               = 0, // interface test message
-    MEDIA2_PREPARED          = 1,
-    MEDIA2_PLAYBACK_COMPLETE = 2,
-    MEDIA2_BUFFERING_UPDATE  = 3,
-    MEDIA2_SEEK_COMPLETE     = 4,
-    MEDIA2_SET_VIDEO_SIZE    = 5,
-    MEDIA2_STARTED           = 6,
-    MEDIA2_PAUSED            = 7,
-    MEDIA2_STOPPED           = 8,
-    MEDIA2_SKIPPED           = 9,
-    MEDIA2_NOTIFY_TIME       = 98,
-    MEDIA2_TIMED_TEXT        = 99,
-    MEDIA2_ERROR             = 100,
-    MEDIA2_INFO              = 200,
-    MEDIA2_SUBTITLE_DATA     = 201,
-    MEDIA2_META_DATA         = 202,
-    MEDIA2_DRM_INFO          = 210,
-    MEDIA2_AUDIO_ROUTING_CHANGED = 10000,
-};
-
-// Generic error codes for the media player framework.  Errors are fatal, the
-// playback must abort.
-//
-// Errors are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below.
-// In this situation, 'notify' is invoked with the following:
-//   'msg' is set to MEDIA_ERROR.
-//   'ext1' should be a value from the enum media2_error_type.
-//   'ext2' contains an implementation dependant error code to provide
-//          more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-//   0xx: Reserved
-//   1xx: Android Player errors. Something went wrong inside the MediaPlayer2.
-//   2xx: Media errors (e.g Codec not supported). There is a problem with the
-//        media itself.
-//   3xx: Runtime errors. Some extraordinary condition arose making the playback
-//        impossible.
-//
-enum media2_error_type {
-    // 0xx
-    MEDIA2_ERROR_UNKNOWN = 1,
-    // 1xx
-    // MEDIA2_ERROR_SERVER_DIED = 100,
-    // 2xx
-    MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
-    // 3xx
-    MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
-};
-
-
-// Info and warning codes for the media player framework.  These are non fatal,
-// the playback is going on but there might be some user visible issues.
-//
-// Info and warning messages are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below.  In this situation,
-// 'notify' is invoked with the following:
-//   'msg' is set to MEDIA_INFO.
-//   'ext1' should be a value from the enum media2_info_type.
-//   'ext2' contains an implementation dependant info code to provide
-//          more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-//   0xx: Reserved
-//   7xx: Android Player info/warning (e.g player lagging behind.)
-//   8xx: Media info/warning (e.g media badly interleaved.)
-//
-enum media2_info_type {
-    // 0xx
-    MEDIA2_INFO_UNKNOWN = 1,
-    // The player was started because it was used as the next player for another
-    // player, which just completed playback
-    MEDIA2_INFO_STARTED_AS_NEXT = 2,
-    // The player just pushed the very first video frame for rendering
-    MEDIA2_INFO_RENDERING_START = 3,
-    // 7xx
-    // The video is too complex for the decoder: it can't decode frames fast
-    // enough. Possibly only the audio plays fine at this stage.
-    MEDIA2_INFO_VIDEO_TRACK_LAGGING = 700,
-    // MediaPlayer2 is temporarily pausing playback internally in order to
-    // buffer more data.
-    MEDIA2_INFO_BUFFERING_START = 701,
-    // MediaPlayer2 is resuming playback after filling buffers.
-    MEDIA2_INFO_BUFFERING_END = 702,
-    // Bandwidth in recent past
-    MEDIA2_INFO_NETWORK_BANDWIDTH = 703,
-
-    // 8xx
-    // Bad interleaving means that a media has been improperly interleaved or not
-    // interleaved at all, e.g has all the video samples first then all the audio
-    // ones. Video is playing but a lot of disk seek may be happening.
-    MEDIA2_INFO_BAD_INTERLEAVING = 800,
-    // The media is not seekable (e.g live stream).
-    MEDIA2_INFO_NOT_SEEKABLE = 801,
-    // New media metadata is available.
-    MEDIA2_INFO_METADATA_UPDATE = 802,
-    // Audio can not be played.
-    MEDIA2_INFO_PLAY_AUDIO_ERROR = 804,
-    // Video can not be played.
-    MEDIA2_INFO_PLAY_VIDEO_ERROR = 805,
-
-    //9xx
-    MEDIA2_INFO_TIMED_TEXT_ERROR = 900,
-};
-
-
-
-enum media_player2_states {
-    MEDIA_PLAYER2_STATE_ERROR        = 0,
-    MEDIA_PLAYER2_IDLE               = 1 << 0,
-    MEDIA_PLAYER2_INITIALIZED        = 1 << 1,
-    MEDIA_PLAYER2_PREPARING          = 1 << 2,
-    MEDIA_PLAYER2_PREPARED           = 1 << 3,
-    MEDIA_PLAYER2_STARTED            = 1 << 4,
-    MEDIA_PLAYER2_PAUSED             = 1 << 5,
-    MEDIA_PLAYER2_STOPPED            = 1 << 6,
-    MEDIA_PLAYER2_PLAYBACK_COMPLETE  = 1 << 7
-};
-
-// Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
-// The same enum space is used for both set and get, in case there are future keys that
-// can be both set and get.  But as of now, all parameters are either set only or get only.
-enum media2_parameter_keys {
-    // Streaming/buffering parameters
-    MEDIA2_KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100,            // set only
-
-    // Return a Parcel containing a single int, which is the channel count of the
-    // audio track, or zero for error (e.g. no audio track) or unknown.
-    MEDIA2_KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200,                   // get only
-
-    // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
-    // values used for rewinding or reverse playback.
-    MEDIA2_KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300,                // set only
-
-    // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
-    MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400                       // set only
-};
-
-// Keep INVOKE_ID_* in sync with MediaPlayer2.java.
-enum media_player2_invoke_ids {
-    MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO = 1,
-    MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
-    MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
-    MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK = 4,
-    MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK = 5,
-    MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
-    MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK = 7
-};
-
-// ----------------------------------------------------------------------------
 // ref-counted object for callbacks
 class MediaPlayer2Listener: virtual public RefBase
 {
@@ -197,20 +45,24 @@
     virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
-class MediaPlayer2 : public MediaPlayer2EngineClient
+class MediaPlayer2 : public MediaPlayer2InterfaceListener
 {
 public:
-    MediaPlayer2();
     ~MediaPlayer2();
+
+    static sp<MediaPlayer2> Create();
+    static status_t DumpAll(int fd, const Vector<String16>& args);
+
             void            disconnect();
 
             status_t        getSrcId(int64_t *srcId);
             status_t        setDataSource(const sp<DataSourceDesc> &dsd);
+            status_t        prepareNextDataSource(const sp<DataSourceDesc> &dsd);
+            status_t        playNextDataSource(int64_t srcId);
             status_t        setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
             status_t        setListener(const sp<MediaPlayer2Listener>& listener);
             status_t        getBufferingSettings(BufferingSettings* buffering /* nonnull */);
             status_t        setBufferingSettings(const BufferingSettings& buffering);
-            status_t        prepare();
             status_t        prepareAsync();
             status_t        start();
             status_t        stop();
@@ -225,11 +77,11 @@
             status_t        getVideoWidth(int *w);
             status_t        getVideoHeight(int *h);
             status_t        seekTo(
-                    int msec,
+                    int64_t msec,
                     MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
             status_t        notifyAt(int64_t mediaTimeUs);
-            status_t        getCurrentPosition(int *msec);
-            status_t        getDuration(int *msec);
+            status_t        getCurrentPosition(int64_t *msec);
+            status_t        getDuration(int64_t *msec);
             status_t        reset();
             status_t        setAudioStreamType(audio_stream_type_t type);
             status_t        getAudioStreamType(audio_stream_type_t *type);
@@ -247,7 +99,6 @@
             status_t        attachAuxEffect(int effectId);
             status_t        setParameter(int key, const Parcel& request);
             status_t        getParameter(int key, Parcel* reply);
-            status_t        setNextMediaPlayer(const sp<MediaPlayer2>& player);
 
             // Modular DRM
             status_t        prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
@@ -257,30 +108,48 @@
             audio_port_handle_t getRoutedDeviceId();
             status_t        enableAudioDeviceCallback(bool enabled);
 
-private:
-            void            clear_l();
-            status_t        seekTo_l(int msec, MediaPlayer2SeekMode mode);
-            status_t        prepareAsync_l();
-            status_t        getDuration_l(int *msec);
-            status_t        attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId);
-            status_t        reset_l();
-            status_t        checkStateForKeySet_l(int key);
+            status_t        dump(int fd, const Vector<String16>& args);
 
-    sp<MediaPlayer2Engine>      mPlayer;
+private:
+    MediaPlayer2();
+    bool init();
+
+    // @param type Of the metadata to be tested.
+    // @return true if the metadata should be dropped according to
+    //              the filters.
+    bool shouldDropMetadata(media::Metadata::Type type) const;
+
+    // Add a new element to the set of metadata updated. Noop if
+    // the element exists already.
+    // @param type Of the metadata to be recorded.
+    void addNewMetadataUpdate(media::Metadata::Type type);
+
+    // Disconnect from the currently connected ANativeWindow.
+    void disconnectNativeWindow_l();
+
+    status_t setAudioAttributes_l(const Parcel &request);
+
+    void clear_l();
+    status_t seekTo_l(int64_t msec, MediaPlayer2SeekMode mode);
+    status_t prepareAsync_l();
+    status_t getDuration_l(int64_t *msec);
+    status_t reset_l();
+    status_t checkStateForKeySet_l(int key);
+
+    pid_t                       mPid;
+    uid_t                       mUid;
+    sp<MediaPlayer2Interface>   mPlayer;
+    sp<MediaPlayer2AudioOutput> mAudioOutput;
     int64_t                     mSrcId;
     thread_id_t                 mLockThreadId;
-    Mutex                       mLock;
+    mutable Mutex               mLock;
     Mutex                       mNotifyLock;
-    Condition                   mSignal;
     sp<MediaPlayer2Listener>    mListener;
-    void*                       mCookie;
     media_player2_states        mCurrentState;
-    int                         mCurrentPosition;
+    int64_t                     mCurrentPosition;
     MediaPlayer2SeekMode        mCurrentSeekMode;
-    int                         mSeekPosition;
+    int64_t                     mSeekPosition;
     MediaPlayer2SeekMode        mSeekMode;
-    bool                        mPrepareSync;
-    status_t                    mPrepareStatus;
     audio_stream_type_t         mStreamType;
     Parcel*                     mAudioAttributesParcel;
     bool                        mLoop;
@@ -289,7 +158,20 @@
     int                         mVideoWidth;
     int                         mVideoHeight;
     audio_session_t             mAudioSessionId;
+    audio_attributes_t *        mAudioAttributes;
     float                       mSendLevel;
+
+    sp<ANativeWindowWrapper>    mConnectedWindow;
+
+    // Metadata filters.
+    media::Metadata::Filter mMetadataAllow;  // protected by mLock
+    media::Metadata::Filter mMetadataDrop;  // protected by mLock
+
+    // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
+    // notification we try to update mMetadataUpdated which is a
+    // set: no duplicate.
+    // getMetadata clears this set.
+    media::Metadata::Filter mMetadataUpdated;  // protected by mLock
 };
 
 }; // namespace android
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index ab30273..c465caa 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -18,44 +18,391 @@
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaPlayer2Native"
 
-#include <fcntl.h>
-#include <inttypes.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <utils/Log.h>
-
 #include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
 
-#include <media/AudioResamplerPublic.h>
 #include <media/AudioSystem.h>
-#include <media/AVSyncSettings.h>
-#include <media/DataSource.h>
 #include <media/DataSourceDesc.h>
 #include <media/MediaAnalyticsItem.h>
+#include <media/MemoryLeakTrackUtil.h>
+#include <media/Metadata.h>
 #include <media/NdkWrapper.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooperRoster.h>
+#include <mediaplayer2/MediaPlayer2AudioOutput.h>
 #include <mediaplayer2/mediaplayer2.h>
 
-#include <binder/MemoryBase.h>
-
-#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
 #include <utils/String8.h>
 
 #include <system/audio.h>
 #include <system/window.h>
 
-#include "MediaPlayer2Manager.h"
+#include <nuplayer2/NuPlayer2Driver.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
 
 namespace android {
 
-MediaPlayer2::MediaPlayer2()
-{
+extern ALooperRoster gLooperRoster;
+
+namespace {
+
+const int kDumpLockRetries = 50;
+const int kDumpLockSleepUs = 20000;
+
+// Max number of entries in the filter.
+const int kMaxFilterSize = 64;  // I pulled that out of thin air.
+
+// FIXME: Move all the metadata related function in the Metadata.cpp
+
+// Unmarshall a filter from a Parcel.
+// Filter format in a parcel:
+//
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       number of entries (n)                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 1                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 2                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type n                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that should start with a filter.
+// @param[out] filter On exit contains the list of metadata type to be
+//                    filtered.
+// @param[out] status On exit contains the status code to be returned.
+// @return true if the parcel starts with a valid filter.
+bool unmarshallFilter(const Parcel& p,
+                      media::Metadata::Filter *filter,
+                      status_t *status) {
+    int32_t val;
+    if (p.readInt32(&val) != OK) {
+        ALOGE("Failed to read filter's length");
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    if (val > kMaxFilterSize || val < 0) {
+        ALOGE("Invalid filter len %d", val);
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    const size_t num = val;
+
+    filter->clear();
+    filter->setCapacity(num);
+
+    size_t size = num * sizeof(media::Metadata::Type);
+
+
+    if (p.dataAvail() < size) {
+        ALOGE("Filter too short expected %zu but got %zu", size, p.dataAvail());
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    const media::Metadata::Type *data =
+        static_cast<const media::Metadata::Type*>(p.readInplace(size));
+
+    if (NULL == data) {
+        ALOGE("Filter had no data");
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    // TODO: The stl impl of vector would be more efficient here
+    // because it degenerates into a memcpy on pod types. Try to
+    // replace later or use stl::set.
+    for (size_t i = 0; i < num; ++i) {
+        filter->add(*data);
+        ++data;
+    }
+    *status = OK;
+    return true;
+}
+
+// @param filter Of metadata type.
+// @param val To be searched.
+// @return true if a match was found.
+bool findMetadata(const media::Metadata::Filter& filter, const int32_t val) {
+    // Deal with empty and ANY right away
+    if (filter.isEmpty()) {
+        return false;
+    }
+    if (filter[0] == media::Metadata::kAny) {
+        return true;
+    }
+
+    return filter.indexOf(val) >= 0;
+}
+
+// marshalling tag indicating flattened utf16 tags
+// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java
+const int32_t kAudioAttributesMarshallTagFlattenTags = 1;
+
+// Audio attributes format in a parcel:
+//
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       usage                                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       content_type                            |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       source                                  |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       flags                                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       kAudioAttributesMarshallTagFlattenTags  | // ignore tags if not found
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       flattened tags in UTF16                 |
+// |                         ...                                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that contains audio attributes.
+// @param[out] attributes On exit points to an initialized audio_attributes_t structure
+// @param[out] status On exit contains the status code to be returned.
+void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes) {
+    attributes->usage = (audio_usage_t) parcel.readInt32();
+    attributes->content_type = (audio_content_type_t) parcel.readInt32();
+    attributes->source = (audio_source_t) parcel.readInt32();
+    attributes->flags = (audio_flags_mask_t) parcel.readInt32();
+    const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags);
+    if (hasFlattenedTag) {
+        // the tags are UTF16, convert to UTF8
+        String16 tags = parcel.readString16();
+        ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size());
+        if (realTagSize <= 0) {
+            strcpy(attributes->tags, "");
+        } else {
+            // copy the flattened string into the attributes as the destination for the conversion:
+            // copying array size -1, array for tags was calloc'd, no need to NULL-terminate it
+            size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ?
+                    AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize;
+            utf16_to_utf8(tags.string(), tagSize, attributes->tags,
+                    sizeof(attributes->tags) / sizeof(attributes->tags[0]));
+        }
+    } else {
+        ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values");
+        strcpy(attributes->tags, "");
+    }
+}
+
+class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback {
+public:
+    AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener)
+        : mListener(listener) { }
+
+    ~AudioDeviceUpdatedNotifier() { }
+
+    virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                     audio_port_handle_t deviceId) override {
+        sp<MediaPlayer2Interface> listener = mListener.promote();
+        if (listener != NULL) {
+            listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+        } else {
+            ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
+        }
+    }
+
+private:
+    wp<MediaPlayer2Interface> mListener;
+};
+
+class proxyListener : public MediaPlayer2InterfaceListener {
+public:
+    proxyListener(const wp<MediaPlayer2> &player)
+        : mPlayer(player) { }
+
+    ~proxyListener() { };
+
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) override {
+        sp<MediaPlayer2> player = mPlayer.promote();
+        if (player != NULL) {
+            player->notify(srcId, msg, ext1, ext2, obj);
+        }
+    }
+
+private:
+    wp<MediaPlayer2> mPlayer;
+};
+
+Mutex sRecordLock;
+SortedVector<wp<MediaPlayer2> > *sPlayers;
+
+void ensureInit_l() {
+    if (sPlayers == NULL) {
+        sPlayers = new SortedVector<wp<MediaPlayer2> >();
+    }
+}
+
+void addPlayer(const wp<MediaPlayer2>& player) {
+    Mutex::Autolock lock(sRecordLock);
+    ensureInit_l();
+    sPlayers->add(player);
+}
+
+void removePlayer(const wp<MediaPlayer2>& player) {
+    Mutex::Autolock lock(sRecordLock);
+    ensureInit_l();
+    sPlayers->remove(player);
+}
+
+/**
+ * The only arguments this understands right now are -c, -von and -voff,
+ * which are parsed by ALooperRoster::dump()
+ */
+status_t dumpPlayers(int fd, const Vector<String16>& args) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    SortedVector< sp<MediaPlayer2> > players; //to serialise the mutex unlock & client destruction.
+
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: can't dump MediaPlayer2\n");
+        result.append(buffer);
+    } else {
+        {
+            Mutex::Autolock lock(sRecordLock);
+            ensureInit_l();
+            for (int i = 0, n = sPlayers->size(); i < n; ++i) {
+                sp<MediaPlayer2> p = (*sPlayers)[i].promote();
+                if (p != 0) {
+                    p->dump(fd, args);
+                }
+                players.add(p);
+            }
+        }
+
+        result.append(" Files opened and/or mapped:\n");
+        snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
+        FILE *f = fopen(buffer, "r");
+        if (f) {
+            while (!feof(f)) {
+                fgets(buffer, SIZE, f);
+                if (strstr(buffer, " /storage/") ||
+                    strstr(buffer, " /system/sounds/") ||
+                    strstr(buffer, " /data/") ||
+                    strstr(buffer, " /system/media/")) {
+                    result.append("  ");
+                    result.append(buffer);
+                }
+            }
+            fclose(f);
+        } else {
+            result.append("couldn't open ");
+            result.append(buffer);
+            result.append("\n");
+        }
+
+        snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
+        DIR *d = opendir(buffer);
+        if (d) {
+            struct dirent *ent;
+            while((ent = readdir(d)) != NULL) {
+                if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
+                    snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
+                    struct stat s;
+                    if (lstat(buffer, &s) == 0) {
+                        if ((s.st_mode & S_IFMT) == S_IFLNK) {
+                            char linkto[256];
+                            int len = readlink(buffer, linkto, sizeof(linkto));
+                            if(len > 0) {
+                                if(len > 255) {
+                                    linkto[252] = '.';
+                                    linkto[253] = '.';
+                                    linkto[254] = '.';
+                                    linkto[255] = 0;
+                                } else {
+                                    linkto[len] = 0;
+                                }
+                                if (strstr(linkto, "/storage/") == linkto ||
+                                    strstr(linkto, "/system/sounds/") == linkto ||
+                                    strstr(linkto, "/data/") == linkto ||
+                                    strstr(linkto, "/system/media/") == linkto) {
+                                    result.append("  ");
+                                    result.append(buffer);
+                                    result.append(" -> ");
+                                    result.append(linkto);
+                                    result.append("\n");
+                                }
+                            }
+                        } else {
+                            result.append("  unexpected type for ");
+                            result.append(buffer);
+                            result.append("\n");
+                        }
+                    }
+                }
+            }
+            closedir(d);
+        } else {
+            result.append("couldn't open ");
+            result.append(buffer);
+            result.append("\n");
+        }
+
+        gLooperRoster.dump(fd, args);
+
+        bool dumpMem = false;
+        bool unreachableMemory = false;
+        for (size_t i = 0; i < args.size(); i++) {
+            if (args[i] == String16("-m")) {
+                dumpMem = true;
+            } else if (args[i] == String16("--unreachable")) {
+                unreachableMemory = true;
+            }
+        }
+        if (dumpMem) {
+            result.append("\nDumping memory:\n");
+            std::string s = dumpMemoryAddresses(100 /* limit */);
+            result.append(s.c_str(), s.size());
+        }
+        if (unreachableMemory) {
+            result.append("\nDumping unreachable memory:\n");
+            // TODO - should limit be an argument parameter?
+            // TODO: enable GetUnreachableMemoryString if it's part of stable API
+            //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
+            //result.append(s.c_str(), s.size());
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+}  // anonymous namespace
+
+//static
+sp<MediaPlayer2> MediaPlayer2::Create() {
+    sp<MediaPlayer2> player = new MediaPlayer2();
+
+    if (!player->init()) {
+        return NULL;
+    }
+
+    ALOGV("Create new player(%p)", player.get());
+
+    addPlayer(player);
+    return player;
+}
+
+// static
+status_t MediaPlayer2::DumpAll(int fd, const Vector<String16>& args) {
+    return dumpPlayers(fd, args);
+}
+
+MediaPlayer2::MediaPlayer2() {
     ALOGV("constructor");
     mSrcId = 0;
+    mLockThreadId = 0;
     mListener = NULL;
-    mCookie = NULL;
     mStreamType = AUDIO_STREAM_MUSIC;
     mAudioAttributesParcel = NULL;
     mCurrentPosition = -1;
@@ -63,19 +410,21 @@
     mSeekPosition = -1;
     mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mCurrentState = MEDIA_PLAYER2_IDLE;
-    mPrepareSync = false;
-    mPrepareStatus = NO_ERROR;
     mLoop = false;
     mLeftVolume = mRightVolume = 1.0;
     mVideoWidth = mVideoHeight = 0;
-    mLockThreadId = 0;
     mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
     AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
     mSendLevel = 0;
+
+    // TODO: get pid and uid from JAVA
+    mPid = IPCThreadState::self()->getCallingPid();
+    mUid = IPCThreadState::self()->getCallingUid();
+
+    mAudioAttributes = NULL;
 }
 
-MediaPlayer2::~MediaPlayer2()
-{
+MediaPlayer2::~MediaPlayer2() {
     ALOGV("destructor");
     if (mAudioAttributesParcel != NULL) {
         delete mAudioAttributesParcel;
@@ -83,13 +432,21 @@
     }
     AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
     disconnect();
-    IPCThreadState::self()->flushCommands();
+    removePlayer(this);
+    if (mAudioAttributes != NULL) {
+        free(mAudioAttributes);
+    }
 }
 
-void MediaPlayer2::disconnect()
-{
+bool MediaPlayer2::init() {
+    // TODO: after merge with NuPlayer2Driver, MediaPlayer2 will have its own
+    // looper for notification.
+    return true;
+}
+
+void MediaPlayer2::disconnect() {
     ALOGV("disconnect");
-    sp<MediaPlayer2Engine> p;
+    sp<MediaPlayer2Interface> p;
     {
         Mutex::Autolock _l(mLock);
         p = mPlayer;
@@ -97,13 +454,17 @@
     }
 
     if (p != 0) {
-        p->disconnect();
+        p->setListener(NULL);
+        p->reset();
+    }
+
+    {
+        Mutex::Autolock _l(mLock);
+        disconnectNativeWindow_l();
     }
 }
 
-// always call with lock held
-void MediaPlayer2::clear_l()
-{
+void MediaPlayer2::clear_l() {
     mCurrentPosition = -1;
     mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
     mSeekPosition = -1;
@@ -111,8 +472,7 @@
     mVideoWidth = mVideoHeight = 0;
 }
 
-status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener)
-{
+status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener) {
     ALOGV("setListener");
     Mutex::Autolock _l(mLock);
     mListener = listener;
@@ -129,109 +489,236 @@
     return OK;
 }
 
-status_t MediaPlayer2::attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId)
-{
-    status_t err = UNKNOWN_ERROR;
-    sp<MediaPlayer2Engine> p;
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-
-        if ( !( (mCurrentState & MEDIA_PLAYER2_IDLE) ||
-                (mCurrentState == MEDIA_PLAYER2_STATE_ERROR ) ) ) {
-            ALOGE("attachNewPlayer called in state %d", mCurrentState);
-            return INVALID_OPERATION;
-        }
-
-        clear_l();
-        p = mPlayer;
-        mPlayer = player;
-        mSrcId = srcId;
-        if (player != 0) {
-            mCurrentState = MEDIA_PLAYER2_INITIALIZED;
-            err = NO_ERROR;
-        } else {
-            ALOGE("Unable to create media player");
-        }
-    }
-
-    if (p != 0) {
-        p->disconnect();
-    }
-
-    return err;
-}
-
-status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd)
-{
+status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
     if (dsd == NULL) {
         return BAD_VALUE;
     }
-    ALOGV("setDataSource type(%d)", dsd->mType);
-    status_t err = UNKNOWN_ERROR;
-    sp<MediaPlayer2Engine> player(MediaPlayer2Manager::get().create(this, mAudioSessionId));
-    if (NO_ERROR != player->setDataSource(dsd)) {
-        player.clear();
+    ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
+
+    sp<MediaPlayer2Interface> oldPlayer;
+
+    Mutex::Autolock _l(mLock);
+    {
+        if (!((mCurrentState & MEDIA_PLAYER2_IDLE)
+              || mCurrentState == MEDIA_PLAYER2_STATE_ERROR)) {
+            ALOGE("setDataSource called in wrong state %d", mCurrentState);
+            return INVALID_OPERATION;
+        }
+
+        sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid);
+        status_t err = player->initCheck();
+        if (err != NO_ERROR) {
+            ALOGE("Failed to create player object, initCheck failed(%d)", err);
+            return err;
+        }
+
+        clear_l();
+
+        player->setListener(new proxyListener(this));
+        mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid,
+                mPid, mAudioAttributes, new AudioDeviceUpdatedNotifier(player));
+        player->setAudioSink(mAudioOutput);
+
+        err = player->setDataSource(dsd);
+        if (err != OK) {
+            ALOGE("setDataSource error: %d", err);
+            return err;
+        }
+
+        sp<MediaPlayer2Interface> oldPlayer = mPlayer;
+        mPlayer = player;
+        mSrcId = dsd->mId;
+        mCurrentState = MEDIA_PLAYER2_INITIALIZED;
     }
-    err = attachNewPlayer(player, dsd->mId);
-    return err;
+
+    if (oldPlayer != NULL) {
+        oldPlayer->setListener(NULL);
+        oldPlayer->reset();
+    }
+
+    return OK;
 }
 
-status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply)
-{
+status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
+    if (dsd == NULL) {
+        return BAD_VALUE;
+    }
+    ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
+
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+        return INVALID_OPERATION;
+    }
+    return mPlayer->prepareNextDataSource(dsd);
+}
+
+status_t MediaPlayer2::playNextDataSource(int64_t srcId) {
+    ALOGV("playNextDataSource srcId(%lld)", (long long)srcId);
+
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+        return INVALID_OPERATION;
+    }
+    mSrcId = srcId;
+    return mPlayer->playNextDataSource(srcId);
+}
+
+status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply) {
     Mutex::Autolock _l(mLock);
     const bool hasBeenInitialized =
             (mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
             ((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
-    if ((mPlayer != NULL) && hasBeenInitialized) {
-        ALOGV("invoke %zu", request.dataSize());
-        return  mPlayer->invoke(request, reply);
+    if ((mPlayer == NULL) || !hasBeenInitialized) {
+        ALOGE("invoke failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+        return INVALID_OPERATION;
     }
-    ALOGE("invoke failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
-    return INVALID_OPERATION;
+    ALOGV("invoke %zu", request.dataSize());
+    return mPlayer->invoke(request, reply);
 }
 
-status_t MediaPlayer2::setMetadataFilter(const Parcel& filter)
-{
+// This call doesn't need to access the native player.
+status_t MediaPlayer2::setMetadataFilter(const Parcel& filter) {
     ALOGD("setMetadataFilter");
-    Mutex::Autolock lock(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
+
+    status_t status;
+    media::Metadata::Filter allow, drop;
+
+    if (unmarshallFilter(filter, &allow, &status) &&
+        unmarshallFilter(filter, &drop, &status)) {
+        Mutex::Autolock lock(mLock);
+
+        mMetadataAllow = allow;
+        mMetadataDrop = drop;
     }
-    return mPlayer->setMetadataFilter(filter);
+    return status;
 }
 
-status_t MediaPlayer2::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
-{
+status_t MediaPlayer2::getMetadata(bool update_only, bool /* apply_filter */, Parcel *reply) {
     ALOGD("getMetadata");
+    sp<MediaPlayer2Interface> player;
+    media::Metadata::Filter ids;
     Mutex::Autolock lock(mLock);
-    if (mPlayer == NULL) {
+    {
+        if (mPlayer == NULL) {
+            return NO_INIT;
+        }
+
+        player = mPlayer;
+        // Placeholder for the return code, updated by the caller.
+        reply->writeInt32(-1);
+
+        // We don't block notifications while we fetch the data. We clear
+        // mMetadataUpdated first so we don't lose notifications happening
+        // during the rest of this call.
+        if (update_only) {
+            ids = mMetadataUpdated;
+        }
+        mMetadataUpdated.clear();
+    }
+
+    media::Metadata metadata(reply);
+
+    metadata.appendHeader();
+    status_t status = player->getMetadata(ids, reply);
+
+    if (status != OK) {
+        metadata.resetParcel();
+        ALOGE("getMetadata failed %d", status);
+        return status;
+    }
+
+    // FIXME: ement filtering on the result. Not critical since
+    // filtering takes place on the update notifications already. This
+    // would be when all the metadata are fetch and a filter is set.
+
+    // Everything is fine, update the metadata length.
+    metadata.updateLength();
+    return OK;
+}
+
+void MediaPlayer2::disconnectNativeWindow_l() {
+    if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
+        status_t err = native_window_api_disconnect(
+                mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+                  strerror(-err), err);
+        }
+    }
+    mConnectedWindow.clear();
+}
+
+status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) {
+    ANativeWindow *anw = (nww == NULL ? NULL : nww->getANativeWindow());
+    ALOGV("setVideoSurfaceTexture(%p)", anw);
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == 0) {
         return NO_INIT;
     }
-    return mPlayer->getMetadata(update_only, apply_filter, metadata);
+
+    if (anw != NULL) {
+        if (mConnectedWindow != NULL
+            && mConnectedWindow->getANativeWindow() == anw) {
+            return OK;
+        }
+        status_t err = native_window_api_connect(anw, NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            ALOGE("setVideoSurfaceTexture failed: %d", err);
+            // Note that we must do the reset before disconnecting from the ANW.
+            // Otherwise queue/dequeue calls could be made on the disconnected
+            // ANW, which may result in errors.
+            mPlayer->reset();
+            disconnectNativeWindow_l();
+            return err;
+        }
+    }
+
+    // Note that we must set the player's new GraphicBufferProducer before
+    // disconnecting the old one.  Otherwise queue/dequeue calls could be made
+    // on the disconnected ANW, which may result in errors.
+    status_t err = mPlayer->setVideoSurfaceTexture(nww);
+
+    disconnectNativeWindow_l();
+
+    if (err == OK) {
+        mConnectedWindow = nww;
+        mLock.unlock();
+    } else if (anw != NULL) {
+        mLock.unlock();
+        status_t err = native_window_api_disconnect(anw, NATIVE_WINDOW_API_MEDIA);
+
+        if (err != OK) {
+            ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+                  strerror(-err), err);
+        }
+    }
+
+    return err;
 }
 
-status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww)
-{
-    ALOGV("setVideoSurfaceTexture");
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return NO_INIT;
-    return mPlayer->setVideoSurfaceTexture(nww);
-}
-
-status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */)
-{
+status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
     ALOGV("getBufferingSettings");
 
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) {
         return NO_INIT;
     }
-    return mPlayer->getBufferingSettings(buffering);
+
+    status_t ret = mPlayer->getBufferingSettings(buffering);
+    if (ret == NO_ERROR) {
+        ALOGV("getBufferingSettings{%s}", buffering->toString().string());
+    } else {
+        ALOGE("getBufferingSettings returned %d", ret);
+    }
+    return ret;
 }
 
-status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering)
-{
-    ALOGV("setBufferingSettings");
+status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
+    ALOGV("setBufferingSettings{%s}", buffering.toString().string());
 
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) {
@@ -240,14 +727,37 @@
     return mPlayer->setBufferingSettings(buffering);
 }
 
-// must call with lock held
-status_t MediaPlayer2::prepareAsync_l()
-{
-    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_STOPPED) ) ) {
+status_t MediaPlayer2::setAudioAttributes_l(const Parcel &parcel) {
+    if (mAudioAttributes != NULL) {
+        free(mAudioAttributes);
+    }
+    mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+    if (mAudioAttributes == NULL) {
+        return NO_MEMORY;
+    }
+    unmarshallAudioAttributes(parcel, mAudioAttributes);
+
+    ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s",
+            mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags,
+            mAudioAttributes->tags);
+
+    if (mAudioOutput != 0) {
+        mAudioOutput->setAudioAttributes(mAudioAttributes);
+    }
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2::prepareAsync() {
+    ALOGV("prepareAsync");
+    Mutex::Autolock _l(mLock);
+    if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_STOPPED))) {
         if (mAudioAttributesParcel != NULL) {
-            mPlayer->setParameter(MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
-        } else {
-            mPlayer->setAudioStreamType(mStreamType);
+            status_t err = setAudioAttributes_l(*mAudioAttributesParcel);
+            if (err != OK) {
+                return err;
+            }
+        } else if (mAudioOutput != 0) {
+            mAudioOutput->setAudioStreamType(mStreamType);
         }
         mCurrentState = MEDIA_PLAYER2_PREPARING;
         return mPlayer->prepareAsync();
@@ -256,44 +766,7 @@
     return INVALID_OPERATION;
 }
 
-// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
-// one defined in the Android framework and one provided by the implementation
-// that generated the error. The sync version of prepare returns only 1 error
-// code.
-status_t MediaPlayer2::prepare()
-{
-    ALOGV("prepare");
-    Mutex::Autolock _l(mLock);
-    mLockThreadId = getThreadId();
-    if (mPrepareSync) {
-        mLockThreadId = 0;
-        return -EALREADY;
-    }
-    mPrepareSync = true;
-    status_t ret = prepareAsync_l();
-    if (ret != NO_ERROR) {
-        mLockThreadId = 0;
-        return ret;
-    }
-
-    if (mPrepareSync) {
-        mSignal.wait(mLock);  // wait for prepare done
-        mPrepareSync = false;
-    }
-    ALOGV("prepare complete - status=%d", mPrepareStatus);
-    mLockThreadId = 0;
-    return mPrepareStatus;
-}
-
-status_t MediaPlayer2::prepareAsync()
-{
-    ALOGV("prepareAsync");
-    Mutex::Autolock _l(mLock);
-    return prepareAsync_l();
-}
-
-status_t MediaPlayer2::start()
-{
+status_t MediaPlayer2::start() {
     ALOGV("start");
 
     status_t ret = NO_ERROR;
@@ -306,8 +779,14 @@
     } else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_PREPARED |
                     MEDIA_PLAYER2_PLAYBACK_COMPLETE | MEDIA_PLAYER2_PAUSED ) ) ) {
         mPlayer->setLooping(mLoop);
-        mPlayer->setVolume(mLeftVolume, mRightVolume);
-        mPlayer->setAuxEffectSendLevel(mSendLevel);
+
+        if (mAudioOutput != 0) {
+            mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+        }
+
+        if (mAudioOutput != 0) {
+            mAudioOutput->setAuxEffectSendLevel(mSendLevel);
+        }
         mCurrentState = MEDIA_PLAYER2_STARTED;
         ret = mPlayer->start();
         if (ret != NO_ERROR) {
@@ -327,8 +806,7 @@
     return ret;
 }
 
-status_t MediaPlayer2::stop()
-{
+status_t MediaPlayer2::stop() {
     ALOGV("stop");
     Mutex::Autolock _l(mLock);
     if (mCurrentState & MEDIA_PLAYER2_STOPPED) return NO_ERROR;
@@ -346,8 +824,7 @@
     return INVALID_OPERATION;
 }
 
-status_t MediaPlayer2::pause()
-{
+status_t MediaPlayer2::pause() {
     ALOGV("pause");
     Mutex::Autolock _l(mLock);
     if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
@@ -365,12 +842,10 @@
     return INVALID_OPERATION;
 }
 
-bool MediaPlayer2::isPlaying()
-{
+bool MediaPlayer2::isPlaying() {
     Mutex::Autolock _l(mLock);
     if (mPlayer != 0) {
-        bool temp = false;
-        mPlayer->isPlaying(&temp);
+        bool temp = mPlayer->isPlaying();
         ALOGV("isPlaying: %d", temp);
         if ((mCurrentState & MEDIA_PLAYER2_STARTED) && ! temp) {
             ALOGE("internal/external state mismatch corrected");
@@ -385,13 +860,12 @@
     return false;
 }
 
-status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate)
-{
+status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate) {
     ALOGV("setPlaybackSettings: %f %f %d %d",
             rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
     // Negative speed and pitch does not make sense. Further validation will
     // be done by the respective mediaplayers.
-    if (rate.mSpeed < 0.f || rate.mPitch < 0.f) {
+    if (rate.mSpeed <= 0.f || rate.mPitch < 0.f) {
         return BAD_VALUE;
     }
     Mutex::Autolock _l(mLock);
@@ -399,36 +873,27 @@
         return INVALID_OPERATION;
     }
 
-    if (rate.mSpeed != 0.f && !(mCurrentState & MEDIA_PLAYER2_STARTED)
-            && (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED
-                    | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
-        mPlayer->setLooping(mLoop);
-        mPlayer->setVolume(mLeftVolume, mRightVolume);
-        mPlayer->setAuxEffectSendLevel(mSendLevel);
-    }
-
     status_t err = mPlayer->setPlaybackSettings(rate);
-    if (err == OK) {
-        if (rate.mSpeed == 0.f && mCurrentState == MEDIA_PLAYER2_STARTED) {
-            mCurrentState = MEDIA_PLAYER2_PAUSED;
-        } else if (rate.mSpeed != 0.f
-                && (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED
-                    | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
-            mCurrentState = MEDIA_PLAYER2_STARTED;
-        }
-    }
     return err;
 }
 
-status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
-{
+status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return INVALID_OPERATION;
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
+    }
     return mPlayer->getPlaybackSettings(rate);
+    status_t ret = mPlayer->getPlaybackSettings(rate);
+    if (ret == NO_ERROR) {
+        ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
+                rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
+    } else {
+        ALOGV("getPlaybackSettings returned %d", ret);
+    }
+    return ret;
 }
 
-status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint)
-{
+status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) {
     ALOGV("setSyncSettings: %u %u %f %f",
             sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
     Mutex::Autolock _l(mLock);
@@ -437,124 +902,128 @@
 }
 
 status_t MediaPlayer2::getSyncSettings(
-        AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
-{
+        AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
     Mutex::Autolock _l(mLock);
     if (mPlayer == 0) return INVALID_OPERATION;
-    return mPlayer->getSyncSettings(sync, videoFps);
+    status_t ret = mPlayer->getSyncSettings(sync, videoFps);
+    if (ret == NO_ERROR) {
+        ALOGV("getSyncSettings(%u, %u, %f, %f)",
+                sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
+    } else {
+        ALOGV("getSyncSettings returned %d", ret);
+    }
+    return ret;
+
 }
 
-status_t MediaPlayer2::getVideoWidth(int *w)
-{
+status_t MediaPlayer2::getVideoWidth(int *w) {
     ALOGV("getVideoWidth");
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return INVALID_OPERATION;
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
+    }
     *w = mVideoWidth;
     return NO_ERROR;
 }
 
-status_t MediaPlayer2::getVideoHeight(int *h)
-{
+status_t MediaPlayer2::getVideoHeight(int *h) {
     ALOGV("getVideoHeight");
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0) return INVALID_OPERATION;
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
+    }
     *h = mVideoHeight;
     return NO_ERROR;
 }
 
-status_t MediaPlayer2::getCurrentPosition(int *msec)
-{
+status_t MediaPlayer2::getCurrentPosition(int64_t *msec) {
     ALOGV("getCurrentPosition");
     Mutex::Autolock _l(mLock);
-    if (mPlayer != 0) {
-        if (mCurrentPosition >= 0) {
-            ALOGV("Using cached seek position: %d", mCurrentPosition);
-            *msec = mCurrentPosition;
-            return NO_ERROR;
-        }
-        return mPlayer->getCurrentPosition(msec);
+    if (mPlayer == 0) {
+        return INVALID_OPERATION;
     }
-    return INVALID_OPERATION;
+    if (mCurrentPosition >= 0) {
+        ALOGV("Using cached seek position: %lld", (long long)mCurrentPosition);
+        *msec = mCurrentPosition;
+        return NO_ERROR;
+    }
+    status_t ret = mPlayer->getCurrentPosition(msec);
+    if (ret == NO_ERROR) {
+        ALOGV("getCurrentPosition = %lld", (long long)*msec);
+    } else {
+        ALOGE("getCurrentPosition returned %d", ret);
+    }
+    return ret;
 }
 
-status_t MediaPlayer2::getDuration_l(int *msec)
-{
+status_t MediaPlayer2::getDuration(int64_t *msec) {
+    Mutex::Autolock _l(mLock);
     ALOGV("getDuration_l");
     bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
             MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_STOPPED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
-    if (mPlayer != 0 && isValidState) {
-        int durationMs;
-        status_t ret = mPlayer->getDuration(&durationMs);
-
-        if (ret != OK) {
-            // Do not enter error state just because no duration was available.
-            durationMs = -1;
-            ret = OK;
-        }
-
-        if (msec) {
-            *msec = durationMs;
-        }
-        return ret;
+    if (mPlayer == 0 || !isValidState) {
+        ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
+                mPlayer.get(), mCurrentState);
+        return INVALID_OPERATION;
     }
-    ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
-            mPlayer.get(), mCurrentState);
-    return INVALID_OPERATION;
-}
+    int64_t durationMs;
+    status_t ret = mPlayer->getDuration(&durationMs);
 
-status_t MediaPlayer2::getDuration(int *msec)
-{
-    Mutex::Autolock _l(mLock);
-    return getDuration_l(msec);
-}
-
-status_t MediaPlayer2::seekTo_l(int msec, MediaPlayer2SeekMode mode)
-{
-    ALOGV("seekTo (%d, %d)", msec, mode);
-    if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
-            MEDIA_PLAYER2_PAUSED |  MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) ) {
-        if ( msec < 0 ) {
-            ALOGW("Attempt to seek to invalid position: %d", msec);
-            msec = 0;
-        }
-
-        int durationMs;
-        status_t err = mPlayer->getDuration(&durationMs);
-
-        if (err != OK) {
-            ALOGW("Stream has no duration and is therefore not seekable.");
-            return err;
-        }
-
-        if (msec > durationMs) {
-            ALOGW("Attempt to seek to past end of file: request = %d, "
-                  "durationMs = %d",
-                  msec,
-                  durationMs);
-
-            msec = durationMs;
-        }
-
-        // cache duration
-        mCurrentPosition = msec;
-        mCurrentSeekMode = mode;
-        if (mSeekPosition < 0) {
-            mSeekPosition = msec;
-            mSeekMode = mode;
-            return mPlayer->seekTo(msec, mode);
-        }
-        else {
-            ALOGV("Seek in progress - queue up seekTo[%d, %d]", msec, mode);
-            return NO_ERROR;
-        }
+    if (ret == NO_ERROR) {
+        ALOGV("getDuration = %lld", (long long)durationMs);
+    } else {
+        ALOGE("getDuration returned %d", ret);
+        // Do not enter error state just because no duration was available.
+        durationMs = -1;
     }
-    ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(),
-            mCurrentState);
-    return INVALID_OPERATION;
+
+    if (msec) {
+        *msec = durationMs;
+    }
+    return OK;
 }
 
-status_t MediaPlayer2::seekTo(int msec, MediaPlayer2SeekMode mode)
-{
+status_t MediaPlayer2::seekTo_l(int64_t msec, MediaPlayer2SeekMode mode) {
+    ALOGV("seekTo (%lld, %d)", (long long)msec, mode);
+    if ((mPlayer == 0) || !(mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
+            MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
+        ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u",
+              mPlayer.get(), mCurrentState);
+        return INVALID_OPERATION;
+    }
+    if (msec < 0) {
+        ALOGW("Attempt to seek to invalid position: %lld", (long long)msec);
+        msec = 0;
+    }
+
+    int64_t durationMs;
+    status_t err = mPlayer->getDuration(&durationMs);
+
+    if (err != OK) {
+        ALOGW("Stream has no duration and is therefore not seekable.");
+        return err;
+    }
+
+    if (msec > durationMs) {
+        ALOGW("Attempt to seek to past end of file: request = %lld, durationMs = %lld",
+              (long long)msec, (long long)durationMs);
+
+        msec = durationMs;
+    }
+
+    // cache duration
+    mCurrentPosition = msec;
+    mCurrentSeekMode = mode;
+    if (mSeekPosition < 0) {
+        mSeekPosition = msec;
+        mSeekMode = mode;
+        return mPlayer->seekTo(msec, mode);
+    }
+    ALOGV("Seek in progress - queue up seekTo[%lld, %d]", (long long)msec, mode);
+    return NO_ERROR;
+}
+
+status_t MediaPlayer2::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
     mLockThreadId = getThreadId();
     Mutex::Autolock _l(mLock);
     status_t result = seekTo_l(msec, mode);
@@ -563,27 +1032,27 @@
     return result;
 }
 
-status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs)
-{
+status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs) {
     Mutex::Autolock _l(mLock);
     if (mPlayer != 0) {
-        return mPlayer->notifyAt(mediaTimeUs);
+        return INVALID_OPERATION;
     }
-    return INVALID_OPERATION;
+
+    return mPlayer->notifyAt(mediaTimeUs);
 }
 
-status_t MediaPlayer2::reset_l()
-{
+status_t MediaPlayer2::reset_l() {
     mLoop = false;
-    if (mCurrentState == MEDIA_PLAYER2_IDLE) return NO_ERROR;
-    mPrepareSync = false;
+    if (mCurrentState == MEDIA_PLAYER2_IDLE) {
+        return NO_ERROR;
+    }
     if (mPlayer != 0) {
         status_t ret = mPlayer->reset();
         if (ret != NO_ERROR) {
             ALOGE("reset() failed with return code (%d)", ret);
             mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
         } else {
-            mPlayer->disconnect();
+            mPlayer->setListener(NULL);
             mCurrentState = MEDIA_PLAYER2_IDLE;
         }
         // setDataSource has to be called again to create a
@@ -595,8 +1064,7 @@
     return NO_ERROR;
 }
 
-status_t MediaPlayer2::reset()
-{
+status_t MediaPlayer2::reset() {
     ALOGV("reset");
     mLockThreadId = getThreadId();
     Mutex::Autolock _l(mLock);
@@ -606,8 +1074,7 @@
     return result;
 }
 
-status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type)
-{
+status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type) {
     ALOGV("MediaPlayer2::setAudioStreamType");
     Mutex::Autolock _l(mLock);
     if (mStreamType == type) return NO_ERROR;
@@ -622,16 +1089,14 @@
     return OK;
 }
 
-status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type)
-{
+status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type) {
     ALOGV("getAudioStreamType");
     Mutex::Autolock _l(mLock);
     *type = mStreamType;
     return OK;
 }
 
-status_t MediaPlayer2::setLooping(int loop)
-{
+status_t MediaPlayer2::setLooping(int loop) {
     ALOGV("MediaPlayer2::setLooping");
     Mutex::Autolock _l(mLock);
     mLoop = (loop != 0);
@@ -651,20 +1116,18 @@
     return false;
 }
 
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume)
-{
+status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
     ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
     Mutex::Autolock _l(mLock);
     mLeftVolume = leftVolume;
     mRightVolume = rightVolume;
-    if (mPlayer != 0) {
-        return mPlayer->setVolume(leftVolume, rightVolume);
+    if (mAudioOutput != 0) {
+        mAudioOutput->setVolume(leftVolume, rightVolume);
     }
     return OK;
 }
 
-status_t MediaPlayer2::setAudioSessionId(audio_session_t sessionId)
-{
+status_t MediaPlayer2::setAudioSessionId(audio_session_t sessionId) {
     ALOGV("MediaPlayer2::setAudioSessionId(%d)", sessionId);
     Mutex::Autolock _l(mLock);
     if (!(mCurrentState & MEDIA_PLAYER2_IDLE)) {
@@ -682,40 +1145,36 @@
     return NO_ERROR;
 }
 
-audio_session_t MediaPlayer2::getAudioSessionId()
-{
+audio_session_t MediaPlayer2::getAudioSessionId() {
     Mutex::Autolock _l(mLock);
     return mAudioSessionId;
 }
 
-status_t MediaPlayer2::setAuxEffectSendLevel(float level)
-{
+status_t MediaPlayer2::setAuxEffectSendLevel(float level) {
     ALOGV("MediaPlayer2::setAuxEffectSendLevel(%f)", level);
     Mutex::Autolock _l(mLock);
     mSendLevel = level;
-    if (mPlayer != 0) {
-        return mPlayer->setAuxEffectSendLevel(level);
+    if (mAudioOutput != 0) {
+        return mAudioOutput->setAuxEffectSendLevel(level);
     }
     return OK;
 }
 
-status_t MediaPlayer2::attachAuxEffect(int effectId)
-{
+status_t MediaPlayer2::attachAuxEffect(int effectId) {
     ALOGV("MediaPlayer2::attachAuxEffect(%d)", effectId);
     Mutex::Autolock _l(mLock);
-    if (mPlayer == 0 ||
+    if (mAudioOutput == 0 ||
         (mCurrentState & MEDIA_PLAYER2_IDLE) ||
         (mCurrentState == MEDIA_PLAYER2_STATE_ERROR )) {
         ALOGE("attachAuxEffect called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
         return INVALID_OPERATION;
     }
 
-    return mPlayer->attachAuxEffect(effectId);
+    return mAudioOutput->attachAuxEffect(effectId);
 }
 
 // always call with lock held
-status_t MediaPlayer2::checkStateForKeySet_l(int key)
-{
+status_t MediaPlayer2::checkStateForKeySet_l(int key) {
     switch(key) {
     case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
         if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
@@ -732,8 +1191,7 @@
     return OK;
 }
 
-status_t MediaPlayer2::setParameter(int key, const Parcel& request)
-{
+status_t MediaPlayer2::setParameter(int key, const Parcel& request) {
     ALOGV("MediaPlayer2::setParameter(%d)", key);
     status_t status = INVALID_OPERATION;
     Mutex::Autolock _l(mLock);
@@ -743,10 +1201,15 @@
     switch (key) {
     case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
         // save the marshalled audio attributes
-        if (mAudioAttributesParcel != NULL) { delete mAudioAttributesParcel; };
+        if (mAudioAttributesParcel != NULL) {
+            delete mAudioAttributesParcel;
+        }
         mAudioAttributesParcel = new Parcel();
         mAudioAttributesParcel->appendFrom(&request, 0, request.dataSize());
-        status = OK;
+        status = setAudioAttributes_l(request);
+        if (status != OK) {
+            return status;
+        }
         break;
     default:
         ALOGV_IF(mPlayer == NULL, "setParameter: no active player");
@@ -759,25 +1222,69 @@
     return status;
 }
 
-status_t MediaPlayer2::getParameter(int key, Parcel *reply)
-{
+status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
     ALOGV("MediaPlayer2::getParameter(%d)", key);
     Mutex::Autolock _l(mLock);
-    if (mPlayer != NULL) {
-        status_t status =  mPlayer->getParameter(key, reply);
-        if (status != OK) {
-            ALOGD("getParameter returns %d", status);
+    if (key == MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES) {
+        if (reply == NULL) {
+            return BAD_VALUE;
         }
-        return status;
+        if (mAudioAttributesParcel != NULL) {
+            reply->appendFrom(mAudioAttributesParcel, 0, mAudioAttributesParcel->dataSize());
+        }
+        return OK;
     }
-    ALOGV("getParameter: no active player");
-    return INVALID_OPERATION;
+
+    if (mPlayer == NULL) {
+        ALOGV("getParameter: no active player");
+        return INVALID_OPERATION;
+    }
+
+    status_t status =  mPlayer->getParameter(key, reply);
+    if (status != OK) {
+        ALOGD("getParameter returns %d", status);
+    }
+    return status;
 }
 
-void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
-{
+bool MediaPlayer2::shouldDropMetadata(media::Metadata::Type code) const {
+    Mutex::Autolock lock(mLock);
+
+    if (findMetadata(mMetadataDrop, code)) {
+        return true;
+    }
+
+    if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+
+void MediaPlayer2::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
+    Mutex::Autolock lock(mLock);
+    if (mMetadataUpdated.indexOf(metadata_type) < 0) {
+        mMetadataUpdated.add(metadata_type);
+    }
+}
+
+void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) {
     ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
           (long long)srcId, msg, ext1, ext2);
+
+    if (MEDIA2_INFO == msg && MEDIA2_INFO_METADATA_UPDATE == ext1) {
+        const media::Metadata::Type metadata_type = ext2;
+
+        if(shouldDropMetadata(metadata_type)) {
+            return;
+        }
+
+        // Update the list of metadata that have changed. getMetadata
+        // also access mMetadataUpdated and clears it.
+        addNewMetadataUpdate(metadata_type);
+    }
+
     bool send = true;
     bool locked = false;
 
@@ -808,12 +1315,6 @@
     case MEDIA2_PREPARED:
         ALOGV("MediaPlayer2::notify() prepared");
         mCurrentState = MEDIA_PLAYER2_PREPARED;
-        if (mPrepareSync) {
-            ALOGV("signal application thread");
-            mPrepareSync = false;
-            mPrepareStatus = NO_ERROR;
-            mSignal.signal();
-        }
         break;
     case MEDIA2_DRM_INFO:
         ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
@@ -834,14 +1335,6 @@
         // ext2: Implementation dependant error code.
         ALOGE("error (%d, %d)", ext1, ext2);
         mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
-        if (mPrepareSync)
-        {
-            ALOGV("signal application thread");
-            mPrepareSync = false;
-            mPrepareStatus = ext1;
-            mSignal.signal();
-            send = false;
-        }
         break;
     case MEDIA2_INFO:
         // ext1: Media framework error code.
@@ -853,7 +1346,8 @@
     case MEDIA2_SEEK_COMPLETE:
         ALOGV("Received seek complete");
         if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
-            ALOGV("Executing queued seekTo(%d, %d)", mCurrentPosition, mCurrentSeekMode);
+            ALOGV("Executing queued seekTo(%lld, %d)",
+                  (long long)mCurrentPosition, mCurrentSeekMode);
             mSeekPosition = -1;
             mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
             seekTo_l(mCurrentPosition, mCurrentSeekMode);
@@ -901,24 +1395,8 @@
     }
 }
 
-status_t MediaPlayer2::setNextMediaPlayer(const sp<MediaPlayer2>& next) {
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        return NO_INIT;
-    }
-
-    if (next != NULL && !(next->mCurrentState &
-            (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
-        ALOGE("next player is not prepared");
-        return INVALID_OPERATION;
-    }
-
-    return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
-}
-
 // Modular DRM
-status_t MediaPlayer2::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId)
-{
+status_t MediaPlayer2::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
     // TODO change to ALOGV
     ALOGD("prepareDrm: uuid: %p  drmSessionId: %p(%zu)", uuid,
             drmSessionId.array(), drmSessionId.size());
@@ -951,8 +1429,7 @@
     return status;
 }
 
-status_t MediaPlayer2::releaseDrm()
-{
+status_t MediaPlayer2::releaseDrm() {
     Mutex::Autolock _l(mLock);
     if (mPlayer == NULL) {
         return NO_INIT;
@@ -980,39 +1457,74 @@
     return status;
 }
 
-status_t MediaPlayer2::setOutputDevice(audio_port_handle_t deviceId)
-{
+status_t MediaPlayer2::setOutputDevice(audio_port_handle_t deviceId) {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        ALOGV("setOutputDevice: player not init");
+    if (mAudioOutput == NULL) {
+        ALOGV("setOutputDevice: audio sink not init");
         return NO_INIT;
     }
-    return mPlayer->setOutputDevice(deviceId);
+    return mAudioOutput->setOutputDevice(deviceId);
 }
 
-audio_port_handle_t MediaPlayer2::getRoutedDeviceId()
-{
+audio_port_handle_t MediaPlayer2::getRoutedDeviceId() {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
-        ALOGV("getRoutedDeviceId: player not init");
+    if (mAudioOutput == NULL) {
+        ALOGV("getRoutedDeviceId: audio sink not init");
         return AUDIO_PORT_HANDLE_NONE;
     }
     audio_port_handle_t deviceId;
-    status_t status = mPlayer->getRoutedDeviceId(&deviceId);
+    status_t status = mAudioOutput->getRoutedDeviceId(&deviceId);
     if (status != NO_ERROR) {
         return AUDIO_PORT_HANDLE_NONE;
     }
     return deviceId;
 }
 
-status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled)
-{
+status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled) {
     Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL) {
+    if (mAudioOutput == NULL) {
         ALOGV("addAudioDeviceCallback: player not init");
         return NO_INIT;
     }
-    return mPlayer->enableAudioDeviceCallback(enabled);
+    return mAudioOutput->enableAudioDeviceCallback(enabled);
+}
+
+status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    result.append(" MediaPlayer2\n");
+    snprintf(buffer, 255, "  pid(%d), looping(%s)\n", mPid, mLoop?"true": "false");
+    result.append(buffer);
+
+    sp<MediaPlayer2Interface> player;
+    sp<MediaPlayer2AudioOutput> audioOutput;
+    bool locked = false;
+    for (int i = 0; i < kDumpLockRetries; ++i) {
+        if (mLock.tryLock() == NO_ERROR) {
+            locked = true;
+            break;
+        }
+        usleep(kDumpLockSleepUs);
+    }
+
+    if (locked) {
+        player = mPlayer;
+        audioOutput = mAudioOutput;
+        mLock.unlock();
+    } else {
+        result.append("  lock is taken, no dump from player and audio output\n");
+    }
+    write(fd, result.string(), result.size());
+
+    if (player != NULL) {
+        player->dump(fd, args);
+    }
+    if (audioOutput != 0) {
+        audioOutput->dump(fd, args);
+    }
+    write(fd, "\n", 1);
+    return NO_ERROR;
 }
 
 } // namespace android
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 4700660..c34aabb 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -1149,7 +1149,7 @@
 }
 
 sp<ABuffer> NuPlayer2::GenericSource2::mediaBufferToABuffer(
-        MediaBuffer* mb,
+        MediaBufferBase* mb,
         media_track_type trackType) {
     bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
     size_t outLength = mb->range_length();
@@ -1333,7 +1333,7 @@
 
     int32_t generation = getDataGeneration(trackType);
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
-        Vector<MediaBuffer *> mediaBuffers;
+        Vector<MediaBufferBase *> mediaBuffers;
         status_t err = NO_ERROR;
 
         sp<IMediaSource> source = track->mSource;
@@ -1342,7 +1342,7 @@
             err = source->readMultiple(
                     &mediaBuffers, maxBuffers - numBuffers, &options);
         } else {
-            MediaBuffer *mbuf = NULL;
+            MediaBufferBase *mbuf = NULL;
             err = source->read(&mbuf, &options);
             if (err == OK && mbuf != NULL) {
                 mediaBuffers.push_back(mbuf);
@@ -1365,7 +1365,7 @@
 
         for (; id < count; ++id) {
             int64_t timeUs;
-            MediaBuffer *mbuf = mediaBuffers[id];
+            MediaBufferBase *mbuf = mediaBuffers[id];
             if (!mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mbuf->meta_data()->dumpToLog();
                 track->mPackets->signalEOS(ERROR_MALFORMED);
@@ -1659,7 +1659,7 @@
     return OK;
 }
 
-void NuPlayer2::GenericSource2::signalBufferReturned(MediaBuffer *buffer)
+void NuPlayer2::GenericSource2::signalBufferReturned(MediaBufferBase *buffer)
 {
     //ALOGV("signalBufferReturned %p  refCount: %d", buffer, buffer->localRefcount());
 
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.h b/media/libmediaplayer2/nuplayer2/GenericSource2.h
index 1a5409a..896c397 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.h
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.h
@@ -86,7 +86,7 @@
     virtual bool isStreaming() const;
 
     // Modular DRM
-    virtual void signalBufferReturned(MediaBuffer *buffer);
+    virtual void signalBufferReturned(MediaBufferBase *buffer);
 
     virtual status_t prepareDrm(
             const uint8_t uuid[16],
@@ -202,7 +202,7 @@
             int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
 
     sp<ABuffer> mediaBufferToABuffer(
-            MediaBuffer *mbuf,
+            MediaBufferBase *mbuf,
             media_track_type trackType);
 
     void postReadBuffer(media_track_type trackType);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index c414f23..5971a8b 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -423,6 +423,14 @@
     msg->post();
 }
 
+void NuPlayer2::playNextDataSource(int64_t srcId) {
+    disconnectSource();
+
+    sp<AMessage> msg = new AMessage(kWhatPlayNextDataSource, this);
+    msg->setInt64("srcId", srcId);
+    msg->post();
+}
+
 status_t NuPlayer2::getBufferingSettings(
         BufferingSettings *buffering /* nonnull */) {
     sp<AMessage> msg = new AMessage(kWhatGetBufferingSettings, this);
@@ -538,6 +546,11 @@
 }
 
 void NuPlayer2::resetAsync() {
+    disconnectSource();
+    (new AMessage(kWhatReset, this))->post();
+}
+
+void NuPlayer2::disconnectSource() {
     sp<Source> source;
     {
         Mutex::Autolock autoLock(mSourceLock);
@@ -554,7 +567,6 @@
         source->disconnect();
     }
 
-    (new AMessage(kWhatReset, this))->post();
 }
 
 status_t NuPlayer2::notifyAt(int64_t mediaTimeUs) {
@@ -641,6 +653,7 @@
                 mSource = static_cast<Source *>(obj.get());
             } else {
                 err = UNKNOWN_ERROR;
+                ALOGE("kWhatSetDataSource, source should not be NULL");
             }
 
             CHECK(mDriver != NULL);
@@ -670,6 +683,32 @@
             break;
         }
 
+        case kWhatPlayNextDataSource:
+        {
+            ALOGV("kWhatPlayNextDataSource");
+            int64_t srcId;
+            CHECK(msg->findInt64("srcId", &srcId));
+            if (srcId != mNextSrcId) {
+                notifyListener(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, 0);
+                return;
+            }
+
+            mResetting = true;
+            stopPlaybackTimer("kWhatPlayNextDataSource");
+            stopRebufferingTimer(true);
+
+            mDeferredActions.push_back(
+                    new FlushDecoderAction(
+                        FLUSH_CMD_SHUTDOWN /* audio */,
+                        FLUSH_CMD_SHUTDOWN /* video */));
+
+            mDeferredActions.push_back(
+                    new SimpleAction(&NuPlayer2::performPlayNextDataSource));
+
+            processDeferredActions();
+            break;
+        }
+
         case kWhatGetBufferingSettings:
         {
             sp<AReplyToken> replyID;
@@ -1381,7 +1420,7 @@
                 handleFlushComplete(audio, false /* isDecoder */);
                 finishFlushIfPossible();
             } else if (what == Renderer::kWhatVideoRenderingStart) {
-                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_RENDERING_START, 0);
+                notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_VIDEO_RENDERING_START, 0);
             } else if (what == Renderer::kWhatMediaRenderingStart) {
                 ALOGV("media rendering started");
                 notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
@@ -1453,26 +1492,24 @@
             ALOGV("kWhatSeek seekTimeUs=%lld us, mode=%d, needNotify=%d",
                     (long long)seekTimeUs, mode, needNotify);
 
-            // seeks can take a while, so we essentially paused
-            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
-
             if (!mStarted) {
-                // Seek before the player is started. In order to preview video,
-                // need to start the player and pause it. This branch is called
-                // only once if needed. After the player is started, any seek
-                // operation will go through normal path.
-                // Audio-only cases are handled separately.
-                onStart(seekTimeUs, (MediaPlayer2SeekMode)mode);
-                if (mStarted) {
-                    onPause();
-                    mPausedByClient = true;
+                if (!mSourceStarted) {
+                    mSourceStarted = true;
+                    mSource->start();
                 }
+                if (seekTimeUs > 0) {
+                    performSeek(seekTimeUs, (MediaPlayer2SeekMode)mode);
+                }
+
                 if (needNotify) {
                     notifyDriverSeekComplete(mSrcId);
                 }
                 break;
             }
 
+            // seeks can take a while, so we essentially paused
+            notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
+
             mDeferredActions.push_back(
                     new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */,
                                            FLUSH_CMD_FLUSH /* video */));
@@ -1565,19 +1602,13 @@
     startPlaybackTimer("onresume");
 }
 
-void NuPlayer2::onStart(int64_t startPositionUs, MediaPlayer2SeekMode mode) {
+void NuPlayer2::onStart() {
     ALOGV("onStart: mCrypto: %p", mCrypto.get());
 
     if (!mSourceStarted) {
         mSourceStarted = true;
         mSource->start();
     }
-    if (startPositionUs > 0) {
-        performSeek(startPositionUs, mode);
-        if (mSource->getFormat(false /* audio */) == NULL) {
-            return;
-        }
-    }
 
     mOffloadAudio = false;
     mAudioEOS = false;
@@ -2410,6 +2441,67 @@
     mIsDrmProtected = false;
 }
 
+void NuPlayer2::performPlayNextDataSource() {
+    ALOGV("performPlayNextDataSource");
+
+    CHECK(mAudioDecoder == NULL);
+    CHECK(mVideoDecoder == NULL);
+
+    stopPlaybackTimer("performPlayNextDataSource");
+    stopRebufferingTimer(true);
+
+    cancelPollDuration();
+
+    ++mScanSourcesGeneration;
+    mScanSourcesPending = false;
+
+    ++mRendererGeneration;
+
+    if (mSource != NULL) {
+        mSource->stop();
+    }
+
+    long previousSrcId;
+    {
+        Mutex::Autolock autoLock(mSourceLock);
+        mSource = mNextSource;
+        mNextSource = NULL;
+        previousSrcId = mSrcId;
+        mSrcId = mNextSrcId;
+        ++mNextSrcId;  // to distinguish the two sources.
+    }
+
+    if (mDriver != NULL) {
+        sp<NuPlayer2Driver> driver = mDriver.promote();
+        if (driver != NULL) {
+            notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAYBACK_COMPLETE, 0);
+            notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0);
+        }
+    }
+
+    mStarted = false;
+    mPrepared = true;  // TODO: what if it's not prepared
+    mResetting = false;
+    mSourceStarted = false;
+
+    // Modular DRM
+    if (mCrypto != NULL) {
+        // decoders will be flushed before this so their mCrypto would go away on their own
+        // TODO change to ALOGV
+        ALOGD("performReset mCrypto: %p", mCrypto.get());
+        mCrypto.clear();
+    }
+    mIsDrmProtected = false;
+
+    if (mRenderer != NULL) {
+        mRenderer->resume();
+    }
+
+    onStart();
+    mPausedByClient = false;
+    notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
+}
+
 void NuPlayer2::performScanSources() {
     ALOGV("performScanSources");
 
@@ -2673,10 +2765,10 @@
                 break;
             }
 
-            int posMs;
+            int64_t posMs;
             int64_t timeUs, posUs;
             driver->getCurrentPosition(&posMs);
-            posUs = (int64_t) posMs * 1000ll;
+            posUs = posMs * 1000ll;
             CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
 
             if (posUs < timeUs) {
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index e884b92..96f85f9 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -44,6 +44,7 @@
 
     void setDataSourceAsync(const sp<DataSourceDesc> &dsd);
     void prepareNextDataSourceAsync(const sp<DataSourceDesc> &dsd);
+    void playNextDataSource(int64_t srcId);
 
     status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
     status_t setBufferingSettings(const BufferingSettings& buffering);
@@ -121,6 +122,7 @@
         kWhatSetDataSource              = '=DaS',
         kWhatPrepare                    = 'prep',
         kWhatPrepareNextDataSource      = 'pNDS',
+        kWhatPlayNextDataSource         = 'plNS',
         kWhatSetVideoSurface            = '=VSu',
         kWhatSetAudioSink               = '=AuS',
         kWhatMoreDataQueued             = 'more',
@@ -269,6 +271,8 @@
         mFlushComplete[1][1] = false;
     }
 
+    void disconnectSource();
+
     status_t createNuPlayer2Source(const sp<DataSourceDesc> &dsd,
                                    sp<Source> *source,
                                    DATA_SOURCE_TYPE *dataSourceType);
@@ -293,9 +297,7 @@
     void handleFlushComplete(bool audio, bool isDecoder);
     void finishFlushIfPossible();
 
-    void onStart(
-            int64_t startPositionUs = -1,
-            MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
+    void onStart();
     void onResume();
     void onPause();
 
@@ -316,6 +318,7 @@
     void performSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode);
     void performDecoderFlush(FlushCommand audio, FlushCommand video);
     void performReset();
+    void performPlayNextDataSource();
     void performScanSources();
     void performSetSurface(const sp<ANativeWindowWrapper> &nw);
     void performResumeDecoders(bool needNotify);
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
index a436592..c49bccb 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
@@ -1066,7 +1066,7 @@
         }
 
         // Modular DRM
-        MediaBuffer *mediaBuf = NULL;
+        MediaBufferBase *mediaBuf = NULL;
         sp<AMediaCodecCryptoInfoWrapper> cryptInfo;
 
         // copy into codec buffer
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 60a07a3..03d17a5 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -107,7 +107,6 @@
 
 NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid)
     : mState(STATE_IDLE),
-      mIsAsyncPrepare(false),
       mAsyncResult(UNKNOWN_ERROR),
       mSrcId(0),
       mSetSurfaceInProgress(false),
@@ -174,7 +173,7 @@
 }
 
 status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
-    ALOGV("setDataSource(%p) callback source", this);
+    ALOGV("setDataSource(%p)", this);
     Mutex::Autolock autoLock(mLock);
 
     if (mState != STATE_IDLE) {
@@ -193,6 +192,25 @@
     return mAsyncResult;
 }
 
+status_t NuPlayer2Driver::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
+    ALOGV("prepareNextDataSource(%p)", this);
+    Mutex::Autolock autoLock(mLock);
+
+    mPlayer->prepareNextDataSourceAsync(dsd);
+
+    return OK;
+}
+
+status_t NuPlayer2Driver::playNextDataSource(int64_t srcId) {
+    ALOGV("playNextDataSource(%p)", this);
+    Mutex::Autolock autoLock(mLock);
+
+    mSrcId = srcId;
+    mPlayer->playNextDataSource(srcId);
+
+    return OK;
+}
+
 status_t NuPlayer2Driver::setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) {
     ALOGV("setVideoSurfaceTexture(%p)", this);
     Mutex::Autolock autoLock(mLock);
@@ -245,42 +263,6 @@
     return mPlayer->setBufferingSettings(buffering);
 }
 
-status_t NuPlayer2Driver::prepare() {
-    ALOGV("prepare(%p)", this);
-    Mutex::Autolock autoLock(mLock);
-    return prepare_l();
-}
-
-status_t NuPlayer2Driver::prepare_l() {
-    switch (mState) {
-        case STATE_UNPREPARED:
-            mState = STATE_PREPARING;
-
-            // Make sure we're not posting any notifications, success or
-            // failure information is only communicated through our result
-            // code.
-            mIsAsyncPrepare = false;
-            mPlayer->prepareAsync();
-            while (mState == STATE_PREPARING) {
-                mCondition.wait(mLock);
-            }
-            return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR;
-        case STATE_STOPPED:
-            // this is really just paused. handle as seek to start
-            mAtEOS = false;
-            mState = STATE_STOPPED_AND_PREPARING;
-            mIsAsyncPrepare = false;
-            mPlayer->seekToAsync(0, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
-                    true /* needNotify */);
-            while (mState == STATE_STOPPED_AND_PREPARING) {
-                mCondition.wait(mLock);
-            }
-            return (mState == STATE_STOPPED_AND_PREPARED) ? OK : UNKNOWN_ERROR;
-        default:
-            return INVALID_OPERATION;
-    };
-}
-
 status_t NuPlayer2Driver::prepareAsync() {
     ALOGV("prepareAsync(%p)", this);
     Mutex::Autolock autoLock(mLock);
@@ -288,14 +270,12 @@
     switch (mState) {
         case STATE_UNPREPARED:
             mState = STATE_PREPARING;
-            mIsAsyncPrepare = true;
             mPlayer->prepareAsync();
             return OK;
         case STATE_STOPPED:
             // this is really just paused. handle as seek to start
             mAtEOS = false;
             mState = STATE_STOPPED_AND_PREPARING;
-            mIsAsyncPrepare = true;
             mPlayer->seekToAsync(0, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */,
                     true /* needNotify */);
             return OK;
@@ -312,19 +292,6 @@
 
 status_t NuPlayer2Driver::start_l() {
     switch (mState) {
-        case STATE_UNPREPARED:
-        {
-            status_t err = prepare_l();
-
-            if (err != OK) {
-                return err;
-            }
-
-            CHECK_EQ(mState, STATE_PREPARED);
-
-            // fall through
-        }
-
         case STATE_PAUSED:
         case STATE_STOPPED_AND_PREPARED:
         case STATE_PREPARED:
@@ -387,7 +354,7 @@
     // down for audio offload mode. If that happens, the NuPlayerRenderer will no longer know the
     // current position. So similar to seekTo, update |mPositionUs| to the pause position by calling
     // getCurrentPosition here.
-    int unused;
+    int64_t unused;
     getCurrentPosition(&unused);
 
     Mutex::Autolock autoLock(mLock);
@@ -417,7 +384,7 @@
     status_t err = mPlayer->setPlaybackSettings(rate);
     if (err == OK) {
         // try to update position
-        int unused;
+        int64_t unused;
         getCurrentPosition(&unused);
         Mutex::Autolock autoLock(mLock);
         if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
@@ -444,8 +411,8 @@
     return mPlayer->getSyncSettings(sync, videoFps);
 }
 
-status_t NuPlayer2Driver::seekTo(int msec, MediaPlayer2SeekMode mode) {
-    ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
+status_t NuPlayer2Driver::seekTo(int64_t msec, MediaPlayer2SeekMode mode) {
+    ALOGD("seekTo(%p) (%lld ms, %d) at state %d", this, (long long)msec, mode, mState);
     Mutex::Autolock autoLock(mLock);
 
     int64_t seekTimeUs = msec * 1000ll;
@@ -470,13 +437,13 @@
     return OK;
 }
 
-status_t NuPlayer2Driver::getCurrentPosition(int *msec) {
+status_t NuPlayer2Driver::getCurrentPosition(int64_t *msec) {
     int64_t tempUs = 0;
     {
         Mutex::Autolock autoLock(mLock);
         if (mSeekInProgress || (mState == STATE_PAUSED && !mAtEOS)) {
             tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
-            *msec = (int)divRound(tempUs, (int64_t)(1000));
+            *msec = divRound(tempUs, (int64_t)(1000));
             return OK;
         }
     }
@@ -492,11 +459,11 @@
     } else {
         mPositionUs = tempUs;
     }
-    *msec = (int)divRound(tempUs, (int64_t)(1000));
+    *msec = divRound(tempUs, (int64_t)(1000));
     return OK;
 }
 
-status_t NuPlayer2Driver::getDuration(int *msec) {
+status_t NuPlayer2Driver::getDuration(int64_t *msec) {
     Mutex::Autolock autoLock(mLock);
 
     if (mDurationUs < 0) {
@@ -562,7 +529,7 @@
     // always provide duration and playing time, even if they have 0/unknown values.
 
     // getDuration() uses mLock for mutex -- careful where we use it.
-    int duration_ms = -1;
+    int64_t duration_ms = -1;
     getDuration(&duration_ms);
     mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
 
@@ -626,8 +593,6 @@
 
         case STATE_PREPARING:
         {
-            CHECK(mIsAsyncPrepare);
-
             notifyListener_l(mSrcId, MEDIA2_PREPARED);
             break;
         }
@@ -696,7 +661,7 @@
         case MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK:
         {
             int trackIndex = request.readInt32();
-            int msec = 0;
+            int64_t msec = 0;
             // getCurrentPosition should always return OK
             getCurrentPosition(&msec);
             return mPlayer->selectTrack(trackIndex, true /* select */, msec * 1000ll);
@@ -824,10 +789,6 @@
         wasSeeking = false;
         mState = STATE_STOPPED_AND_PREPARED;
         mCondition.broadcast();
-        if (!mIsAsyncPrepare) {
-            // if we are preparing synchronously, no need to notify listener
-            return;
-        }
     } else if (mState == STATE_STOPPED) {
         // no need to notify listener
         return;
@@ -947,58 +908,60 @@
     ALOGD("notifyListener_l(%p), (%lld, %d, %d, %d, %d), loop setting(%d, %d)",
             this, (long long)srcId, msg, ext1, ext2,
             (in == NULL ? -1 : (int)in->dataSize()), mAutoLoop, mLooping);
-    switch (msg) {
-        case MEDIA2_PLAYBACK_COMPLETE:
-        {
-            if (mState != STATE_RESET_IN_PROGRESS) {
-                if (mAutoLoop) {
-                    audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
-                    if (mAudioSink != NULL) {
-                        streamType = mAudioSink->getAudioStreamType();
+    if (srcId == mSrcId) {
+        switch (msg) {
+            case MEDIA2_PLAYBACK_COMPLETE:
+            {
+                if (mState != STATE_RESET_IN_PROGRESS) {
+                    if (mAutoLoop) {
+                        audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
+                        if (mAudioSink != NULL) {
+                            streamType = mAudioSink->getAudioStreamType();
+                        }
+                        if (streamType == AUDIO_STREAM_NOTIFICATION) {
+                            ALOGW("disabling auto-loop for notification");
+                            mAutoLoop = false;
+                        }
                     }
-                    if (streamType == AUDIO_STREAM_NOTIFICATION) {
-                        ALOGW("disabling auto-loop for notification");
-                        mAutoLoop = false;
+                    if (mLooping || mAutoLoop) {
+                        mPlayer->seekToAsync(0);
+                        if (mAudioSink != NULL) {
+                            // The renderer has stopped the sink at the end in order to play out
+                            // the last little bit of audio. In looping mode, we need to restart it.
+                            mAudioSink->start();
+                        }
+                        // don't send completion event when looping
+                        return;
                     }
-                }
-                if (mLooping || mAutoLoop) {
-                    mPlayer->seekToAsync(0);
-                    if (mAudioSink != NULL) {
-                        // The renderer has stopped the sink at the end in order to play out
-                        // the last little bit of audio. If we're looping, we need to restart it.
-                        mAudioSink->start();
+                    if (property_get_bool("persist.debug.sf.stats", false)) {
+                        Vector<String16> args;
+                        dump(-1, args);
                     }
-                    // don't send completion event when looping
-                    return;
+                    mPlayer->pause();
+                    mState = STATE_PAUSED;
                 }
-                if (property_get_bool("persist.debug.sf.stats", false)) {
-                    Vector<String16> args;
-                    dump(-1, args);
-                }
-                mPlayer->pause();
-                mState = STATE_PAUSED;
+                // fall through
             }
-            // fall through
-        }
 
-        case MEDIA2_ERROR:
-        {
-            // when we have an error, add it to the analytics for this playback.
-            // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
-            // [test against msg is due to fall through from previous switch value]
-            if (msg == MEDIA2_ERROR) {
-                mAnalyticsItem->setInt32(kPlayerError, ext1);
-                if (ext2 != 0) {
-                    mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
+            case MEDIA2_ERROR:
+            {
+                // when we have an error, add it to the analytics for this playback.
+                // ext1 is our primary 'error type' value. Only add ext2 when non-zero.
+                // [test against msg is due to fall through from previous switch value]
+                if (msg == MEDIA2_ERROR) {
+                    mAnalyticsItem->setInt32(kPlayerError, ext1);
+                    if (ext2 != 0) {
+                        mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
+                    }
+                    mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
                 }
-                mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
+                mAtEOS = true;
+                break;
             }
-            mAtEOS = true;
-            break;
-        }
 
-        default:
-            break;
+            default:
+                break;
+        }
     }
 
     sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
@@ -1025,6 +988,15 @@
 
     Mutex::Autolock autoLock(mLock);
 
+    if (srcId != mSrcId) {
+        if (err == OK) {
+            notifyListener_l(srcId, MEDIA2_PREPARED);
+        } else {
+            notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
+        }
+        return;
+    }
+
     if (mState != STATE_PREPARING) {
         // We were preparing asynchronously when the client called
         // reset(), we sent a premature "prepared" notification and
@@ -1041,14 +1013,10 @@
         // update state before notifying client, so that if client calls back into NuPlayer2Driver
         // in response, NuPlayer2Driver has the right state
         mState = STATE_PREPARED;
-        if (mIsAsyncPrepare) {
-            notifyListener_l(srcId, MEDIA2_PREPARED);
-        }
+        notifyListener_l(srcId, MEDIA2_PREPARED);
     } else {
         mState = STATE_UNPREPARED;
-        if (mIsAsyncPrepare) {
-            notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
-        }
+        notifyListener_l(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN, err);
     }
 
     sp<MetaData> meta = mPlayer->getFileMeta();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
index 4c57cfd..4da2566 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.h
@@ -28,17 +28,18 @@
 struct NuPlayer2Driver : public MediaPlayer2Interface {
     explicit NuPlayer2Driver(pid_t pid, uid_t uid);
 
-    virtual status_t initCheck();
+    virtual status_t initCheck() override;
 
     virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
+    virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) override;
+    virtual status_t playNextDataSource(int64_t srcId) override;
 
-    virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww);
+    virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww) override;
 
     virtual status_t getBufferingSettings(
             BufferingSettings* buffering /* nonnull */) override;
     virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
 
-    virtual status_t prepare();
     virtual status_t prepareAsync();
     virtual status_t start();
     virtual status_t stop();
@@ -49,9 +50,9 @@
     virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
     virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps);
     virtual status_t seekTo(
-            int msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
-    virtual status_t getCurrentPosition(int *msec);
-    virtual status_t getDuration(int *msec);
+            int64_t msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
+    virtual status_t getCurrentPosition(int64_t *msec);
+    virtual status_t getDuration(int64_t *msec);
     virtual status_t reset();
     virtual status_t notifyAt(int64_t mediaTimeUs) override;
     virtual status_t setLooping(int loop);
@@ -114,7 +115,6 @@
 
     State mState;
 
-    bool mIsAsyncPrepare;
     status_t mAsyncResult;
 
     // The following are protected through "mLock"
@@ -147,7 +147,6 @@
     void updateMetrics(const char *where);
     void logMetrics(const char *where);
 
-    status_t prepare_l();
     status_t start_l();
     void notifyListener_l(int64_t srcId, int msg, int ext1 = 0, int ext2 = 0,
                           const Parcel *in = NULL);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 511f46f..b0c82f2 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1143,7 +1143,7 @@
 }
 
 sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
-        MediaBuffer* mb,
+        MediaBufferBase* mb,
         media_track_type trackType) {
     bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO;
     size_t outLength = mb->range_length();
@@ -1326,7 +1326,7 @@
 
     int32_t generation = getDataGeneration(trackType);
     for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
-        Vector<MediaBuffer *> mediaBuffers;
+        Vector<MediaBufferBase *> mediaBuffers;
         status_t err = NO_ERROR;
 
         sp<IMediaSource> source = track->mSource;
@@ -1335,7 +1335,7 @@
             err = source->readMultiple(
                     &mediaBuffers, maxBuffers - numBuffers, &options);
         } else {
-            MediaBuffer *mbuf = NULL;
+            MediaBufferBase *mbuf = NULL;
             err = source->read(&mbuf, &options);
             if (err == OK && mbuf != NULL) {
                 mediaBuffers.push_back(mbuf);
@@ -1358,7 +1358,7 @@
 
         for (; id < count; ++id) {
             int64_t timeUs;
-            MediaBuffer *mbuf = mediaBuffers[id];
+            MediaBufferBase *mbuf = mediaBuffers[id];
             if (!mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
                 mbuf->meta_data()->dumpToLog();
                 track->mPackets->signalEOS(ERROR_MALFORMED);
@@ -1654,7 +1654,7 @@
     return OK;
 }
 
-void NuPlayer::GenericSource::signalBufferReturned(MediaBuffer *buffer)
+void NuPlayer::GenericSource::signalBufferReturned(MediaBufferBase *buffer)
 {
     //ALOGV("signalBufferReturned %p  refCount: %d", buffer, buffer->localRefcount());
 
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 2406665..065cac1 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -86,7 +86,7 @@
     virtual bool isStreaming() const;
 
     // Modular DRM
-    virtual void signalBufferReturned(MediaBuffer *buffer);
+    virtual void signalBufferReturned(MediaBufferBase *buffer);
 
     virtual status_t prepareDrm(
             const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *outCrypto);
@@ -201,7 +201,7 @@
             int32_t curGen, const sp<AnotherPacketSource>& packets, const sp<AMessage>& msg);
 
     sp<ABuffer> mediaBufferToABuffer(
-            MediaBuffer *mbuf,
+            MediaBufferBase *mbuf,
             media_track_type trackType);
 
     void postReadBuffer(media_track_type trackType);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1aca96c..88594d2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -1046,7 +1046,7 @@
         }
 
         // Modular DRM
-        MediaBuffer *mediaBuf = NULL;
+        MediaBufferBase *mediaBuf = NULL;
         NuPlayerDrm::CryptoInfo *cryptInfo = NULL;
 
         // copy into codec buffer
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 281af47..d64138e 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -294,7 +294,7 @@
     prctl(PR_SET_NAME, (unsigned long)"AACWriterThread", 0, 0, 0);
 
     while (!mDone && err == OK) {
-        MediaBuffer *buffer;
+        MediaBufferBase *buffer;
         err = mSource->read(&buffer);
 
         if (err != OK) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 541093a..b296622 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -6349,90 +6349,54 @@
     Vector<AString> matchingCodecs;
     Vector<AString> owners;
 
-    AString mime;
-
     AString componentName;
-    int32_t encoder = false;
-    if (msg->findString("componentName", &componentName)) {
-        sp<IMediaCodecList> list = MediaCodecList::getInstance();
-        if (list == nullptr) {
-            ALOGE("Unable to obtain MediaCodecList while "
-                    "attempting to create codec \"%s\"",
-                    componentName.c_str());
-            mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
-            return false;
-        }
-        ssize_t index = list->findCodecByName(componentName.c_str());
-        if (index < 0) {
-            ALOGE("Unable to find codec \"%s\"",
-                    componentName.c_str());
-            mCodec->signalError(OMX_ErrorInvalidComponent, NAME_NOT_FOUND);
-            return false;
-        }
-        sp<MediaCodecInfo> info = list->getCodecInfo(index);
-        if (info == nullptr) {
-            ALOGE("Unexpected error (index out-of-bound) while "
-                    "retrieving information for codec \"%s\"",
-                    componentName.c_str());
-            mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
-            return false;
-        }
-        matchingCodecs.add(info->getCodecName());
-        owners.add(info->getOwnerName() == nullptr ?
-                "default" : info->getOwnerName());
-    } else {
-        CHECK(msg->findString("mime", &mime));
+    CHECK(msg->findString("componentName", &componentName));
 
-        if (!msg->findInt32("encoder", &encoder)) {
-            encoder = false;
-        }
-
-        MediaCodecList::findMatchingCodecs(
-                mime.c_str(),
-                encoder, // createEncoder
-                0,       // flags
-                &matchingCodecs,
-                &owners);
+    sp<IMediaCodecList> list = MediaCodecList::getInstance();
+    if (list == nullptr) {
+        ALOGE("Unable to obtain MediaCodecList while "
+                "attempting to create codec \"%s\"",
+                componentName.c_str());
+        mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
+        return false;
     }
+    ssize_t index = list->findCodecByName(componentName.c_str());
+    if (index < 0) {
+        ALOGE("Unable to find codec \"%s\"",
+                componentName.c_str());
+        mCodec->signalError(OMX_ErrorInvalidComponent, NAME_NOT_FOUND);
+        return false;
+    }
+    sp<MediaCodecInfo> info = list->getCodecInfo(index);
+    if (info == nullptr) {
+        ALOGE("Unexpected error (index out-of-bound) while "
+                "retrieving information for codec \"%s\"",
+                componentName.c_str());
+        mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
+        return false;
+    }
+    AString owner = (info->getOwnerName() == nullptr) ? "default" : info->getOwnerName();
 
     sp<CodecObserver> observer = new CodecObserver;
     sp<IOMX> omx;
     sp<IOMXNode> omxNode;
 
     status_t err = NAME_NOT_FOUND;
-    for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
-            ++matchIndex) {
-        componentName = matchingCodecs[matchIndex];
-
-        OMXClient client;
-        if (client.connect(owners[matchIndex].c_str()) != OK) {
-            mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
-            return false;
-        }
-        omx = client.interface();
-
-        pid_t tid = gettid();
-        int prevPriority = androidGetThreadPriority(tid);
-        androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
-        err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
-        androidSetThreadPriority(tid, prevPriority);
-
-        if (err == OK) {
-            break;
-        } else {
-            ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str());
-        }
-
-        omxNode = NULL;
+    OMXClient client;
+    if (client.connect(owner.c_str()) != OK) {
+        mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
+        return false;
     }
+    omx = client.interface();
 
-    if (omxNode == NULL) {
-        if (!mime.empty()) {
-            ALOGE("Unable to instantiate a %scoder for type '%s' with err %#x.",
-                    encoder ? "en" : "de", mime.c_str(), err);
-        } else {
-            ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);
-        }
+    pid_t tid = gettid();
+    int prevPriority = androidGetThreadPriority(tid);
+    androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
+    err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
+    androidSetThreadPriority(tid, prevPriority);
+
+    if (err != OK) {
+        ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);
 
         mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));
         return false;
@@ -7289,12 +7253,16 @@
         }
     }
 
-    float rate;
-    if (params->findFloat("operating-rate", &rate) && rate > 0) {
-        status_t err = setOperatingRate(rate, mIsVideo);
+    int32_t rateInt = -1;
+    float rateFloat = -1;
+    if (!params->findFloat("operating-rate", &rateFloat)) {
+        params->findInt32("operating-rate", &rateInt);
+        rateFloat = (float) rateInt; // 16MHz (FLINTMAX) is OK for upper bound.
+    }
+    if (rateFloat > 0) {
+        status_t err = setOperatingRate(rateFloat, mIsVideo);
         if (err != OK) {
-            ALOGE("Failed to set parameter 'operating-rate' (err %d)", err);
-            return err;
+            ALOGI("Failed to set parameter 'operating-rate' (err %d)", err);
         }
     }
 
@@ -7319,10 +7287,8 @@
         }
     }
 
-    status_t err = configureTemporalLayers(params, false /* inConfigure */, mOutputFormat);
-    if (err != OK) {
-        err = OK; // ignore failure
-    }
+    // Ignore errors as failure is expected for codecs that aren't video encoders.
+    (void)configureTemporalLayers(params, false /* inConfigure */, mOutputFormat);
 
     return setVendorParameters(params);
 }
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 3c7ae3e..710ae68 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -22,6 +22,7 @@
 
 #include <android/hardware/cas/native/1.0/IDescrambler.h>
 #include <binder/MemoryDealer.h>
+#include <hidlmemory/FrameworkUtils.h>
 #include <media/openmax/OMX_Core.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AUtils.h>
@@ -34,6 +35,7 @@
 #include "include/SharedMemoryBuffer.h"
 
 namespace android {
+using hardware::fromHeap;
 using hardware::hidl_handle;
 using hardware::hidl_string;
 using hardware::hidl_vec;
@@ -162,7 +164,7 @@
         size_t size;
         it->mSharedEncryptedBuffer->getMemory(&offset, &size);
         hardware::cas::native::V1_0::SharedBuffer srcBuffer = {
-                .heapBase = mHidlMemory,
+                .heapBase = *mHidlMemory,
                 .offset = (uint64_t) offset,
                 .size = size
         };
@@ -308,11 +310,8 @@
         }
     } else if (mDescrambler != nullptr) {
         sp<IMemoryHeap> heap = dealer->getMemoryHeap();
-        native_handle_t* nativeHandle = native_handle_create(1, 0);
-        if (nativeHandle != nullptr) {
-            int fd = heap->getHeapID();
-            nativeHandle->data[0] = fd;
-            mHidlMemory = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize());
+        mHidlMemory = fromHeap(heap);
+        if (mHidlMemory != NULL) {
             ALOGV("created hidl_memory for descrambler");
         } else {
             ALOGE("failed to create hidl_memory for descrambler");
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 910abc6..e33d3da 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -193,7 +193,7 @@
 
     prctl(PR_SET_NAME, (unsigned long)"AMRWriter", 0, 0, 0);
     while (!mDone) {
-        MediaBuffer *buffer;
+        MediaBufferBase *buffer;
         err = mSource->read(&buffer);
 
         if (err != OK) {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 08b2775..65348e5 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -60,8 +60,10 @@
         "AudioPresentationInfo.cpp",
         "AudioSource.cpp",
         "BufferImpl.cpp",
+        "C2OMXNode.cpp",
         "CCodec.cpp",
         "CCodecBufferChannel.cpp",
+        "Codec2InfoBuilder.cpp",
         "CodecBase.cpp",
         "CallbackDataSource.cpp",
         "CallbackMediaSource.cpp",
@@ -99,7 +101,6 @@
         "SkipCutBuffer.cpp",
         "StagefrightMediaScanner.cpp",
         "StagefrightMetadataRetriever.cpp",
-        "SurfaceMediaSource.cpp",
         "SurfaceUtils.cpp",
         "Utils.cpp",
         "ThrottledSource.cpp",
@@ -130,7 +131,6 @@
         "libui",
         "libutils",
         "libmedia_helper",
-        "libstagefright_bufferqueue_helper",
         "libstagefright_codec2",
         "libstagefright_codec2_vndk",
         "libstagefright_foundation",
@@ -139,6 +139,7 @@
         "libstagefright_xmlparser",
         "libdl",
         "libRScpp",
+        "libhidlallocatorutils",
         "libhidlbase",
         "libhidlmemory",
         // TODO: Remove libv4l2_c2_componentstore.
@@ -149,6 +150,10 @@
         "android.hardware.media.omx@1.0",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
+
+        // TODO: do not link directly with impl
+        "android.hardware.media.c2@1.0-service-impl",
+        "libstagefright_bufferqueue_helper",
     ],
 
     static_libs: [
@@ -215,6 +220,7 @@
         "InterfaceUtils.cpp",
         "MediaClock.cpp",
         "MediaExtractorFactory.cpp",
+        "NdkUtils.cpp",
         "NuCachedSource2.cpp",
         "RemoteMediaExtractor.cpp",
         "RemoteMediaSource.cpp",
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 70ce38c..d854582 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -240,7 +240,7 @@
 }
 
 status_t AudioSource::read(
-        MediaBuffer **out, const ReadOptions * /* options */) {
+        MediaBufferBase **out, const ReadOptions * /* options */) {
     Mutex::Autolock autoLock(mLock);
     *out = NULL;
 
@@ -311,7 +311,7 @@
     return OK;
 }
 
-void AudioSource::signalBufferReturned(MediaBuffer *buffer) {
+void AudioSource::signalBufferReturned(MediaBufferBase *buffer) {
     ALOGV("signalBufferReturned: %p", buffer->data());
     Mutex::Autolock autoLock(mLock);
     --mNumClientOwnedBuffers;
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index bd2443d..d2eee33 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -64,10 +64,87 @@
     return ICrypto::kDestinationTypeNativeHandle;
 }
 
+// Codec2Buffer
+
+bool Codec2Buffer::canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const {
+    if (const_cast<Codec2Buffer *>(this)->base() == nullptr) {
+        return false;
+    }
+    if (buffer->data().type() != C2BufferData::LINEAR) {
+        return false;
+    }
+    if (buffer->data().linearBlocks().size() == 0u) {
+        // Nothing to copy, so we can copy by doing nothing.
+        return true;
+    } else if (buffer->data().linearBlocks().size() > 1u) {
+        // We don't know how to copy more than one blocks.
+        return false;
+    }
+    if (buffer->data().linearBlocks()[0].size() > capacity()) {
+        // It won't fit.
+        return false;
+    }
+    return true;
+}
+
+bool Codec2Buffer::copyLinear(const std::shared_ptr<C2Buffer> &buffer) {
+    // We assume that all canCopyLinear() checks passed.
+    if (buffer->data().linearBlocks().size() == 0u) {
+        setRange(0, 0);
+        return true;
+    }
+    C2ReadView view = buffer->data().linearBlocks()[0].map().get();
+    if (view.error() != C2_OK) {
+        ALOGD("Error while mapping: %d", view.error());
+        return false;
+    }
+    if (view.capacity() > capacity()) {
+        ALOGD("C2ConstLinearBlock lied --- it actually doesn't fit: view(%u) > this(%zu)",
+                view.capacity(), capacity());
+        return false;
+    }
+    memcpy(base(), view.data(), view.capacity());
+    setRange(0, view.capacity());
+    return true;
+}
+
+// LocalLinearBuffer
+
+bool LocalLinearBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
+    return canCopyLinear(buffer);
+}
+
+bool LocalLinearBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
+    return copyLinear(buffer);
+}
+
+// DummyContainerBuffer
+
+DummyContainerBuffer::DummyContainerBuffer(
+        const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer)
+    : Codec2Buffer(format, new ABuffer(nullptr, 1)),
+      mBufferRef(buffer) {
+    setRange(0, buffer ? 1 : 0);
+}
+
+std::shared_ptr<C2Buffer> DummyContainerBuffer::asC2Buffer() {
+    return std::move(mBufferRef);
+}
+
+bool DummyContainerBuffer::canCopy(const std::shared_ptr<C2Buffer> &) const {
+    return !mBufferRef;
+}
+
+bool DummyContainerBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
+    mBufferRef = buffer;
+    setRange(0, mBufferRef ? 1 : 0);
+    return true;
+}
+
 // LinearBlockBuffer
 
 // static
-sp<LinearBlockBuffer> LinearBlockBuffer::allocate(
+sp<LinearBlockBuffer> LinearBlockBuffer::Allocate(
         const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
     C2WriteView writeView(block->map().get());
     if (writeView.error() != C2_OK) {
@@ -76,15 +153,23 @@
     return new LinearBlockBuffer(format, std::move(writeView), block);
 }
 
-C2ConstLinearBlock LinearBlockBuffer::share() {
-    return mBlock->share(offset(), size(), C2Fence());
+std::shared_ptr<C2Buffer> LinearBlockBuffer::asC2Buffer() {
+    return C2Buffer::CreateLinearBuffer(mBlock->share(offset(), size(), C2Fence()));
+}
+
+bool LinearBlockBuffer::canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
+    return canCopyLinear(buffer);
+}
+
+bool LinearBlockBuffer::copy(const std::shared_ptr<C2Buffer> &buffer) {
+    return copyLinear(buffer);
 }
 
 LinearBlockBuffer::LinearBlockBuffer(
         const sp<AMessage> &format,
         C2WriteView&& writeView,
         const std::shared_ptr<C2LinearBlock> &block)
-    : MediaCodecBuffer(format, new ABuffer(writeView.data(), writeView.size())),
+    : Codec2Buffer(format, new ABuffer(writeView.data(), writeView.size())),
       mWriteView(writeView),
       mBlock(block) {
 }
@@ -92,23 +177,34 @@
 // ConstLinearBlockBuffer
 
 // static
-sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::allocate(
-        const sp<AMessage> &format, const C2ConstLinearBlock &block) {
-    C2ReadView readView(block.map().get());
+sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::Allocate(
+        const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer) {
+    if (!buffer
+            || buffer->data().type() != C2BufferData::LINEAR
+            || buffer->data().linearBlocks().size() != 1u) {
+        return nullptr;
+    }
+    C2ReadView readView(buffer->data().linearBlocks()[0].map().get());
     if (readView.error() != C2_OK) {
         return nullptr;
     }
-    return new ConstLinearBlockBuffer(format, std::move(readView));
+    return new ConstLinearBlockBuffer(format, std::move(readView), buffer);
 }
 
 ConstLinearBlockBuffer::ConstLinearBlockBuffer(
         const sp<AMessage> &format,
-        C2ReadView&& readView)
-    : MediaCodecBuffer(format, new ABuffer(
+        C2ReadView&& readView,
+        const std::shared_ptr<C2Buffer> &buffer)
+    : Codec2Buffer(format, new ABuffer(
             // NOTE: ABuffer only takes non-const pointer but this data is
             //       supposed to be read-only.
             const_cast<uint8_t *>(readView.data()), readView.capacity())),
-      mReadView(readView) {
+      mReadView(readView),
+      mBufferRef(buffer) {
+}
+
+std::shared_ptr<C2Buffer> ConstLinearBlockBuffer::asC2Buffer() {
+    return std::move(mBufferRef);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/C2OMXNode.cpp b/media/libstagefright/C2OMXNode.cpp
new file mode 100644
index 0000000..04faa28
--- /dev/null
+++ b/media/libstagefright/C2OMXNode.cpp
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+#ifdef __LP64__
+#define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
+#endif
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "C2OMXNode"
+#include <log/log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Component.h>
+#include <C2PlatformSupport.h>
+
+#include <OMX_Component.h>
+#include <OMX_Index.h>
+#include <OMX_IndexExt.h>
+
+#include <media/stagefright/omx/OMXUtils.h>
+#include <media/stagefright/MediaErrors.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include "include/C2OMXNode.h"
+
+namespace android {
+
+namespace {
+
+class Buffer2D : public C2Buffer {
+public:
+    explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
+};
+
+}  // namespace
+
+C2OMXNode::C2OMXNode(const std::shared_ptr<C2Component> &comp) : mComp(comp) {}
+
+status_t C2OMXNode::freeNode() {
+    mComp.reset();
+    return OK;
+}
+
+status_t C2OMXNode::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
+    (void)cmd;
+    (void)param;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::getParameter(OMX_INDEXTYPE index, void *params, size_t size) {
+    status_t err = ERROR_UNSUPPORTED;
+    switch ((uint32_t)index) {
+        case OMX_IndexParamConsumerUsageBits: {
+            // TODO: read from intf()
+            OMX_U32 *usage = (OMX_U32 *)params;
+            *usage = GRALLOC_USAGE_SW_READ_OFTEN;
+            err = OK;
+            break;
+        }
+        case OMX_IndexParamPortDefinition: {
+            if (size < sizeof(OMX_PARAM_PORTDEFINITIONTYPE)) {
+                return BAD_VALUE;
+            }
+            OMX_PARAM_PORTDEFINITIONTYPE *pDef = (OMX_PARAM_PORTDEFINITIONTYPE *)params;
+            // TODO: read these from intf()
+            pDef->nBufferCountActual = 16;
+            pDef->eDomain = OMX_PortDomainVideo;
+            pDef->format.video.nFrameWidth = 1080;
+            pDef->format.video.nFrameHeight = 1920;
+            err = OK;
+            break;
+        }
+        default:
+            break;
+    }
+    return err;
+}
+
+status_t C2OMXNode::setParameter(OMX_INDEXTYPE index, const void *params, size_t size) {
+    (void)index;
+    (void)params;
+    (void)size;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::getConfig(OMX_INDEXTYPE index, void *config, size_t size) {
+    (void)index;
+    (void)config;
+    (void)size;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::setConfig(OMX_INDEXTYPE index, const void *config, size_t size) {
+    (void)index;
+    (void)config;
+    (void)size;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
+    (void)portIndex;
+    (void)mode;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::prepareForAdaptivePlayback(
+        OMX_U32 portIndex, OMX_BOOL enable,
+        OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
+    (void)portIndex;
+    (void)enable;
+    (void)maxFrameWidth;
+    (void)maxFrameHeight;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::configureVideoTunnelMode(
+        OMX_U32 portIndex, OMX_BOOL tunneled,
+        OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
+    (void)portIndex;
+    (void)tunneled;
+    (void)audioHwSync;
+    *sidebandHandle = nullptr;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::getGraphicBufferUsage(OMX_U32 portIndex, OMX_U32* usage) {
+    (void)portIndex;
+    *usage = 0;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::setInputSurface(const sp<IOMXBufferSource> &bufferSource) {
+    c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
+            C2PlatformAllocatorStore::GRALLOC,
+            &mAllocator);
+    if (err != OK) {
+        return UNKNOWN_ERROR;
+    }
+    mBufferSource = bufferSource;
+    return OK;
+}
+
+status_t C2OMXNode::allocateSecureBuffer(
+        OMX_U32 portIndex, size_t size, buffer_id *buffer,
+        void **bufferData, sp<NativeHandle> *nativeHandle) {
+    (void)portIndex;
+    (void)size;
+    (void)nativeHandle;
+    *buffer = 0;
+    *bufferData = nullptr;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::useBuffer(
+        OMX_U32 portIndex, const OMXBuffer &omxBuf, buffer_id *buffer) {
+    (void)portIndex;
+    (void)omxBuf;
+    *buffer = 0;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::freeBuffer(OMX_U32 portIndex, buffer_id buffer) {
+    (void)portIndex;
+    (void)buffer;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::fillBuffer(
+        buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) {
+    (void)buffer;
+    (void)omxBuf;
+    (void)fenceFd;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::emptyBuffer(
+        buffer_id buffer, const OMXBuffer &omxBuf,
+        OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+    // TODO: better fence handling
+    if (fenceFd >= 0) {
+        sp<Fence> fence = new Fence(fenceFd);
+        fence->waitForever(LOG_TAG);
+    }
+    std::shared_ptr<C2Component> comp = mComp.lock();
+    if (!comp) {
+        return NO_INIT;
+    }
+
+    uint32_t c2Flags = 0;
+    std::shared_ptr<C2GraphicBlock> block;
+
+    C2Handle *handle = nullptr;
+    if (omxBuf.mBufferType == OMXBuffer::kBufferTypeANWBuffer) {
+        std::shared_ptr<C2GraphicAllocation> alloc;
+        handle = WrapNativeCodec2GrallocHandle(
+                native_handle_clone(omxBuf.mGraphicBuffer->handle),
+                omxBuf.mGraphicBuffer->width,
+                omxBuf.mGraphicBuffer->height,
+                omxBuf.mGraphicBuffer->format,
+                omxBuf.mGraphicBuffer->usage,
+                omxBuf.mGraphicBuffer->stride);
+        c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
+        if (err != OK) {
+            return UNKNOWN_ERROR;
+        }
+        block = _C2BlockFactory::CreateGraphicBlock(alloc);
+    } else if (flags & OMX_BUFFERFLAG_EOS) {
+        c2Flags = C2FrameData::FLAG_END_OF_STREAM;
+    } else {
+        return BAD_VALUE;
+    }
+
+    std::unique_ptr<C2Work> work(new C2Work);
+    work->input.flags = (C2FrameData::flags_t)c2Flags;
+    work->input.ordinal.timestamp = timestamp;
+    work->input.ordinal.frameIndex = mFrameIndex++;
+    work->input.buffers.clear();
+    if (block) {
+        std::shared_ptr<C2Buffer> c2Buffer(
+                // TODO: fence
+                new Buffer2D(block->share(
+                        C2Rect(block->width(), block->height()), ::C2Fence())),
+                [handle, buffer, source = getSource()](C2Buffer *ptr) {
+                    delete ptr;
+                    native_handle_delete(handle);
+                    // TODO: fence
+                    (void)source->onInputBufferEmptied(buffer, -1);
+                });
+        work->input.buffers.push_back(c2Buffer);
+    }
+    work->worklets.clear();
+    work->worklets.emplace_back(new C2Worklet);
+    std::list<std::unique_ptr<C2Work>> items;
+    items.push_back(std::move(work));
+
+    c2_status_t err = comp->queue_nb(&items);
+    if (err != C2_OK) {
+        return UNKNOWN_ERROR;
+    }
+
+    return OK;
+}
+
+status_t C2OMXNode::getExtensionIndex(
+        const char *parameterName, OMX_INDEXTYPE *index) {
+    (void)parameterName;
+    *index = OMX_IndexMax;
+    return ERROR_UNSUPPORTED;
+}
+
+status_t C2OMXNode::dispatchMessage(const omx_message& msg) {
+    if (msg.type != omx_message::EVENT) {
+        return ERROR_UNSUPPORTED;
+    }
+    if (msg.u.event_data.event != OMX_EventDataSpaceChanged) {
+        return ERROR_UNSUPPORTED;
+    }
+    // TODO: fill intf() with info inside |msg|.
+    return OK;
+}
+
+sp<IOMXBufferSource> C2OMXNode::getSource() {
+    return mBufferSource;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/CCodec.cpp b/media/libstagefright/CCodec.cpp
index 84e98f8..f62ee41 100644
--- a/media/libstagefright/CCodec.cpp
+++ b/media/libstagefright/CCodec.cpp
@@ -24,17 +24,23 @@
 #include <C2PlatformSupport.h>
 #include <C2V4l2Support.h>
 
+#include <android/IOMXBufferSource.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
 #include <gui/Surface.h>
+#include <media/stagefright/codec2/1.0/InputSurface.h>
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/CCodec.h>
 #include <media/stagefright/PersistentSurface.h>
 
+#include "include/C2OMXNode.h"
 #include "include/CCodecBufferChannel.h"
-
-using namespace std::chrono_literals;
+#include "include/InputSurfaceWrapper.h"
 
 namespace android {
 
+using namespace std::chrono_literals;
+using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+
 namespace {
 
 class CCodecWatchdog : public AHandler {
@@ -146,6 +152,76 @@
     wp<CCodec> mCodec;
 };
 
+class C2InputSurfaceWrapper : public InputSurfaceWrapper {
+public:
+    explicit C2InputSurfaceWrapper(const sp<InputSurface> &surface) : mSurface(surface) {}
+    ~C2InputSurfaceWrapper() override = default;
+
+    status_t connect(const std::shared_ptr<C2Component> &comp) override {
+        if (mConnection != nullptr) {
+            return ALREADY_EXISTS;
+        }
+        mConnection = mSurface->connectToComponent(comp);
+        return OK;
+    }
+
+    void disconnect() override {
+        if (mConnection != nullptr) {
+            mConnection->disconnect();
+            mConnection.clear();
+        }
+    }
+
+private:
+    sp<InputSurface> mSurface;
+    sp<InputSurfaceConnection> mConnection;
+};
+
+class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
+public:
+    explicit GraphicBufferSourceWrapper(const sp<IGraphicBufferSource> &source) : mSource(source) {}
+    ~GraphicBufferSourceWrapper() override = default;
+
+    status_t connect(const std::shared_ptr<C2Component> &comp) override {
+        // TODO: proper color aspect & dataspace
+        android_dataspace dataSpace = HAL_DATASPACE_BT709;
+
+        mNode = new C2OMXNode(comp);
+        mSource->configure(mNode, dataSpace);
+
+        // TODO: configure according to intf().
+
+        sp<IOMXBufferSource> source = mNode->getSource();
+        if (source == nullptr) {
+            return NO_INIT;
+        }
+        constexpr size_t kNumSlots = 16;
+        for (size_t i = 0; i < kNumSlots; ++i) {
+            source->onInputBufferAdded(i);
+        }
+        source->onOmxExecuting();
+        return OK;
+    }
+
+    void disconnect() override {
+        if (mNode == nullptr) {
+            return;
+        }
+        sp<IOMXBufferSource> source = mNode->getSource();
+        if (source == nullptr) {
+            ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
+            return;
+        }
+        source->onOmxIdle();
+        source->onOmxLoaded();
+        mNode.clear();
+    }
+
+private:
+    sp<IGraphicBufferSource> mSource;
+    sp<C2OMXNode> mNode;
+};
+
 }  // namespace
 
 CCodec::CCodec()
@@ -237,6 +313,19 @@
 }
 
 void CCodec::configure(const sp<AMessage> &msg) {
+    std::shared_ptr<C2ComponentInterface> intf;
+    {
+        Mutexed<State>::Locked state(mState);
+        if (state->get() != ALLOCATED) {
+            state->set(RELEASED);
+            state.unlock();
+            mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
+            state.lock();
+            return;
+        }
+        intf = state->comp->intf();
+    }
+
     sp<AMessage> inputFormat(new AMessage);
     sp<AMessage> outputFormat(new AMessage);
     if (status_t err = [=] {
@@ -256,11 +345,34 @@
             setSurface(surface);
         }
 
+        std::vector<std::unique_ptr<C2Param>> params;
+        std::initializer_list<C2Param::Index> indices {
+            C2PortMimeConfig::input::PARAM_TYPE,
+            C2PortMimeConfig::output::PARAM_TYPE,
+        };
+        c2_status_t c2err = intf->query_vb(
+                {},
+                indices,
+                C2_DONT_BLOCK,
+                &params);
+        if (c2err != C2_OK) {
+            ALOGE("Failed to query component interface: %d", c2err);
+            return UNKNOWN_ERROR;
+        }
+        if (params.size() != indices.size()) {
+            ALOGE("Component returns wrong number of params");
+            return UNKNOWN_ERROR;
+        }
+        if (!params[0] || !params[1]) {
+            ALOGE("Component returns null params");
+            return UNKNOWN_ERROR;
+        }
+        inputFormat->setString("mime", ((C2PortMimeConfig *)params[0].get())->m.value);
+        outputFormat->setString("mime", ((C2PortMimeConfig *)params[1].get())->m.value);
+
         // XXX: hack
         bool audio = mime.startsWithIgnoreCase("audio/");
         if (encoder) {
-            outputFormat->setString("mime", mime);
-            inputFormat->setString("mime", AStringPrintf("%s/raw", audio ? "audio" : "video"));
             if (audio) {
                 inputFormat->setInt32("channel-count", 1);
                 inputFormat->setInt32("sample-rate", 44100);
@@ -271,8 +383,6 @@
                 outputFormat->setInt32("height", 1920);
             }
         } else {
-            inputFormat->setString("mime", mime);
-            outputFormat->setString("mime", AStringPrintf("%s/raw", audio ? "audio" : "video"));
             if (audio) {
                 outputFormat->setInt32("channel-count", 2);
                 outputFormat->setInt32("sample-rate", 44100);
@@ -300,18 +410,18 @@
 }
 
 void CCodec::createInputSurface() {
-    sp<IGraphicBufferProducer> producer;
-    sp<GraphicBufferSource> source(new GraphicBufferSource);
+    // TODO: get this from codec process
+    sp<InputSurface> surface(InputSurface::Create());
 
-    status_t err = source->initCheck();
+    // TODO: get proper error code.
+    status_t err = (surface == nullptr) ? UNKNOWN_ERROR : OK;
     if (err != OK) {
-        ALOGE("Failed to initialize graphic buffer source: %d", err);
+        ALOGE("Failed to initialize input surface: %d", err);
         mCallback->onInputSurfaceCreationFailed(err);
         return;
     }
-    producer = source->getIGraphicBufferProducer();
 
-    err = setupInputSurface(source);
+    err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(surface));
     if (err != OK) {
         ALOGE("Failed to set up input surface: %d", err);
         mCallback->onInputSurfaceCreationFailed(err);
@@ -328,16 +438,16 @@
     mCallback->onInputSurfaceCreated(
             inputFormat,
             outputFormat,
-            new BufferProducerWrapper(producer));
+            new BufferProducerWrapper(new H2BGraphicBufferProducer(surface)));
 }
 
-status_t CCodec::setupInputSurface(const sp<GraphicBufferSource> &source) {
-    status_t err = mChannel->setGraphicBufferSource(source);
+status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) {
+    status_t err = mChannel->setInputSurface(surface);
     if (err != OK) {
         return err;
     }
 
-    // TODO: configure |source| with other settings.
+    // TODO: configure |surface| with other settings.
     return OK;
 }
 
@@ -348,10 +458,22 @@
 }
 
 void CCodec::setInputSurface(const sp<PersistentSurface> &surface) {
-    // TODO
-    (void)surface;
+    status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
+            surface->getBufferSource()));
+    if (err != OK) {
+        ALOGE("Failed to set up input surface: %d", err);
+        mCallback->onInputSurfaceDeclined(err);
+        return;
+    }
 
-    mCallback->onInputSurfaceDeclined(ERROR_UNSUPPORTED);
+    sp<AMessage> inputFormat;
+    sp<AMessage> outputFormat;
+    {
+        Mutexed<Formats>::Locked formats(mFormats);
+        inputFormat = formats->inputFormat;
+        outputFormat = formats->outputFormat;
+    }
+    mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
 }
 
 void CCodec::initiateStart() {
@@ -624,7 +746,7 @@
     switch (msg->what()) {
         case kWhatAllocate: {
             // C2ComponentStore::createComponent() should return within 100ms.
-            setDeadline(now + 150ms);
+            setDeadline(now + 150ms, "allocate");
             AString componentName;
             CHECK(msg->findString("componentName", &componentName));
             allocate(componentName);
@@ -632,7 +754,7 @@
         }
         case kWhatConfigure: {
             // C2Component::commit_sm() should return within 5ms.
-            setDeadline(now + 50ms);
+            setDeadline(now + 50ms, "configure");
             sp<AMessage> format;
             CHECK(msg->findMessage("format", &format));
             configure(format);
@@ -640,31 +762,31 @@
         }
         case kWhatStart: {
             // C2Component::start() should return within 500ms.
-            setDeadline(now + 550ms);
+            setDeadline(now + 550ms, "start");
             start();
             break;
         }
         case kWhatStop: {
             // C2Component::stop() should return within 500ms.
-            setDeadline(now + 550ms);
+            setDeadline(now + 550ms, "stop");
             stop();
             break;
         }
         case kWhatFlush: {
             // C2Component::flush_sm() should return within 5ms.
-            setDeadline(now + 50ms);
+            setDeadline(now + 50ms, "flush");
             flush();
             break;
         }
         case kWhatCreateInputSurface: {
             // Surface operations may be briefly blocking.
-            setDeadline(now + 100ms);
+            setDeadline(now + 100ms, "createInputSurface");
             createInputSurface();
             break;
         }
         case kWhatSetInputSurface: {
             // Surface operations may be briefly blocking.
-            setDeadline(now + 100ms);
+            setDeadline(now + 100ms, "setInputSurface");
             sp<RefBase> obj;
             CHECK(msg->findObject("surface", &obj));
             sp<PersistentSurface> surface(static_cast<PersistentSurface *>(obj.get()));
@@ -692,25 +814,28 @@
             break;
         }
     }
-    setDeadline(TimePoint::max());
+    setDeadline(TimePoint::max(), "none");
 }
 
-void CCodec::setDeadline(const TimePoint &newDeadline) {
-    Mutexed<TimePoint>::Locked deadline(mDeadline);
-    *deadline = newDeadline;
+void CCodec::setDeadline(const TimePoint &newDeadline, const char *name) {
+    Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
+    deadline->set(newDeadline, name);
 }
 
 void CCodec::initiateReleaseIfStuck() {
+    std::string name;
     {
-        Mutexed<TimePoint>::Locked deadline(mDeadline);
-        if (*deadline >= std::chrono::steady_clock::now()) {
+        Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
+        if (deadline->get() >= std::chrono::steady_clock::now()) {
             // We're not stuck.
             return;
         }
+        name = deadline->getName();
     }
 
+    ALOGW("previous call to %s exceeded timeout", name.c_str());
     mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
-    initiateRelease();
+    initiateRelease(false);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 27060e1..449c6aa 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -101,15 +101,6 @@
      * Release the buffer obtained from requestNewBuffer() and get the
      * associated C2Buffer object back. Returns empty shared_ptr if the
      * buffer is not on file.
-     *
-     * XXX: this is a quick hack to be removed
-     */
-    virtual std::shared_ptr<C2Buffer> releaseBufferIndex(size_t /* index */) { return nullptr; }
-
-    /**
-     * Release the buffer obtained from requestNewBuffer() and get the
-     * associated C2Buffer object back. Returns empty shared_ptr if the
-     * buffer is not on file.
      */
     virtual std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) = 0;
 
@@ -134,47 +125,6 @@
     DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
 };
 
-class CCodecBufferChannel::InputBufferClient {
-public:
-    explicit InputBufferClient(
-            const std::shared_ptr<CCodecBufferChannel> &channel) : mChannel(channel) {}
-    virtual ~InputBufferClient() = default;
-
-    virtual void onInputBufferAdded(size_t index, const sp<MediaCodecBuffer> &buffer) {
-        std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
-        if (!channel) {
-            return;
-        }
-        channel->mCallback->onInputBufferAvailable(index, buffer);
-    }
-
-    virtual void onStart() {
-        // no-op
-    }
-
-    virtual void onStop() {
-        // no-op
-    }
-
-    virtual void onRelease() {
-        // no-op
-    }
-
-    virtual void onInputBufferAvailable(size_t index, const sp<MediaCodecBuffer> &buffer) {
-        std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
-        if (!channel) {
-            return;
-        }
-        channel->mCallback->onInputBufferAvailable(index, buffer);
-    }
-
-protected:
-    InputBufferClient() = default;
-    std::weak_ptr<CCodecBufferChannel> mChannel;
-
-    DISALLOW_EVIL_CONSTRUCTORS(InputBufferClient);
-};
-
 class CCodecBufferChannel::OutputBuffers : public CCodecBufferChannel::Buffers {
 public:
     OutputBuffers() = default;
@@ -188,7 +138,7 @@
     virtual bool registerBuffer(
             const std::shared_ptr<C2Buffer> &buffer,
             size_t *index,
-            sp<MediaCodecBuffer> *codecBuffer) = 0;
+            sp<MediaCodecBuffer> *clientBuffer) = 0;
 
     /**
      * Register codec specific data as a buffer to be consistent with
@@ -197,9 +147,7 @@
     virtual bool registerCsd(
             const C2StreamCsdInfo::output * /* csd */,
             size_t * /* index */,
-            sp<MediaCodecBuffer> * /* codecBuffer */) {
-        return false;
-    }
+            sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
 
     /**
      * Release the buffer obtained from registerBuffer() and get the
@@ -227,29 +175,10 @@
 
 namespace {
 
-constexpr int32_t kMaskI32 = ~0;
-
 // TODO: get this info from component
 const static size_t kMinBufferArraySize = 16;
 const static size_t kLinearBufferSize = 524288;
 
-template <class T>
-ssize_t findBufferSlot(
-        std::vector<T> *buffers,
-        size_t maxSize,
-        std::function<bool(const T&)> pred) {
-    auto it = std::find_if(buffers->begin(), buffers->end(), pred);
-    if (it == buffers->end()) {
-        if (buffers->size() < maxSize) {
-            buffers->emplace_back();
-            return buffers->size() - 1;
-        } else {
-            return -1;
-        }
-    }
-    return std::distance(buffers->begin(), it);
-}
-
 sp<LinearBlockBuffer> allocateLinearBuffer(
         const std::shared_ptr<C2BlockPool> &pool,
         const sp<AMessage> &format,
@@ -257,41 +186,209 @@
         const C2MemoryUsage &usage) {
     std::shared_ptr<C2LinearBlock> block;
 
-    status_t err = pool->fetchLinearBlock(
-            size,
-            usage,
-            &block);
+    status_t err = pool->fetchLinearBlock(size, usage, &block);
     if (err != OK) {
         return nullptr;
     }
 
-    return LinearBlockBuffer::allocate(format, block);
+    return LinearBlockBuffer::Allocate(format, block);
 }
 
-class Buffer1D : public C2Buffer {
+class BuffersArrayImpl;
+
+/**
+ * Flexible buffer slots implementation.
+ */
+class FlexBuffersImpl {
 public:
-    explicit Buffer1D(C2ConstLinearBlock block) : C2Buffer({ block }) {}
+    FlexBuffersImpl() = default;
+
+    /**
+     * Assign an empty slot for a buffer and return the index. If there's no
+     * empty slot, just add one at the end and return it.
+     *
+     * \param buffer[in]  a new buffer to assign a slot.
+     * \return            index of the assigned slot.
+     */
+    size_t assignSlot(const sp<Codec2Buffer> &buffer) {
+        for (size_t i = 0; i < mBuffers.size(); ++i) {
+            if (mBuffers[i].clientBuffer.promote() == nullptr
+                    && mBuffers[i].compBuffer.expired()) {
+                mBuffers[i].clientBuffer = buffer;
+                return i;
+            }
+        }
+        mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
+        return mBuffers.size() - 1;
+    }
+
+    /**
+     * Release the slot from the client, and get the C2Buffer object back from
+     * the previously assigned buffer. Note that the slot is not completely free
+     * until the returned C2Buffer object is freed.
+     *
+     * \param buffer[in]  the buffer previously assigned a slot.
+     * \return            C2Buffer object from |buffer|.
+     */
+    std::shared_ptr<C2Buffer> releaseSlot(const sp<MediaCodecBuffer> &buffer) {
+        sp<Codec2Buffer> c2Buffer;
+        size_t index = mBuffers.size();
+        for (size_t i = 0; i < mBuffers.size(); ++i) {
+            if (mBuffers[i].clientBuffer.promote() == buffer) {
+                c2Buffer = mBuffers[i].clientBuffer.promote();
+                index = i;
+                break;
+            }
+        }
+        if (c2Buffer == nullptr) {
+            ALOGD("No matching buffer found");
+            return nullptr;
+        }
+        std::shared_ptr<C2Buffer> result = c2Buffer->asC2Buffer();
+        mBuffers[index].compBuffer = result;
+        return result;
+    }
+
+private:
+    friend class BuffersArrayImpl;
+
+    struct Entry {
+        wp<Codec2Buffer> clientBuffer;
+        std::weak_ptr<C2Buffer> compBuffer;
+    };
+    std::vector<Entry> mBuffers;
 };
 
-class Buffer2D : public C2Buffer {
+/**
+ * Static buffer slots implementation based on a fixed-size array.
+ */
+class BuffersArrayImpl {
 public:
-    explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
+    /**
+     * Initialize buffer array from the original |impl|. The buffers known by
+     * the client is preserved, and the empty slots are populated so that the
+     * array size is at least |minSize|.
+     *
+     * \param impl[in]      FlexBuffersImpl object used so far.
+     * \param minSize[in]   minimum size of the buffer array.
+     * \param allocate[in]  function to allocate a client buffer for an empty slot.
+     */
+    void initialize(
+            const FlexBuffersImpl &impl,
+            size_t minSize,
+            std::function<sp<Codec2Buffer>()> allocate) {
+        for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
+            sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer.promote();
+            bool ownedByClient = (clientBuffer != nullptr);
+            if (!ownedByClient) {
+                clientBuffer = allocate();
+            }
+            mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
+        }
+        for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
+            mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
+        }
+    }
+
+    /**
+     * Grab a buffer from the underlying array which matches the criteria.
+     *
+     * \param index[out]    index of the slot.
+     * \param buffer[out]   the matching buffer.
+     * \param match[in]     a function to test whether the buffer matches the
+     *                      criteria or not.
+     * \return OK           if successful,
+     *         NO_MEMORY    if there's no available slot meets the criteria.
+     */
+    status_t grabBuffer(
+            size_t *index,
+            sp<Codec2Buffer> *buffer,
+            std::function<bool(const sp<Codec2Buffer> &)> match =
+                [](const sp<Codec2Buffer> &) { return true; }) {
+        for (size_t i = 0; i < mBuffers.size(); ++i) {
+            if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()
+                    && match(mBuffers[i].clientBuffer)) {
+                mBuffers[i].ownedByClient = true;
+                *buffer = mBuffers[i].clientBuffer;
+                (*buffer)->meta()->clear();
+                (*buffer)->setRange(0, (*buffer)->capacity());
+                *index = i;
+                return OK;
+            }
+        }
+        return NO_MEMORY;
+    }
+
+    /**
+     * Return the buffer from the client, and get the C2Buffer object back from
+     * the buffer. Note that the slot is not completely free until the returned
+     * C2Buffer object is freed.
+     *
+     * \param buffer[in]  the buffer previously grabbed.
+     * \return            C2Buffer object from |buffer|.
+     */
+    std::shared_ptr<C2Buffer> returnBuffer(const sp<MediaCodecBuffer> &buffer) {
+        sp<Codec2Buffer> c2Buffer;
+        size_t index = mBuffers.size();
+        for (size_t i = 0; i < mBuffers.size(); ++i) {
+            if (mBuffers[i].clientBuffer == buffer) {
+                if (!mBuffers[i].ownedByClient) {
+                    ALOGD("Client returned a buffer it does not own according to our record: %zu", i);
+                }
+                c2Buffer = mBuffers[i].clientBuffer;
+                mBuffers[i].ownedByClient = false;
+                index = i;
+                break;
+            }
+        }
+        if (c2Buffer == nullptr) {
+            ALOGD("No matching buffer found");
+            return nullptr;
+        }
+        std::shared_ptr<C2Buffer> result = c2Buffer->asC2Buffer();
+        mBuffers[index].compBuffer = result;
+        return result;
+    }
+
+    /**
+     * Populate |array| with the underlying buffer array.
+     *
+     * \param array[out]  an array to be filled with the underlying buffer array.
+     */
+    void getArray(Vector<sp<MediaCodecBuffer>> *array) const {
+        array->clear();
+        for (const Entry &entry : mBuffers) {
+            array->push(entry.clientBuffer);
+        }
+    }
+
+    /**
+     * The client abandoned all known buffers, so reclaim the ownership.
+     */
+    void flush() {
+        for (Entry &entry : mBuffers) {
+            entry.ownedByClient = false;
+        }
+    }
+
+private:
+    struct Entry {
+        const sp<Codec2Buffer> clientBuffer;
+        std::weak_ptr<C2Buffer> compBuffer;
+        bool ownedByClient;
+    };
+    std::vector<Entry> mBuffers;
 };
 
 class InputBuffersArray : public CCodecBufferChannel::InputBuffers {
 public:
     InputBuffersArray() = default;
 
-    void add(
-            size_t index,
-            const sp<LinearBlockBuffer> &clientBuffer,
-            bool available) {
-        if (mBufferArray.size() <= index) {
-            // TODO: make this more efficient
-            mBufferArray.resize(index + 1);
-        }
-        mBufferArray[index].clientBuffer = clientBuffer;
-        mBufferArray[index].available = available;
+    void initialize(
+            const FlexBuffersImpl &impl,
+            size_t minSize,
+            std::function<sp<Codec2Buffer>()> allocate) {
+        mImpl.initialize(impl, minSize, allocate);
     }
 
     bool isArrayMode() const final { return true; }
@@ -301,52 +398,30 @@
     }
 
     void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
-        array->clear();
-        for (const Entry &entry : mBufferArray) {
-            array->push(entry.clientBuffer);
-        }
+        mImpl.getArray(array);
     }
 
     bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
-        for (size_t i = 0; i < mBufferArray.size(); ++i) {
-            if (mBufferArray[i].available && mBufferArray[i].compBuffer.expired()) {
-                mBufferArray[i].available = false;
-                *index = i;
-                *buffer = mBufferArray[i].clientBuffer;
-                (*buffer)->meta()->clear();
-                (*buffer)->setRange(0, (*buffer)->capacity());
-                return true;
-            }
+        sp<Codec2Buffer> c2Buffer;
+        status_t err = mImpl.grabBuffer(index, &c2Buffer);
+        if (err == OK) {
+            c2Buffer->setFormat(mFormat);
+            *buffer = c2Buffer;
+            return true;
         }
         return false;
     }
 
     std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) override {
-        for (size_t i = 0; i < mBufferArray.size(); ++i) {
-            if (!mBufferArray[i].available && mBufferArray[i].clientBuffer == buffer) {
-                std::shared_ptr<C2Buffer> buffer = std::make_shared<Buffer1D>(mBufferArray[i].clientBuffer->share());
-                mBufferArray[i].available = true;
-                mBufferArray[i].compBuffer = buffer;
-                return buffer;
-            }
-        }
-        return nullptr;
+        return mImpl.returnBuffer(buffer);
     }
 
     void flush() override {
-        for (size_t i = 0; i < mBufferArray.size(); ++i) {
-            mBufferArray[i].available = true;
-        }
+        mImpl.flush();
     }
 
 private:
-    struct Entry {
-        sp<LinearBlockBuffer> clientBuffer;
-        std::weak_ptr<C2Buffer> compBuffer;
-        bool available;
-    };
-
-    std::vector<Entry> mBufferArray;
+    BuffersArrayImpl mImpl;
 };
 
 class LinearInputBuffers : public CCodecBufferChannel::InputBuffers {
@@ -354,91 +429,50 @@
     using CCodecBufferChannel::InputBuffers::InputBuffers;
 
     bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
-        *buffer = nullptr;
-        ssize_t ret = findBufferSlot<wp<LinearBlockBuffer>>(
-                &mBuffers, kMinBufferArraySize,
-                [] (const auto &elem) { return elem.promote() == nullptr; });
-        if (ret < 0) {
-            return false;
-        }
-        // TODO: proper max input size and usage
+        // TODO: proper max input size
         // TODO: read usage from intf
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
         sp<LinearBlockBuffer> newBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
         if (newBuffer == nullptr) {
             return false;
         }
-        mBuffers[ret] = newBuffer;
-        *index = ret;
+        *index = mImpl.assignSlot(newBuffer);
         *buffer = newBuffer;
         return true;
     }
 
     std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) override {
-        auto it = std::find(mBuffers.begin(), mBuffers.end(), buffer);
-        if (it == mBuffers.end()) {
-            return nullptr;
-        }
-        sp<LinearBlockBuffer> codecBuffer = it->promote();
-        // We got sp<> reference from the caller so this should never happen..
-        CHECK(codecBuffer != nullptr);
-        return std::make_shared<Buffer1D>(codecBuffer->share());
+        return mImpl.releaseSlot(buffer);
     }
 
     void flush() override {
+        // This is no-op by default unless we're in array mode where we need to keep
+        // track of the flushed work.
     }
 
     std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode() final {
         std::unique_ptr<InputBuffersArray> array(new InputBuffersArray);
         array->setFormat(mFormat);
-        // TODO
-        const size_t size = std::max(kMinBufferArraySize, mBuffers.size());
-        mBuffers.resize(size);
-        for (size_t i = 0; i < size; ++i) {
-            sp<LinearBlockBuffer> clientBuffer = mBuffers[i].promote();
-            bool available = false;
-            if (clientBuffer == nullptr) {
-                // TODO: proper max input size
-                // TODO: read usage from intf
-                C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-                clientBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
-                available = true;
-            }
-            array->add(
-                    i,
-                    clientBuffer,
-                    available);
-        }
+        array->initialize(
+                mImpl,
+                kMinBufferArraySize,
+                [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
+                    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+                    return allocateLinearBuffer(pool, format, kLinearBufferSize, usage);
+                });
         return std::move(array);
     }
 
 private:
-    // Buffers we passed to the client. The index of a buffer matches what
-    // was passed in BufferCallback::onInputBufferAvailable().
-    std::vector<wp<LinearBlockBuffer>> mBuffers;
+    FlexBuffersImpl mImpl;
 };
 
 class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
 public:
     GraphicInputBuffers() = default;
 
-    bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
-        *buffer = nullptr;
-        for (size_t i = 0; i < mAvailable.size(); ++i) {
-            if (mAvailable[i]) {
-                *index = i;
-                mAvailable[i] = false;
-                return true;
-            }
-        }
-        *index = mAvailable.size();
-        mAvailable.push_back(false);
-        return true;
-    }
-
-    std::shared_ptr<C2Buffer> releaseBufferIndex(size_t index) override {
-        mAvailable[index] = true;
-        return nullptr;
+    bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
+        return false;
     }
 
     std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &) override {
@@ -452,26 +486,22 @@
         return nullptr;
     }
 
-private:
-    std::vector<bool> mAvailable;
+    bool isArrayMode() const final { return true; }
+
+    void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
+        array->clear();
+    }
 };
 
 class OutputBuffersArray : public CCodecBufferChannel::OutputBuffers {
 public:
     using CCodecBufferChannel::OutputBuffers::OutputBuffers;
 
-    void add(
-            size_t index,
-            const sp<MediaCodecBuffer> &clientBuffer,
-            const std::shared_ptr<C2Buffer> &compBuffer,
-            bool available) {
-        if (mBufferArray.size() <= index) {
-            // TODO: make this more efficient
-            mBufferArray.resize(index + 1);
-        }
-        mBufferArray[index].clientBuffer = clientBuffer;
-        mBufferArray[index].compBuffer = compBuffer;
-        mBufferArray[index].available = available;
+    void initialize(
+            const FlexBuffersImpl &impl,
+            size_t minSize,
+            std::function<sp<Codec2Buffer>()> allocate) {
+        mImpl.initialize(impl, minSize, allocate);
     }
 
     bool isArrayMode() const final { return true; }
@@ -483,125 +513,69 @@
     bool registerBuffer(
             const std::shared_ptr<C2Buffer> &buffer,
             size_t *index,
-            sp<MediaCodecBuffer> *codecBuffer) final {
-        for (size_t i = 0; i < mBufferArray.size(); ++i) {
-            if (mBufferArray[i].available && copy(buffer, mBufferArray[i].clientBuffer)) {
-                *index = i;
-                *codecBuffer = mBufferArray[i].clientBuffer;
-                (*codecBuffer)->setFormat(mFormat);
-                (*codecBuffer)->meta()->clear();
-                mBufferArray[i].compBuffer = buffer;
-                mBufferArray[i].available = false;
-                return true;
-            }
+            sp<MediaCodecBuffer> *clientBuffer) final {
+        sp<Codec2Buffer> c2Buffer;
+        status_t err = mImpl.grabBuffer(
+                index,
+                &c2Buffer,
+                [buffer](const sp<Codec2Buffer> &clientBuffer) {
+                    return clientBuffer->canCopy(buffer);
+                });
+        if (err != OK) {
+            return false;
         }
-        return false;
+        if (!c2Buffer->copy(buffer)) {
+            return false;
+        }
+        c2Buffer->setFormat(mFormat);
+        *clientBuffer = c2Buffer;
+        return true;
     }
 
     bool registerCsd(
             const C2StreamCsdInfo::output *csd,
             size_t *index,
-            sp<MediaCodecBuffer> *codecBuffer) final {
-        for (size_t i = 0; i < mBufferArray.size(); ++i) {
-            if (mBufferArray[i].available
-                    && mBufferArray[i].clientBuffer->capacity() >= csd->flexCount()) {
-                // TODO: proper format update
-                sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy(csd->m.value, csd->flexCount());
-                mFormat = mFormat->dup();
-                mFormat->setBuffer("csd-0", csdBuffer);
-
-                memcpy(mBufferArray[i].clientBuffer->base(), csd->m.value, csd->flexCount());
-                mBufferArray[i].clientBuffer->setRange(0, csd->flexCount());
-                *index = i;
-                *codecBuffer = mBufferArray[i].clientBuffer;
-                (*codecBuffer)->setFormat(mFormat);
-                (*codecBuffer)->meta()->clear();
-                mBufferArray[i].available = false;
-                return true;
-            }
+            sp<MediaCodecBuffer> *clientBuffer) final {
+        sp<Codec2Buffer> c2Buffer;
+        status_t err = mImpl.grabBuffer(
+                index,
+                &c2Buffer,
+                [csd](const sp<Codec2Buffer> &clientBuffer) {
+                    return clientBuffer->base() != nullptr
+                            && clientBuffer->capacity() >= csd->flexCount();
+                });
+        if (err != OK) {
+            return false;
         }
-        return false;
+        // TODO: proper format update
+        sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy(csd->m.value, csd->flexCount());
+        mFormat = mFormat->dup();
+        mFormat->setBuffer("csd-0", csdBuffer);
+
+        memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
+        c2Buffer->setRange(0, csd->flexCount());
+        c2Buffer->setFormat(mFormat);
+        *clientBuffer = c2Buffer;
+        return true;
     }
 
     std::shared_ptr<C2Buffer> releaseBuffer(const sp<MediaCodecBuffer> &buffer) final {
-        for (size_t i = 0; i < mBufferArray.size(); ++i) {
-            if (!mBufferArray[i].available && mBufferArray[i].clientBuffer == buffer) {
-                mBufferArray[i].available = true;
-                return std::move(mBufferArray[i].compBuffer);
-            }
-        }
-        return nullptr;
+        return mImpl.returnBuffer(buffer);
     }
 
-    void flush(
-            const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
+    void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
         (void) flushedWork;
-        for (size_t i = 0; i < mBufferArray.size(); ++i) {
-            mBufferArray[i].available = true;
-            mBufferArray[i].compBuffer.reset();
-        }
+        mImpl.flush();
     }
 
-    virtual bool copy(
-            const std::shared_ptr<C2Buffer> &buffer,
-            const sp<MediaCodecBuffer> &clientBuffer) = 0;
-
     void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
-        array->clear();
-        for (const Entry &entry : mBufferArray) {
-            array->push(entry.clientBuffer);
-        }
+        mImpl.getArray(array);
     }
 
 private:
-    struct Entry {
-        sp<MediaCodecBuffer> clientBuffer;
-        std::shared_ptr<C2Buffer> compBuffer;
-        bool available;
-    };
-
-    std::vector<Entry> mBufferArray;
+    BuffersArrayImpl mImpl;
 };
 
-class LinearOutputBuffersArray : public OutputBuffersArray {
-public:
-    using OutputBuffersArray::OutputBuffersArray;
-
-    bool copy(
-            const std::shared_ptr<C2Buffer> &buffer,
-            const sp<MediaCodecBuffer> &clientBuffer) final {
-        if (!buffer) {
-            clientBuffer->setRange(0u, 0u);
-            return true;
-        }
-        C2ReadView view = buffer->data().linearBlocks().front().map().get();
-        if (clientBuffer->capacity() < view.capacity()) {
-            ALOGV("view.capacity() = %u", view.capacity());
-            return false;
-        }
-        clientBuffer->setRange(0u, view.capacity());
-        memcpy(clientBuffer->data(), view.data(), view.capacity());
-        return true;
-    }
-};
-
-class GraphicOutputBuffersArray : public OutputBuffersArray {
-public:
-    using OutputBuffersArray::OutputBuffersArray;
-
-    bool copy(
-            const std::shared_ptr<C2Buffer> &buffer,
-            const sp<MediaCodecBuffer> &clientBuffer) final {
-        if (!buffer) {
-            clientBuffer->setRange(0u, 0u);
-            return true;
-        }
-        clientBuffer->setRange(0u, 1u);
-        return true;
-    }
-};
-
-// Flexible in a sense that it does not have fixed array size.
 class FlexOutputBuffers : public CCodecBufferChannel::OutputBuffers {
 public:
     using CCodecBufferChannel::OutputBuffers::OutputBuffers;
@@ -609,56 +583,31 @@
     bool registerBuffer(
             const std::shared_ptr<C2Buffer> &buffer,
             size_t *index,
-            sp<MediaCodecBuffer> *codecBuffer) override {
-        *codecBuffer = nullptr;
-        ssize_t ret = findBufferSlot<BufferInfo>(
-                &mBuffers,
-                std::numeric_limits<size_t>::max(),
-                [] (const auto &elem) { return elem.clientBuffer.promote() == nullptr; });
-        if (ret < 0) {
-            return false;
-        }
-        sp<MediaCodecBuffer> newBuffer = convert(buffer);
-        mBuffers[ret] = { newBuffer, buffer };
-        *index = ret;
-        *codecBuffer = newBuffer;
+            sp<MediaCodecBuffer> *clientBuffer) override {
+        sp<Codec2Buffer> newBuffer = wrap(buffer);
+        *index = mImpl.assignSlot(newBuffer);
+        *clientBuffer = newBuffer;
         return true;
     }
 
     bool registerCsd(
             const C2StreamCsdInfo::output *csd,
             size_t *index,
-            sp<MediaCodecBuffer> *codecBuffer) final {
-        *codecBuffer = nullptr;
-        ssize_t ret = findBufferSlot<BufferInfo>(
-                &mBuffers,
-                std::numeric_limits<size_t>::max(),
-                [] (const auto &elem) { return elem.clientBuffer.promote() == nullptr; });
-        if (ret < 0) {
-            return false;
-        }
+            sp<MediaCodecBuffer> *clientBuffer) final {
         // TODO: proper format update
         sp<ABuffer> csdBuffer = ABuffer::CreateAsCopy(csd->m.value, csd->flexCount());
         mFormat = mFormat->dup();
         mFormat->setBuffer("csd-0", csdBuffer);
-        sp<MediaCodecBuffer> newBuffer = new MediaCodecBuffer(mFormat, csdBuffer);
-        mBuffers[ret] = { newBuffer, nullptr };
-        *index = ret;
-        *codecBuffer = newBuffer;
+
+        sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(mFormat, csdBuffer);
+        *index = mImpl.assignSlot(newBuffer);
+        *clientBuffer = newBuffer;
         return true;
     }
 
     std::shared_ptr<C2Buffer> releaseBuffer(
             const sp<MediaCodecBuffer> &buffer) override {
-        auto it = std::find_if(
-                mBuffers.begin(), mBuffers.end(),
-                [buffer] (const auto &elem) {
-                    return elem.clientBuffer.promote() == buffer;
-                });
-        if (it == mBuffers.end()) {
-            return nullptr;
-        }
-        return std::move(it->bufferRef);
+        return mImpl.releaseSlot(buffer);
     }
 
     void flush(
@@ -668,27 +617,31 @@
         // track of the flushed work.
     }
 
-    virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) = 0;
+    std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
+        std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray);
+        array->setFormat(mFormat);
+        array->initialize(
+                mImpl,
+                kMinBufferArraySize,
+                [this]() { return allocateArrayBuffer(); });
+        return std::move(array);
+    }
 
-protected:
-    struct BufferInfo {
-        // wp<> of MediaCodecBuffer for MediaCodec.
-        wp<MediaCodecBuffer> clientBuffer;
-        // Buffer reference to hold until clientBuffer is valid.
-        std::shared_ptr<C2Buffer> bufferRef;
-    };
-    // Buffers we passed to the client. The index of a buffer matches what
-    // was passed in BufferCallback::onInputBufferAvailable().
-    std::vector<BufferInfo> mBuffers;
+    virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0;
+
+    virtual sp<Codec2Buffer> allocateArrayBuffer() = 0;
+
+private:
+    FlexBuffersImpl mImpl;
 };
 
 class LinearOutputBuffers : public FlexOutputBuffers {
 public:
     using FlexOutputBuffers::FlexOutputBuffers;
 
-    virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
+    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
         if (buffer == nullptr) {
-            return new MediaCodecBuffer(mFormat, new ABuffer(nullptr, 0));
+            return new DummyContainerBuffer(mFormat, buffer);
         }
         if (buffer->data().type() != C2BufferData::LINEAR) {
             // We expect linear output buffers from the component.
@@ -698,28 +651,12 @@
             // We expect one and only one linear block from the component.
             return nullptr;
         }
-        return ConstLinearBlockBuffer::allocate(mFormat, buffer->data().linearBlocks().front());
+        return ConstLinearBlockBuffer::Allocate(mFormat, buffer);
     }
 
-    std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
-        std::unique_ptr<OutputBuffersArray> array(new LinearOutputBuffersArray);
-        array->setFormat(mFormat);
-
-        const size_t size = std::max(kMinBufferArraySize, mBuffers.size());
-        mBuffers.resize(size);
-        for (size_t i = 0; i < size; ++i) {
-            sp<MediaCodecBuffer> clientBuffer = mBuffers[i].clientBuffer.promote();
-            std::shared_ptr<C2Buffer> compBuffer = mBuffers[i].bufferRef;
-            bool available = false;
-            if (clientBuffer == nullptr) {
-                // TODO: proper max input size
-                clientBuffer = new MediaCodecBuffer(mFormat, new ABuffer(kLinearBufferSize));
-                available = true;
-                compBuffer.reset();
-            }
-            array->add(i, clientBuffer, compBuffer, available);
-        }
-        return std::move(array);
+    sp<Codec2Buffer> allocateArrayBuffer() override {
+        // TODO: proper max output size
+        return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
     }
 };
 
@@ -727,190 +664,17 @@
 public:
     using FlexOutputBuffers::FlexOutputBuffers;
 
-    sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
-        return new MediaCodecBuffer(
-                mFormat, buffer ? new ABuffer(nullptr, 1) : new ABuffer(nullptr, 0));
+    sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
+        return new DummyContainerBuffer(mFormat, buffer);
     }
 
-    std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
-        std::unique_ptr<OutputBuffersArray> array(new GraphicOutputBuffersArray);
-        array->setFormat(mFormat);
-
-        const size_t size = std::max(kMinBufferArraySize, mBuffers.size());
-        mBuffers.resize(size);
-        for (size_t i = 0; i < size; ++i) {
-            sp<MediaCodecBuffer> clientBuffer = mBuffers[i].clientBuffer.promote();
-            std::shared_ptr<C2Buffer> compBuffer = mBuffers[i].bufferRef;
-            bool available = false;
-            if (clientBuffer == nullptr) {
-                clientBuffer = new MediaCodecBuffer(mFormat, new ABuffer(nullptr, 1));
-                available = true;
-                compBuffer.reset();
-            }
-            array->add(i, clientBuffer, compBuffer, available);
-        }
-        return std::move(array);
+    sp<Codec2Buffer> allocateArrayBuffer() override {
+        return new DummyContainerBuffer(mFormat);
     }
 };
 
-class BufferQueueClient : public CCodecBufferChannel::InputBufferClient {
-public:
-    explicit BufferQueueClient(const sp<GraphicBufferSource> &source) : mSource(source) {}
-    virtual ~BufferQueueClient() = default;
-
-    void onInputBufferAdded(size_t index, const sp<MediaCodecBuffer> &buffer) override {
-        (void)buffer;
-        mSource->onInputBufferAdded(index & kMaskI32);
-    }
-
-    void onStart() override {
-        mSource->start();
-    }
-
-    void onStop() override {
-        mSource->stop();
-    }
-
-    void onRelease() override {
-        mSource->release();
-    }
-
-    void onInputBufferAvailable(size_t index, const sp<MediaCodecBuffer> &buffer) override {
-        ALOGV("onInputBufferEmptied index = %zu", index);
-        (void)buffer;
-        // TODO: can we really ignore fence here?
-        mSource->onInputBufferEmptied(index & kMaskI32, -1 /* fenceFd */);
-    }
-
-private:
-    sp<GraphicBufferSource> mSource;
-};
-
-class GraphicBlock : public C2GraphicBlock {
-    using C2GraphicBlock::C2GraphicBlock;
-    friend class ::android::CCodecBufferChannel;
-};
-
 }  // namespace
 
-class CCodecBufferChannel::C2ComponentWrapper : public ComponentWrapper {
-public:
-    explicit C2ComponentWrapper(
-            const std::shared_ptr<CCodecBufferChannel> &channel)
-        : mChannel(channel), mLastTimestamp(0) {}
-
-    virtual ~C2ComponentWrapper() {
-        for (const std::pair<int32_t, C2Handle *> &entry : mHandles) {
-            native_handle_delete(entry.second);
-        }
-    }
-
-    status_t submitBuffer(
-            int32_t bufferId, const sp<GraphicBuffer> &buffer,
-            int64_t timestamp, int fenceFd) override {
-        ALOGV("submitBuffer bufferId = %d", bufferId);
-        // TODO: Use fd to construct fence
-        (void)fenceFd;
-
-        std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
-        if (!channel) {
-            return NO_INIT;
-        }
-
-        std::shared_ptr<C2Allocator> allocator = mAllocator.lock();
-        if (!allocator) {
-            c2_status_t err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
-                    C2PlatformAllocatorStore::GRALLOC,
-                    &allocator);
-            if (err != OK) {
-                return UNKNOWN_ERROR;
-            }
-            mAllocator = allocator;
-        }
-
-        std::shared_ptr<C2GraphicAllocation> alloc;
-        C2Handle *handle = WrapNativeCodec2GrallocHandle(
-                buffer->handle, buffer->width, buffer->height,
-                buffer->format, buffer->usage, buffer->stride);
-        c2_status_t err = allocator->priorGraphicAllocation(handle, &alloc);
-        if (err != OK) {
-            return UNKNOWN_ERROR;
-        }
-
-        std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
-
-        std::unique_ptr<C2Work> work(new C2Work);
-        work->input.flags = (C2FrameData::flags_t)0;
-        work->input.ordinal.timestamp = timestamp;
-        work->input.ordinal.frameIndex = channel->mFrameIndex++;
-        work->input.buffers.clear();
-        work->input.buffers.emplace_back(new Buffer2D(
-                // TODO: fence
-                block->share(C2Rect(block->width(), block->height()), ::android::C2Fence())));
-        work->worklets.clear();
-        work->worklets.emplace_back(new C2Worklet);
-        std::list<std::unique_ptr<C2Work>> items;
-        items.push_back(std::move(work));
-
-        err = channel->mComponent->queue_nb(&items);
-        if (err != OK) {
-            native_handle_delete(handle);
-            return UNKNOWN_ERROR;
-        }
-
-        mLastTimestamp = timestamp;
-        if (mHandles.count(bufferId) > 0) {
-            native_handle_delete(mHandles[bufferId]);
-        }
-        mHandles[bufferId] = handle;
-
-        Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(channel->mInputBuffers);
-        ALOGV("releaseBufferIndex index = %d", bufferId);
-        (*buffers)->releaseBufferIndex(bufferId);
-
-        return OK;
-    }
-
-    status_t submitEos(int32_t bufferId) override {
-        std::shared_ptr<CCodecBufferChannel> channel = mChannel.lock();
-        if (!channel) {
-            return NO_INIT;
-        }
-
-        std::unique_ptr<C2Work> work(new C2Work);
-        work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
-        work->input.ordinal.timestamp = mLastTimestamp;
-        work->input.ordinal.frameIndex = channel->mFrameIndex++;
-        work->input.buffers.clear();
-        work->input.buffers.push_back(nullptr);
-        work->worklets.clear();
-        work->worklets.emplace_back(new C2Worklet);
-        std::list<std::unique_ptr<C2Work>> items;
-        items.push_back(std::move(work));
-
-        c2_status_t err = channel->mComponent->queue_nb(&items);
-
-        Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(channel->mInputBuffers);
-        (*buffers)->releaseBufferIndex(bufferId);
-
-        return (err == C2_OK) ? OK : UNKNOWN_ERROR;
-    }
-
-    void dispatchDataSpaceChanged(
-            int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
-        // TODO
-        (void)dataSpace;
-        (void)aspects;
-        (void)pixelFormat;
-    }
-
-private:
-    std::weak_ptr<CCodecBufferChannel> mChannel;
-    std::map<int32_t, C2Handle *> mHandles;
-    int64_t mLastTimestamp;
-    std::weak_ptr<C2Allocator> mAllocator;
-};
-
 CCodecBufferChannel::QueueGuard::QueueGuard(
         CCodecBufferChannel::QueueSync &sync) : mSync(sync) {
     std::unique_lock<std::mutex> l(mSync.mMutex);
@@ -967,13 +731,10 @@
     if (mCrypto != nullptr && mDealer != nullptr && mHeapSeqNum >= 0) {
         mCrypto->unsetHeap(mHeapSeqNum);
     }
-    // TODO: is this the right place?
-    mInputClient->onRelease();
 }
 
 void CCodecBufferChannel::setComponent(const std::shared_ptr<C2Component> &component) {
     mComponent = component;
-    mInputClient.reset(new InputBufferClient(shared_from_this()));
 
     C2StreamFormatConfig::input inputFormat(0u);
     C2StreamFormatConfig::output outputFormat(0u);
@@ -1026,16 +787,11 @@
     }
 }
 
-status_t CCodecBufferChannel::setGraphicBufferSource(
-        const sp<GraphicBufferSource> &source) {
-    ALOGV("setGraphicBufferSource");
-    mInputClient.reset(new BufferQueueClient(source));
-
-    // TODO: proper color aspect & dataspace
-    android_dataspace dataSpace = HAL_DATASPACE_BT709;
-    // TODO: read settings properly from the interface
-    return source->configure(new C2ComponentWrapper(
-            shared_from_this()), dataSpace, 16, 1080, 1920, GRALLOC_USAGE_SW_READ_OFTEN);
+status_t CCodecBufferChannel::setInputSurface(
+        const std::shared_ptr<InputSurfaceWrapper> &surface) {
+    ALOGV("setInputSurface");
+    mInputSurface = surface;
+    return OK;
 }
 
 status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
@@ -1100,12 +856,13 @@
     {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
         if (!(*buffers)->requestNewBuffer(&index, &inBuffer)) {
-            ALOGW("no new buffer available");
+            ALOGV("no new buffer available");
             inBuffer = nullptr;
+            return;
         }
     }
     ALOGV("new input index = %zu", index);
-    mInputClient->onInputBufferAvailable(index, inBuffer);
+    mCallback->onInputBufferAvailable(index, inBuffer);
 }
 
 status_t CCodecBufferChannel::renderOutputBuffer(
@@ -1182,7 +939,9 @@
     {
         Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
         if((*buffers)->releaseBuffer(buffer)) {
+            buffers.unlock();
             feedInputBufferIfAvailable();
+            buffers.lock();
         }
     }
     return OK;
@@ -1221,29 +980,38 @@
     }
 
     mSync.start();
-    // TODO: use proper buffer depth instead of this random value
-    for (size_t i = 0; i < kMinBufferArraySize; ++i) {
-        size_t index;
-        sp<MediaCodecBuffer> buffer;
-        {
-            Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
-            if (!(*buffers)->requestNewBuffer(&index, &buffer)) {
-                buffers.unlock();
-                ALOGE("start: cannot allocate memory");
-                mOnError(NO_MEMORY, ACTION_CODE_FATAL);
-                buffers.lock();
-                return;
+    if (mInputSurface == nullptr) {
+        // TODO: use proper buffer depth instead of this random value
+        for (size_t i = 0; i < kMinBufferArraySize; ++i) {
+            size_t index;
+            sp<MediaCodecBuffer> buffer;
+            {
+                Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
+                if (!(*buffers)->requestNewBuffer(&index, &buffer)) {
+                    if (i == 0) {
+                        ALOGE("start: cannot allocate memory at all");
+                        buffers.unlock();
+                        mOnError(NO_MEMORY, ACTION_CODE_FATAL);
+                        buffers.lock();
+                    } else {
+                        ALOGV("start: cannot allocate memory, only %zu buffers allocated", i);
+                    }
+                    break;
+                }
             }
+            mCallback->onInputBufferAvailable(index, buffer);
         }
-        mInputClient->onInputBufferAdded(index, buffer);
+    } else {
+        (void)mInputSurface->connect(mComponent);
     }
-    mInputClient->onStart();
 }
 
 void CCodecBufferChannel::stop() {
     mSync.stop();
     mFirstValidFrameIndex = mFrameIndex.load();
-    mInputClient->onStop();
+    if (mInputSurface != nullptr) {
+        mInputSurface->disconnect();
+    }
 }
 
 void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
diff --git a/media/libstagefright/CallbackMediaSource.cpp b/media/libstagefright/CallbackMediaSource.cpp
index 6811882..ea7392e 100644
--- a/media/libstagefright/CallbackMediaSource.cpp
+++ b/media/libstagefright/CallbackMediaSource.cpp
@@ -36,7 +36,7 @@
     return mSource->getFormat();
 }
 
-status_t CallbackMediaSource::read(MediaBuffer **buffer, const ReadOptions *options) {
+status_t CallbackMediaSource::read(MediaBufferBase **buffer, const ReadOptions *options) {
     return mSource->read(buffer, reinterpret_cast<const ReadOptions*>(options));
 }
 
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 6ed0d0e..4960418 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -1040,7 +1040,7 @@
     releaseRecordingFrame(frame);
 }
 
-void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
+void CameraSource::signalBufferReturned(MediaBufferBase *buffer) {
     ALOGV("signalBufferReturned: %p", buffer->data());
     Mutex::Autolock autoLock(mLock);
     for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
@@ -1059,7 +1059,7 @@
 }
 
 status_t CameraSource::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
+        MediaBufferBase **buffer, const ReadOptions *options) {
     ALOGV("read");
 
     *buffer = NULL;
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 970526a..f3f06d8 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -168,7 +168,7 @@
     return isSuccessful;
 }
 
-void CameraSourceTimeLapse::signalBufferReturned(MediaBuffer* buffer) {
+void CameraSourceTimeLapse::signalBufferReturned(MediaBufferBase* buffer) {
     ALOGV("signalBufferReturned");
     Mutex::Autolock autoLock(mQuickStopLock);
     if (mQuickStop && (buffer == mLastReadBufferCopy)) {
@@ -180,9 +180,9 @@
 }
 
 void createMediaBufferCopy(
-        const MediaBuffer& sourceBuffer,
+        const MediaBufferBase& sourceBuffer,
         int64_t frameTime,
-        MediaBuffer **newBuffer) {
+        MediaBufferBase **newBuffer) {
 
     ALOGV("createMediaBufferCopy");
     size_t sourceSize = sourceBuffer.size();
@@ -194,7 +194,7 @@
     (*newBuffer)->meta_data()->setInt64(kKeyTime, frameTime);
 }
 
-void CameraSourceTimeLapse::fillLastReadBufferCopy(MediaBuffer& sourceBuffer) {
+void CameraSourceTimeLapse::fillLastReadBufferCopy(MediaBufferBase& sourceBuffer) {
     ALOGV("fillLastReadBufferCopy");
     int64_t frameTime;
     CHECK(sourceBuffer.meta_data()->findInt64(kKeyTime, &frameTime));
@@ -204,7 +204,7 @@
 }
 
 status_t CameraSourceTimeLapse::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
+        MediaBufferBase **buffer, const ReadOptions *options) {
     ALOGV("read");
     if (mLastReadBufferCopy == NULL) {
         mLastReadStatus = CameraSource::read(buffer, options);
diff --git a/media/libstagefright/Codec2InfoBuilder.cpp b/media/libstagefright/Codec2InfoBuilder.cpp
new file mode 100644
index 0000000..ee7258d
--- /dev/null
+++ b/media/libstagefright/Codec2InfoBuilder.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "Codec2InfoBuilder"
+#include <log/log.h>
+
+#include <C2Component.h>
+#include <C2PlatformSupport.h>
+#include <C2V4l2Support.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+#include <media/stagefright/Codec2InfoBuilder.h>
+
+namespace android {
+
+using ConstTraitsPtr = std::shared_ptr<const C2Component::Traits>;
+
+status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
+    // Obtain C2ComponentStore
+    std::shared_ptr<C2ComponentStore> store = GetCodec2PlatformComponentStore();
+    if (store == nullptr) {
+        ALOGE("Cannot find a component store.");
+        return NO_INIT;
+    }
+
+    std::vector<ConstTraitsPtr> traits = store->listComponents();
+
+    if (property_get_bool("debug.stagefright.ccodec_v4l2", false)) {
+        std::shared_ptr<C2ComponentStore> v4l2Store = GetCodec2VDAComponentStore();
+        if (v4l2Store == nullptr) {
+            ALOGD("Cannot find a V4L2 component store.");
+            // non-fatal.
+        } else {
+            std::vector<ConstTraitsPtr> v4l2Traits = v4l2Store->listComponents();
+            traits.insert(traits.end(), v4l2Traits.begin(), v4l2Traits.end());
+        }
+    }
+
+    for (const ConstTraitsPtr &trait : traits) {
+        std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
+        codecInfo->setName(trait->name.c_str());
+        codecInfo->setOwner("dummy");
+        // TODO: get this from trait->kind
+        codecInfo->setEncoder(trait->name.find("encoder") != std::string::npos);
+        codecInfo->setRank(trait->rank);
+        (void)codecInfo->addMime(trait->mediaType.c_str());
+    }
+    return OK;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index b529940..6f88c0e 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -230,7 +230,7 @@
             }
             codecBuffer = inputBuffers[inputIndex];
 
-            MediaBuffer *mediaBuffer = NULL;
+            MediaBufferBase *mediaBuffer = NULL;
 
             err = mSource->read(&mediaBuffer, &options);
             options.clearSeekTo();
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index ee3aedb..10eb2d2 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -21,6 +21,7 @@
 #include <media/DataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/JPEGSource.h>
+#include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
@@ -108,7 +109,7 @@
 }
 
 status_t JPEGSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBufferBase **out, const ReadOptions *options) {
     *out = NULL;
 
     int64_t seekTimeUs;
@@ -117,7 +118,7 @@
         return UNKNOWN_ERROR;
     }
 
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     mGroup->acquire_buffer(&buffer);
 
     ssize_t n = mSource->readAt(mOffset, buffer->data(), mSize - mOffset);
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index 4c85b0d..cdcd657 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -85,8 +85,8 @@
 
     void extractCodecSpecificData();
 
-    void appendAACFrames(MediaBuffer *buffer);
-    void appendAVCFrame(MediaBuffer *buffer);
+    void appendAACFrames(MediaBufferBase *buffer);
+    void appendAVCFrame(MediaBufferBase *buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
 };
@@ -249,7 +249,7 @@
     notify->post();
 }
 
-void MPEG2TSWriter::SourceInfo::appendAVCFrame(MediaBuffer *buffer) {
+void MPEG2TSWriter::SourceInfo::appendAVCFrame(MediaBufferBase *buffer) {
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kNotifyBuffer);
 
@@ -279,7 +279,7 @@
     notify->post();
 }
 
-void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBuffer *buffer) {
+void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBufferBase *buffer) {
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kNotifyBuffer);
 
@@ -368,7 +368,7 @@
 
         case kWhatRead:
         {
-            MediaBuffer *buffer;
+            MediaBufferBase *buffer;
             status_t err = mSource->read(&buffer);
 
             if (err != OK && err != INFO_FORMAT_CHANGED) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 8db00f0..387cb13 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -2809,7 +2809,7 @@
     sp<MetaData> meta_data;
 
     status_t err = OK;
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     const char *trackName = getTrackType();
     while (!mDone && (err = mSource->read(&buffer)) == OK) {
         if (buffer->range_length() == 0) {
diff --git a/media/libstagefright/MediaAdapter.cpp b/media/libstagefright/MediaAdapter.cpp
index 74eb1ff..f1b6e8c 100644
--- a/media/libstagefright/MediaAdapter.cpp
+++ b/media/libstagefright/MediaAdapter.cpp
@@ -72,7 +72,7 @@
     return mOutputFormat;
 }
 
-void MediaAdapter::signalBufferReturned(MediaBuffer *buffer) {
+void MediaAdapter::signalBufferReturned(MediaBufferBase *buffer) {
     Mutex::Autolock autoLock(mAdapterLock);
     CHECK(buffer != NULL);
     buffer->setObserver(0);
@@ -82,7 +82,7 @@
 }
 
 status_t MediaAdapter::read(
-            MediaBuffer **buffer, const ReadOptions * /* options */) {
+            MediaBufferBase **buffer, const ReadOptions * /* options */) {
     Mutex::Autolock autoLock(mAdapterLock);
     if (!mStarted) {
         ALOGV("Read before even started!");
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 2b33708..7d5c63a 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -421,13 +421,33 @@
 sp<MediaCodec> MediaCodec::CreateByType(
         const sp<ALooper> &looper, const AString &mime, bool encoder, status_t *err, pid_t pid,
         uid_t uid) {
-    sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
+    Vector<AString> matchingCodecs;
+    Vector<AString> owners;
 
-    const status_t ret = codec->init(mime, true /* nameIsType */, encoder);
+    MediaCodecList::findMatchingCodecs(
+            mime.c_str(),
+            encoder,
+            0,
+            &matchingCodecs,
+            &owners);
+
     if (err != NULL) {
-        *err = ret;
+        *err = NAME_NOT_FOUND;
     }
-    return ret == OK ? codec : NULL; // NULL deallocates codec.
+    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+        sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
+        AString componentName = matchingCodecs[i];
+        status_t ret = codec->init(componentName);
+        if (err != NULL) {
+            *err = ret;
+        }
+        if (ret == OK) {
+            return codec;
+        }
+        ALOGD("Allocating component '%s' failed (%d), try next one.",
+                componentName.c_str(), ret);
+    }
+    return NULL;
 }
 
 // static
@@ -435,7 +455,7 @@
         const sp<ALooper> &looper, const AString &name, status_t *err, pid_t pid, uid_t uid) {
     sp<MediaCodec> codec = new MediaCodec(looper, pid, uid);
 
-    const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */);
+    const status_t ret = codec->init(name);
     if (err != NULL) {
         *err = ret;
     }
@@ -553,11 +573,11 @@
 }
 
 //static
-sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, bool nameIsType) {
+sp<CodecBase> MediaCodec::GetCodecBase(const AString &name) {
     static bool ccodecEnabled = property_get_bool("debug.stagefright.ccodec", false);
-    if (ccodecEnabled && !nameIsType && name.startsWithIgnoreCase("c2.")) {
+    if (ccodecEnabled && name.startsWithIgnoreCase("c2.")) {
         return new CCodec;
-    } else if (nameIsType || name.startsWithIgnoreCase("omx.")) {
+    } else if (name.startsWithIgnoreCase("omx.")) {
         // at this time only ACodec specifies a mime type.
         return new ACodec;
     } else if (name.startsWithIgnoreCase("android.filter.")) {
@@ -567,48 +587,42 @@
     }
 }
 
-status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {
+status_t MediaCodec::init(const AString &name) {
     mResourceManagerService->init();
 
     // save init parameters for reset
     mInitName = name;
-    mInitNameIsType = nameIsType;
-    mInitIsEncoder = encoder;
 
     // Current video decoders do not return from OMX_FillThisBuffer
     // quickly, violating the OpenMAX specs, until that is remedied
     // we need to invest in an extra looper to free the main event
     // queue.
 
-    mCodec = GetCodecBase(name, nameIsType);
+    mCodec = GetCodecBase(name);
     if (mCodec == NULL) {
         return NAME_NOT_FOUND;
     }
 
     bool secureCodec = false;
-    if (nameIsType && !strncasecmp(name.c_str(), "video/", 6)) {
-        mIsVideo = true;
-    } else {
-        AString tmp = name;
-        if (tmp.endsWith(".secure")) {
-            secureCodec = true;
-            tmp.erase(tmp.size() - 7, 7);
-        }
-        const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
-        if (mcl == NULL) {
-            mCodec = NULL;  // remove the codec.
-            return NO_INIT; // if called from Java should raise IOException
-        }
-        ssize_t codecIdx = mcl->findCodecByName(tmp.c_str());
-        if (codecIdx >= 0) {
-            const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx);
-            Vector<AString> mimes;
-            info->getSupportedMimes(&mimes);
-            for (size_t i = 0; i < mimes.size(); i++) {
-                if (mimes[i].startsWith("video/")) {
-                    mIsVideo = true;
-                    break;
-                }
+    AString tmp = name;
+    if (tmp.endsWith(".secure")) {
+        secureCodec = true;
+        tmp.erase(tmp.size() - 7, 7);
+    }
+    const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
+    if (mcl == NULL) {
+        mCodec = NULL;  // remove the codec.
+        return NO_INIT; // if called from Java should raise IOException
+    }
+    ssize_t codecIdx = mcl->findCodecByName(tmp.c_str());
+    if (codecIdx >= 0) {
+        const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx);
+        Vector<AString> mimes;
+        info->getSupportedMimes(&mimes);
+        for (size_t i = 0; i < mimes.size(); i++) {
+            if (mimes[i].startsWith("video/")) {
+                mIsVideo = true;
+                break;
             }
         }
     }
@@ -638,22 +652,10 @@
 
     sp<AMessage> msg = new AMessage(kWhatInit, this);
     msg->setString("name", name);
-    msg->setInt32("nameIsType", nameIsType);
-
-    if (nameIsType) {
-        msg->setInt32("encoder", encoder);
-    }
 
     if (mAnalyticsItem != NULL) {
-        if (nameIsType) {
-            // name is the mime type
-            mAnalyticsItem->setCString(kCodecMime, name.c_str());
-        } else {
-            mAnalyticsItem->setCString(kCodecCodec, name.c_str());
-        }
+        mAnalyticsItem->setCString(kCodecCodec, name.c_str());
         mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
-        if (nameIsType)
-            mAnalyticsItem->setInt32(kCodecEncoder, encoder);
     }
 
     status_t err;
@@ -719,6 +721,7 @@
         if (format->findInt32("level", &level)) {
             mAnalyticsItem->setInt32(kCodecLevel, level);
         }
+        mAnalyticsItem->setInt32(kCodecEncoder, (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
     }
 
     if (mIsVideo) {
@@ -743,8 +746,7 @@
         }
 
         // Prevent possible integer overflow in downstream code.
-        if (mInitIsEncoder
-                && (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
+        if ((uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
             ALOGE("buffer size is too big, width=%d, height=%d", mVideoWidth, mVideoHeight);
             return BAD_VALUE;
         }
@@ -1023,7 +1025,7 @@
     mHaveInputSurface = false;
 
     if (err == OK) {
-        err = init(mInitName, mInitNameIsType, mInitIsEncoder);
+        err = init(mInitName);
     }
     return err;
 }
@@ -1973,21 +1975,8 @@
             AString name;
             CHECK(msg->findString("name", &name));
 
-            int32_t nameIsType;
-            int32_t encoder = false;
-            CHECK(msg->findInt32("nameIsType", &nameIsType));
-            if (nameIsType) {
-                CHECK(msg->findInt32("encoder", &encoder));
-            }
-
             sp<AMessage> format = new AMessage;
-
-            if (nameIsType) {
-                format->setString("mime", name.c_str());
-                format->setInt32("encoder", encoder);
-            } else {
-                format->setString("componentName", name.c_str());
-            }
+            format->setString("componentName", name.c_str());
 
             mCodec->initiateAllocateComponent(format);
             break;
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 54265a4..f595646 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -29,6 +29,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/MediaDefs.h>
+#include <media/stagefright/Codec2InfoBuilder.h>
 #include <media/stagefright/MediaCodecList.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/OmxInfoBuilder.h>
@@ -77,6 +78,15 @@
 }
 
 OmxInfoBuilder sOmxInfoBuilder;
+Codec2InfoBuilder sCodec2InfoBuilder;
+
+std::initializer_list<MediaCodecListBuilderBase *> GetBuilders() {
+    if (property_get_bool("debug.stagefright.ccodec", false)) {
+        return {&sOmxInfoBuilder, &sCodec2InfoBuilder};
+    } else {
+        return {&sOmxInfoBuilder};
+    }
+}
 
 }  // unnamed namespace
 
@@ -88,7 +98,7 @@
     ALOGV("Enter profilerThreadWrapper.");
     remove(kProfilingResults);  // remove previous result so that it won't be loaded to
                                 // the new MediaCodecList
-    sp<MediaCodecList> codecList(new MediaCodecList(&sOmxInfoBuilder));
+    sp<MediaCodecList> codecList(new MediaCodecList(GetBuilders()));
     if (codecList->initCheck() != OK) {
         ALOGW("Failed to create a new MediaCodecList, skipping codec profiling.");
         return nullptr;
@@ -98,7 +108,7 @@
     ALOGV("Codec profiling started.");
     profileCodecs(infos, kProfilingResults);
     ALOGV("Codec profiling completed.");
-    codecList = new MediaCodecList(&sOmxInfoBuilder);
+    codecList = new MediaCodecList(GetBuilders());
     if (codecList->initCheck() != OK) {
         ALOGW("Failed to parse profiling results.");
         return nullptr;
@@ -116,7 +126,7 @@
     Mutex::Autolock autoLock(sInitMutex);
 
     if (sCodecList == nullptr) {
-        MediaCodecList *codecList = new MediaCodecList(&sOmxInfoBuilder);
+        MediaCodecList *codecList = new MediaCodecList(GetBuilders());
         if (codecList->initCheck() == OK) {
             sCodecList = codecList;
 
@@ -169,11 +179,28 @@
     return sRemoteList;
 }
 
-MediaCodecList::MediaCodecList(MediaCodecListBuilderBase* builder) {
+MediaCodecList::MediaCodecList(std::initializer_list<MediaCodecListBuilderBase*> builders) {
     mGlobalSettings = new AMessage();
     mCodecInfos.clear();
     MediaCodecListWriter writer(this);
-    mInitCheck = builder->buildMediaCodecList(&writer);
+    for (MediaCodecListBuilderBase *builder : builders) {
+        mInitCheck = builder->buildMediaCodecList(&writer);
+        if (mInitCheck != OK) {
+            break;
+        }
+    }
+    std::stable_sort(
+            mCodecInfos.begin(),
+            mCodecInfos.end(),
+            [](const sp<MediaCodecInfo> &info1, const sp<MediaCodecInfo> &info2) {
+                if (info2 == nullptr) {
+                    return false;
+                } else if (info1 == nullptr) {
+                    return true;
+                } else {
+                    return info1->rank() < info2->rank();
+                }
+            });
 }
 
 MediaCodecList::~MediaCodecList() {
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 04d83af..08331ad 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -59,7 +59,7 @@
     void pause();
     void resume();
     status_t setStopTimeUs(int64_t stopTimeUs);
-    bool readBuffer(MediaBuffer **buffer);
+    bool readBuffer(MediaBufferBase **buffer);
 
 protected:
     virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -86,14 +86,14 @@
         int64_t mReadPendingSince;
         bool mPaused;
         bool mPulling;
-        Vector<MediaBuffer *> mReadBuffers;
+        Vector<MediaBufferBase *> mReadBuffers;
 
         void flush();
         // if queue is empty, return false and set *|buffer| to NULL . Otherwise, pop
         // buffer from front of the queue, place it into *|buffer| and return true.
-        bool readBuffer(MediaBuffer **buffer);
+        bool readBuffer(MediaBufferBase **buffer);
         // add a buffer to the back of the queue
-        void pushBuffer(MediaBuffer *mbuf);
+        void pushBuffer(MediaBufferBase *mbuf);
     };
     Mutexed<Queue> mQueue;
 
@@ -123,11 +123,11 @@
     mLooper->stop();
 }
 
-void MediaCodecSource::Puller::Queue::pushBuffer(MediaBuffer *mbuf) {
+void MediaCodecSource::Puller::Queue::pushBuffer(MediaBufferBase *mbuf) {
     mReadBuffers.push_back(mbuf);
 }
 
-bool MediaCodecSource::Puller::Queue::readBuffer(MediaBuffer **mbuf) {
+bool MediaCodecSource::Puller::Queue::readBuffer(MediaBufferBase **mbuf) {
     if (mReadBuffers.empty()) {
         *mbuf = NULL;
         return false;
@@ -138,14 +138,14 @@
 }
 
 void MediaCodecSource::Puller::Queue::flush() {
-    MediaBuffer *mbuf;
+    MediaBufferBase *mbuf;
     while (readBuffer(&mbuf)) {
         // there are no null buffers in the queue
         mbuf->release();
     }
 }
 
-bool MediaCodecSource::Puller::readBuffer(MediaBuffer **mbuf) {
+bool MediaCodecSource::Puller::readBuffer(MediaBufferBase **mbuf) {
     Mutexed<Queue>::Locked queue(mQueue);
     return queue->readBuffer(mbuf);
 }
@@ -298,7 +298,7 @@
             }
 
             queue.unlock();
-            MediaBuffer *mbuf = NULL;
+            MediaBufferBase *mbuf = NULL;
             status_t err = mSource->read(&mbuf);
             queue.lock();
 
@@ -413,7 +413,7 @@
 }
 
 status_t MediaCodecSource::read(
-        MediaBuffer** buffer, const ReadOptions* /* options */) {
+        MediaBufferBase** buffer, const ReadOptions* /* options */) {
     Mutexed<Output>::Locked output(mOutput);
 
     *buffer = NULL;
@@ -428,7 +428,7 @@
     return output->mErrorCode;
 }
 
-void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) {
+void MediaCodecSource::signalBufferReturned(MediaBufferBase *buffer) {
     buffer->setObserver(0);
     buffer->release();
 }
@@ -636,7 +636,7 @@
         if (!reachedEOS) {
             ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio");
             // release all unread media buffers
-            for (List<MediaBuffer*>::iterator it = output->mBufferQueue.begin();
+            for (List<MediaBufferBase*>::iterator it = output->mBufferQueue.begin();
                     it != output->mBufferQueue.end(); it++) {
                 (*it)->release();
             }
@@ -682,7 +682,7 @@
 }
 
 status_t MediaCodecSource::feedEncoderInputBuffers() {
-    MediaBuffer* mbuf = NULL;
+    MediaBufferBase* mbuf = NULL;
     while (!mAvailEncoderInputIndices.empty() && mPuller->readBuffer(&mbuf)) {
         size_t bufferIndex = *mAvailEncoderInputIndices.begin();
         mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin());
@@ -906,7 +906,7 @@
                 break;
             }
 
-            MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
+            MediaBufferBase *mbuf = new MediaBuffer(outbuf->size());
             mbuf->setObserver(this);
             mbuf->add_ref();
 
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index bb72167..543c274 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -112,23 +112,25 @@
     // initialize source decryption if needed
     source->DrmInitialization(nullptr /* mime */);
 
-    sp<AMessage> meta;
-
+    void *meta = nullptr;
     MediaExtractor::CreatorFunc creator = NULL;
-    String8 tmp;
+    MediaExtractor::FreeMetaFunc freeMeta = nullptr;
     float confidence;
     sp<ExtractorPlugin> plugin;
-    creator = sniff(source.get(), &tmp, &confidence, &meta, plugin);
+    creator = sniff(source.get(), &confidence, &meta, &freeMeta, plugin);
     if (!creator) {
         ALOGV("FAILED to autodetect media content.");
         return NULL;
     }
 
-    mime = tmp.string();
-    ALOGV("Autodetected media content as '%s' with confidence %.2f",
-         mime, confidence);
-
     MediaExtractor *ret = creator(source.get(), meta);
+    if (meta != nullptr && freeMeta != nullptr) {
+        freeMeta(meta);
+    }
+
+    ALOGV("Created an extractor '%s' with confidence %.2f",
+         ret != nullptr ? ret->name() : "<null>", confidence);
+
     return CreateIMediaExtractorFromMediaExtractor(ret, source, plugin);
 }
 
@@ -165,11 +167,10 @@
 
 // static
 MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
-        DataSourceBase *source, String8 *mimeType, float *confidence, sp<AMessage> *meta,
-        sp<ExtractorPlugin> &plugin) {
-    *mimeType = "";
+        DataSourceBase *source, float *confidence, void **meta,
+        MediaExtractor::FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin) {
     *confidence = 0.0f;
-    meta->clear();
+    *meta = nullptr;
 
     std::shared_ptr<List<sp<ExtractorPlugin>>> plugins;
     {
@@ -183,16 +184,23 @@
     MediaExtractor::CreatorFunc curCreator = NULL;
     MediaExtractor::CreatorFunc bestCreator = NULL;
     for (auto it = plugins->begin(); it != plugins->end(); ++it) {
-        String8 newMimeType;
         float newConfidence;
-        sp<AMessage> newMeta;
-        if ((curCreator = (*it)->def.sniff(source, &newMimeType, &newConfidence, &newMeta))) {
+        void *newMeta = nullptr;
+        MediaExtractor::FreeMetaFunc newFreeMeta = nullptr;
+        if ((curCreator = (*it)->def.sniff(source, &newConfidence, &newMeta, &newFreeMeta))) {
             if (newConfidence > *confidence) {
-                *mimeType = newMimeType;
                 *confidence = newConfidence;
+                if (*meta != nullptr && *freeMeta != nullptr) {
+                    (*freeMeta)(*meta);
+                }
                 *meta = newMeta;
+                *freeMeta = newFreeMeta;
                 plugin = *it;
                 bestCreator = curCreator;
+            } else {
+                if (newMeta != nullptr && newFreeMeta != nullptr) {
+                    newFreeMeta(newMeta);
+                }
             }
         }
     }
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index fd51a2c..ac1f33f 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -49,20 +49,56 @@
 sp<MetaData> MakeAACCodecSpecificData(
         unsigned profile, unsigned sampling_freq_index,
         unsigned channel_configuration) {
-    int32_t sampleRate;
-    int32_t channelCount;
-    sp<ABuffer> csd = MakeAACCodecSpecificData(profile, sampling_freq_index,
-            channel_configuration, &sampleRate, &channelCount);
-    if (csd == nullptr) {
+    if(sampling_freq_index > 11u) {
         return nullptr;
     }
+    int32_t sampleRate;
+    int32_t channelCount;
+    static const int32_t kSamplingFreq[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000
+    };
+    sampleRate = kSamplingFreq[sampling_freq_index];
+    channelCount = channel_configuration;
+
+    static const uint8_t kStaticESDS[] = {
+        0x03, 22,
+        0x00, 0x00,     // ES_ID
+        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+        0x04, 17,
+        0x40,                       // Audio ISO/IEC 14496-3
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x05, 2,
+        // AudioSpecificInfo follows
+
+        // oooo offf fccc c000
+        // o - audioObjectType
+        // f - samplingFreqIndex
+        // c - channelConfig
+    };
+
+    size_t csdSize = sizeof(kStaticESDS) + 2;
+    uint8_t *csd = new uint8_t[csdSize];
+    memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
+
+    csd[sizeof(kStaticESDS)] =
+        ((profile + 1) << 3) | (sampling_freq_index >> 1);
+
+    csd[sizeof(kStaticESDS) + 1] =
+        ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
     sp<MetaData> meta = new MetaData;
     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
 
     meta->setInt32(kKeySampleRate, sampleRate);
     meta->setInt32(kKeyChannelCount, channelCount);
 
-    meta->setData(kKeyESDS, 0, csd->data(), csd->size());
+    meta->setData(kKeyESDS, 0, csd, csdSize);
+    delete [] csd;
     return meta;
 }
 
diff --git a/media/libstagefright/NdkUtils.cpp b/media/libstagefright/NdkUtils.cpp
new file mode 100644
index 0000000..904fe72
--- /dev/null
+++ b/media/libstagefright/NdkUtils.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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
+
+#include <media/stagefright/NdkUtils.h>
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+sp<MetaData> convertMediaFormatWrapperToMetaData(const sp<AMediaFormatWrapper> &fmt) {
+    sp<AMessage> msg = fmt->toAMessage();
+    sp<MetaData> meta = new MetaData;
+    convertMessageToMetaData(msg, meta);
+    return meta;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index d96f7e0..c6cbb2f 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -45,7 +45,7 @@
       mSampleTimeUs(-1ll) {
 }
 
-NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs)
+NuMediaExtractor::Sample::Sample(MediaBufferBase *buffer, int64_t timeUs)
     : mBuffer(buffer),
       mSampleTimeUs(timeUs) {
 }
@@ -488,12 +488,12 @@
     }
 
     status_t err = OK;
-    Vector<MediaBuffer *> mediaBuffers;
+    Vector<MediaBufferBase *> mediaBuffers;
     if (info->mSource->supportReadMultiple()) {
         options.setNonBlocking();
         err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
     } else {
-        MediaBuffer *mbuf = NULL;
+        MediaBufferBase *mbuf = NULL;
         err = info->mSource->read(&mbuf, &options);
         if (err == OK && mbuf != NULL) {
             mediaBuffers.push_back(mbuf);
@@ -505,7 +505,7 @@
         ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
         size_t count = mediaBuffers.size();
         for (size_t id = 0; id < count; ++id) {
-            MediaBuffer *mbuf = mediaBuffers[id];
+            MediaBufferBase *mbuf = mediaBuffers[id];
             if (mbuf != NULL) {
                 mbuf->release();
             }
@@ -517,7 +517,7 @@
     bool releaseRemaining = false;
     for (size_t id = 0; id < count; ++id) {
         int64_t timeUs;
-        MediaBuffer *mbuf = mediaBuffers[id];
+        MediaBufferBase *mbuf = mediaBuffers[id];
         if (mbuf == NULL) {
             continue;
         }
@@ -565,7 +565,8 @@
     return OK;
 }
 
-status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) {
+status_t NuMediaExtractor::appendVorbisNumPageSamples(
+        MediaBufferBase *mbuf, const sp<ABuffer> &buffer) {
     int32_t numPageSamples;
     if (!mbuf->meta_data()->findInt32(
             kKeyValidSamples, &numPageSamples)) {
diff --git a/media/libstagefright/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index a6ebadd..fe141ab 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -154,22 +154,22 @@
     // codec name -> index into swCodecs/hwCodecs
     std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>>
             swCodecName2Info, hwCodecName2Info;
-    // owner name -> MediaCodecInfo
-    // This map will be used to obtain the correct IOmx service(s) needed for
-    // creating IOmxNode instances and querying capabilities.
-    std::map<std::string, std::vector<sp<MediaCodecInfo> > >
-            owner2CodecInfo;
 
-    for (const auto& role : roles) {
-        const auto& typeName = role.type;
+    char rank[PROPERTY_VALUE_MAX];
+    uint32_t defaultRank = 0x100;
+    if (property_get("debug.stagefright.omx_default_rank", rank, nullptr)) {
+        defaultRank = std::strtoul(rank, nullptr, 10);
+    }
+    for (const IOmxStore::RoleInfo& role : roles) {
+        const hidl_string& typeName = role.type;
         bool isEncoder = role.isEncoder;
         bool preferPlatformNodes = role.preferPlatformNodes;
         // If preferPlatformNodes is true, hardware nodes must be added after
         // platform (software) nodes. hwCodecs is used to hold hardware nodes
         // that need to be added after software nodes for the same role.
         std::vector<const IOmxStore::NodeInfo*> hwCodecs;
-        for (const auto& node : role.nodes) {
-            const auto& nodeName = node.name;
+        for (const IOmxStore::NodeInfo& node : role.nodes) {
+            const hidl_string& nodeName = node.name;
             bool isSoftware = hasPrefix(nodeName, "OMX.google");
             MediaCodecInfoWriter* info;
             if (isSoftware) {
@@ -182,6 +182,7 @@
                     info->setName(nodeName.c_str());
                     info->setOwner(node.owner.c_str());
                     info->setEncoder(isEncoder);
+                    info->setRank(defaultRank);
                 } else {
                     // The node has been seen before. Simply retrieve the
                     // existing MediaCodecInfoWriter.
@@ -198,6 +199,7 @@
                         info->setName(nodeName.c_str());
                         info->setOwner(node.owner.c_str());
                         info->setEncoder(isEncoder);
+                        info->setRank(defaultRank);
                     } else {
                         // If preferPlatformNodes is true, this node must be
                         // added after all software nodes.
@@ -224,9 +226,9 @@
         // added in the loop above, but rather saved in hwCodecs. They are
         // going to be added here.
         if (preferPlatformNodes) {
-            for (const auto& node : hwCodecs) {
+            for (const IOmxStore::NodeInfo *node : hwCodecs) {
                 MediaCodecInfoWriter* info;
-                const auto& nodeName = node->name;
+                const hidl_string& nodeName = node->name;
                 auto c2i = hwCodecName2Info.find(nodeName);
                 if (c2i == hwCodecName2Info.end()) {
                     // Create a new MediaCodecInfo for a new node.
@@ -236,6 +238,7 @@
                     info->setName(nodeName.c_str());
                     info->setOwner(node->owner.c_str());
                     info->setEncoder(isEncoder);
+                    info->setRank(defaultRank);
                 } else {
                     // The node has been seen before. Simply retrieve the
                     // existing MediaCodecInfoWriter.
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 5bb0953..7efb91c 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -121,14 +121,6 @@
     return mExtractor->flags();
 }
 
-char* RemoteMediaExtractor::getDrmTrackInfo(size_t trackID, int * len) {
-    return mExtractor->getDrmTrackInfo(trackID, len);
-}
-
-void RemoteMediaExtractor::setUID(uid_t uid) {
-    return mExtractor->setUID(uid);
-}
-
 status_t RemoteMediaExtractor::setMediaCas(const HInterfaceToken &casToken) {
     return mExtractor->setMediaCas((uint8_t*)casToken.data(), casToken.size());
 }
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index 6b48ce8..d038454 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -45,7 +45,8 @@
     return mSource->getFormat();
 }
 
-status_t RemoteMediaSource::read(MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+status_t RemoteMediaSource::read(
+        MediaBufferBase **buffer, const MediaSource::ReadOptions *options) {
     return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
 }
 
diff --git a/media/libstagefright/SimpleDecodingSource.cpp b/media/libstagefright/SimpleDecodingSource.cpp
index 9b2fb4f..f93a0b7 100644
--- a/media/libstagefright/SimpleDecodingSource.cpp
+++ b/media/libstagefright/SimpleDecodingSource.cpp
@@ -200,7 +200,7 @@
 }
 
 status_t SimpleDecodingSource::read(
-        MediaBuffer **buffer, const ReadOptions *options) {
+        MediaBufferBase **buffer, const ReadOptions *options) {
     *buffer = NULL;
 
     Mutexed<ProtectedState>::Locked me(mProtectedState);
@@ -221,7 +221,7 @@
 }
 
 status_t SimpleDecodingSource::doRead(
-        Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options) {
+        Mutexed<ProtectedState>::Locked &me, MediaBufferBase **buffer, const ReadOptions *options) {
     // |me| is always locked on entry, but is allowed to be unlocked on exit
     CHECK_EQ(me->mState, STARTED);
 
@@ -267,7 +267,7 @@
                 return UNKNOWN_ERROR;
             }
 
-            MediaBuffer *in_buf;
+            MediaBufferBase *in_buf;
             while (true) {
                 in_buf = NULL;
                 me.unlock();
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
deleted file mode 100644
index d14e86b..0000000
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright (C) 2011 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 "SurfaceMediaSource"
-
-#include <inttypes.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/SurfaceMediaSource.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <OMX_IVCommon.h>
-#include <media/hardware/HardwareAPI.h>
-#include <media/hardware/MetadataBufferType.h>
-
-#include <ui/GraphicBuffer.h>
-#include <gui/BufferItem.h>
-#include <gui/ISurfaceComposer.h>
-#include <OMX_Component.h>
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <private/gui/ComposerService.h>
-
-namespace android {
-
-SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight) :
-    mWidth(bufferWidth),
-    mHeight(bufferHeight),
-    mCurrentSlot(BufferQueue::INVALID_BUFFER_SLOT),
-    mNumPendingBuffers(0),
-    mCurrentTimestamp(0),
-    mFrameRate(30),
-    mStarted(false),
-    mNumFramesReceived(0),
-    mNumFramesEncoded(0),
-    mFirstFrameTimestamp(0),
-    mMaxAcquiredBufferCount(4),  // XXX double-check the default
-    mUseAbsoluteTimestamps(false) {
-    ALOGV("SurfaceMediaSource");
-
-    if (bufferWidth == 0 || bufferHeight == 0) {
-        ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
-    }
-
-    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
-    mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight);
-    mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
-            GRALLOC_USAGE_HW_TEXTURE);
-
-    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-
-    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
-    // reference once the ctor ends, as that would cause the refcount of 'this'
-    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
-    // that's what we create.
-    wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
-    sp<BufferQueue::ProxyConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
-
-    status_t err = mConsumer->consumerConnect(proxy, false);
-    if (err != NO_ERROR) {
-        ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)",
-                strerror(-err), err);
-    }
-}
-
-SurfaceMediaSource::~SurfaceMediaSource() {
-    ALOGV("~SurfaceMediaSource");
-    CHECK(!mStarted);
-}
-
-nsecs_t SurfaceMediaSource::getTimestamp() {
-    ALOGV("getTimestamp");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTimestamp;
-}
-
-void SurfaceMediaSource::setFrameAvailableListener(
-        const sp<FrameAvailableListener>& listener) {
-    ALOGV("setFrameAvailableListener");
-    Mutex::Autolock lock(mMutex);
-    mFrameAvailableListener = listener;
-}
-
-void SurfaceMediaSource::dumpState(String8& result) const
-{
-    char buffer[1024];
-    dumpState(result, "", buffer, 1024);
-}
-
-void SurfaceMediaSource::dumpState(
-        String8& result,
-        const char* /* prefix */,
-        char* buffer,
-        size_t /* SIZE */) const
-{
-    Mutex::Autolock lock(mMutex);
-
-    result.append(buffer);
-    mConsumer->dumpState(result, "");
-}
-
-status_t SurfaceMediaSource::setFrameRate(int32_t fps)
-{
-    ALOGV("setFrameRate");
-    Mutex::Autolock lock(mMutex);
-    const int MAX_FRAME_RATE = 60;
-    if (fps < 0 || fps > MAX_FRAME_RATE) {
-        return BAD_VALUE;
-    }
-    mFrameRate = fps;
-    return OK;
-}
-
-MetadataBufferType SurfaceMediaSource::metaDataStoredInVideoBuffers() const {
-    ALOGV("isMetaDataStoredInVideoBuffers");
-    return kMetadataBufferTypeANWBuffer;
-}
-
-int32_t SurfaceMediaSource::getFrameRate( ) const {
-    ALOGV("getFrameRate");
-    Mutex::Autolock lock(mMutex);
-    return mFrameRate;
-}
-
-status_t SurfaceMediaSource::start(MetaData *params)
-{
-    ALOGV("start");
-
-    Mutex::Autolock lock(mMutex);
-
-    CHECK(!mStarted);
-
-    mStartTimeNs = 0;
-    int64_t startTimeUs;
-    int32_t bufferCount = 0;
-    if (params) {
-        if (params->findInt64(kKeyTime, &startTimeUs)) {
-            mStartTimeNs = startTimeUs * 1000;
-        }
-
-        if (!params->findInt32(kKeyNumBuffers, &bufferCount)) {
-            ALOGE("Failed to find the advertised buffer count");
-            return UNKNOWN_ERROR;
-        }
-
-        if (bufferCount <= 1) {
-            ALOGE("bufferCount %d is too small", bufferCount);
-            return BAD_VALUE;
-        }
-
-        mMaxAcquiredBufferCount = bufferCount;
-    }
-
-    CHECK_GT(mMaxAcquiredBufferCount, 1u);
-
-    status_t err =
-        mConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount);
-
-    if (err != OK) {
-        return err;
-    }
-
-    mNumPendingBuffers = 0;
-    mStarted = true;
-
-    return OK;
-}
-
-status_t SurfaceMediaSource::setMaxAcquiredBufferCount(size_t count) {
-    ALOGV("setMaxAcquiredBufferCount(%zu)", count);
-    Mutex::Autolock lock(mMutex);
-
-    CHECK_GT(count, 1u);
-    mMaxAcquiredBufferCount = count;
-
-    return OK;
-}
-
-status_t SurfaceMediaSource::setUseAbsoluteTimestamps() {
-    ALOGV("setUseAbsoluteTimestamps");
-    Mutex::Autolock lock(mMutex);
-    mUseAbsoluteTimestamps = true;
-
-    return OK;
-}
-
-status_t SurfaceMediaSource::stop()
-{
-    ALOGV("stop");
-    Mutex::Autolock lock(mMutex);
-
-    if (!mStarted) {
-        return OK;
-    }
-
-    mStarted = false;
-    mFrameAvailableCondition.signal();
-
-    while (mNumPendingBuffers > 0) {
-        ALOGI("Still waiting for %zu buffers to be returned.",
-                mNumPendingBuffers);
-
-#if DEBUG_PENDING_BUFFERS
-        for (size_t i = 0; i < mPendingBuffers.size(); ++i) {
-            ALOGI("%d: %p", i, mPendingBuffers.itemAt(i));
-        }
-#endif
-
-        mMediaBuffersAvailableCondition.wait(mMutex);
-    }
-
-    mMediaBuffersAvailableCondition.signal();
-
-    return mConsumer->consumerDisconnect();
-}
-
-sp<MetaData> SurfaceMediaSource::getFormat()
-{
-    ALOGV("getFormat");
-
-    Mutex::Autolock lock(mMutex);
-    sp<MetaData> meta = new MetaData;
-
-    meta->setInt32(kKeyWidth, mWidth);
-    meta->setInt32(kKeyHeight, mHeight);
-    // The encoder format is set as an opaque colorformat
-    // The encoder will later find out the actual colorformat
-    // from the GL Frames itself.
-    meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque);
-    meta->setInt32(kKeyStride, mWidth);
-    meta->setInt32(kKeySliceHeight, mHeight);
-    meta->setInt32(kKeyFrameRate, mFrameRate);
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
-    return meta;
-}
-
-// Pass the data to the MediaBuffer. Pass in only the metadata
-// Note: Call only when you have the lock
-void SurfaceMediaSource::passMetadataBuffer_l(MediaBuffer **buffer,
-        ANativeWindowBuffer *bufferHandle) const {
-    *buffer = new MediaBuffer(sizeof(VideoNativeMetadata));
-    VideoNativeMetadata *data = (VideoNativeMetadata *)(*buffer)->data();
-    if (data == NULL) {
-        ALOGE("Cannot allocate memory for metadata buffer!");
-        return;
-    }
-    data->eType = metaDataStoredInVideoBuffers();
-    data->pBuffer = bufferHandle;
-    data->nFenceFd = -1;
-    ALOGV("handle = %p, offset = %zu, length = %zu",
-            bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
-}
-
-status_t SurfaceMediaSource::read(
-        MediaBuffer **buffer, const ReadOptions * /* options */) {
-    ALOGV("read");
-    Mutex::Autolock lock(mMutex);
-
-    *buffer = NULL;
-
-    while (mStarted && mNumPendingBuffers == mMaxAcquiredBufferCount) {
-        mMediaBuffersAvailableCondition.wait(mMutex);
-    }
-
-    // Update the current buffer info
-    // TODO: mCurrentSlot can be made a bufferstate since there
-    // can be more than one "current" slots.
-
-    BufferItem item;
-    // If the recording has started and the queue is empty, then just
-    // wait here till the frames come in from the client side
-    while (mStarted) {
-
-        status_t err = mConsumer->acquireBuffer(&item, 0);
-        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-            // wait for a buffer to be queued
-            mFrameAvailableCondition.wait(mMutex);
-        } else if (err == OK) {
-            err = item.mFence->waitForever("SurfaceMediaSource::read");
-            if (err) {
-                ALOGW("read: failed to wait for buffer fence: %d", err);
-            }
-
-            // First time seeing the buffer?  Added it to the SMS slot
-            if (item.mGraphicBuffer != NULL) {
-                mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
-            }
-            mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
-
-            // check for the timing of this buffer
-            if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) {
-                mFirstFrameTimestamp = item.mTimestamp;
-                // Initial delay
-                if (mStartTimeNs > 0) {
-                    if (item.mTimestamp < mStartTimeNs) {
-                        // This frame predates start of record, discard
-                        mConsumer->releaseBuffer(
-                                item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY,
-                                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
-                        continue;
-                    }
-                    mStartTimeNs = item.mTimestamp - mStartTimeNs;
-                }
-            }
-            item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp);
-
-            mNumFramesReceived++;
-
-            break;
-        } else {
-            ALOGE("read: acquire failed with error code %d", err);
-            return ERROR_END_OF_STREAM;
-        }
-
-    }
-
-    // If the loop was exited as a result of stopping the recording,
-    // it is OK
-    if (!mStarted) {
-        ALOGV("Read: SurfaceMediaSource is stopped. Returning ERROR_END_OF_STREAM.");
-        return ERROR_END_OF_STREAM;
-    }
-
-    mCurrentSlot = item.mSlot;
-
-    // First time seeing the buffer?  Added it to the SMS slot
-    if (item.mGraphicBuffer != NULL) {
-        mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
-    }
-    mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
-
-    mCurrentBuffers.push_back(mSlots[mCurrentSlot].mGraphicBuffer);
-    int64_t prevTimeStamp = mCurrentTimestamp;
-    mCurrentTimestamp = item.mTimestamp;
-
-    mNumFramesEncoded++;
-    // Pass the data to the MediaBuffer. Pass in only the metadata
-
-    passMetadataBuffer_l(buffer, mSlots[mCurrentSlot].mGraphicBuffer->getNativeBuffer());
-
-    (*buffer)->setObserver(this);
-    (*buffer)->add_ref();
-    (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000);
-    ALOGV("Frames encoded = %d, timestamp = %" PRId64 ", time diff = %" PRId64,
-            mNumFramesEncoded, mCurrentTimestamp / 1000,
-            mCurrentTimestamp / 1000 - prevTimeStamp / 1000);
-
-    ++mNumPendingBuffers;
-
-#if DEBUG_PENDING_BUFFERS
-    mPendingBuffers.push_back(*buffer);
-#endif
-
-    ALOGV("returning mbuf %p", *buffer);
-
-    return OK;
-}
-
-static buffer_handle_t getMediaBufferHandle(MediaBuffer *buffer) {
-    // need to convert to char* for pointer arithmetic and then
-    // copy the byte stream into our handle
-    buffer_handle_t bufferHandle;
-    memcpy(&bufferHandle, (char*)(buffer->data()) + 4, sizeof(buffer_handle_t));
-    return bufferHandle;
-}
-
-void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
-    ALOGV("signalBufferReturned");
-
-    bool foundBuffer = false;
-
-    Mutex::Autolock lock(mMutex);
-
-    buffer_handle_t bufferHandle = getMediaBufferHandle(buffer);
-
-    for (size_t i = 0; i < mCurrentBuffers.size(); i++) {
-        if (mCurrentBuffers[i]->handle == bufferHandle) {
-            mCurrentBuffers.removeAt(i);
-            foundBuffer = true;
-            break;
-        }
-    }
-
-    if (!foundBuffer) {
-        ALOGW("returned buffer was not found in the current buffer list");
-    }
-
-    for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) {
-        if (mSlots[id].mGraphicBuffer == NULL) {
-            continue;
-        }
-
-        if (bufferHandle == mSlots[id].mGraphicBuffer->handle) {
-            ALOGV("Slot %d returned, matches handle = %p", id,
-                    mSlots[id].mGraphicBuffer->handle);
-
-            mConsumer->releaseBuffer(id, mSlots[id].mFrameNumber,
-                                        EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
-                    Fence::NO_FENCE);
-
-            buffer->setObserver(0);
-            buffer->release();
-
-            foundBuffer = true;
-            break;
-        }
-    }
-
-    if (!foundBuffer) {
-        CHECK(!"signalBufferReturned: bogus buffer");
-    }
-
-#if DEBUG_PENDING_BUFFERS
-    for (size_t i = 0; i < mPendingBuffers.size(); ++i) {
-        if (mPendingBuffers.itemAt(i) == buffer) {
-            mPendingBuffers.removeAt(i);
-            break;
-        }
-    }
-#endif
-
-    --mNumPendingBuffers;
-    mMediaBuffersAvailableCondition.broadcast();
-}
-
-// Part of the BufferQueue::ConsumerListener
-void SurfaceMediaSource::onFrameAvailable(const BufferItem& /* item */) {
-    ALOGV("onFrameAvailable");
-
-    sp<FrameAvailableListener> listener;
-    { // scope for the lock
-        Mutex::Autolock lock(mMutex);
-        mFrameAvailableCondition.broadcast();
-        listener = mFrameAvailableListener;
-    }
-
-    if (listener != NULL) {
-        ALOGV("actually calling onFrameAvailable");
-        listener->onFrameAvailable();
-    }
-}
-
-// SurfaceMediaSource hijacks this event to assume
-// the prodcuer is disconnecting from the BufferQueue
-// and that it should stop the recording
-void SurfaceMediaSource::onBuffersReleased() {
-    ALOGV("onBuffersReleased");
-
-    Mutex::Autolock lock(mMutex);
-
-    mFrameAvailableCondition.signal();
-
-    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-       mSlots[i].mGraphicBuffer = 0;
-    }
-}
-
-void SurfaceMediaSource::onSidebandStreamChanged() {
-    ALOG_ASSERT(false, "SurfaceMediaSource can't consume sideband streams");
-}
-
-} // end of namespace android
diff --git a/media/libstagefright/bqhelper/Android.bp b/media/libstagefright/bqhelper/Android.bp
index b5b4a2a..388ed6b 100644
--- a/media/libstagefright/bqhelper/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -43,6 +43,7 @@
 
     export_shared_lib_headers: [
         "libstagefright_foundation",
+        "libhidlmemory",
     ],
 
     cflags: [
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
index 6f594fd..8ddf20f 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/WGraphicBufferProducer.h
@@ -20,7 +20,6 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-#include <android-base/logging.h>
 #include <binder/Binder.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
@@ -52,6 +51,15 @@
 typedef ::android::IProducerListener BProducerListener;
 using ::android::BnGraphicBufferProducer;
 
+#ifndef LOG
+struct LOG_dummy {
+    template <typename T>
+    LOG_dummy& operator<< (const T&) { return *this; }
+};
+
+#define LOG(x)  LOG_dummy()
+#endif
+
 // Instantiate only if HGraphicBufferProducer is base of BASE.
 template <typename BASE,
           typename = typename std::enable_if<std::is_base_of<HGraphicBufferProducer, BASE>::value>::type>
diff --git a/media/libstagefright/codec2/1.0/Android.bp b/media/libstagefright/codec2/1.0/Android.bp
new file mode 100644
index 0000000..84d301a
--- /dev/null
+++ b/media/libstagefright/codec2/1.0/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+    name: "android.hardware.media.c2@1.0-service-impl",
+    // relative_install_path: "hw",
+    // TODO: vendor: true,
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+
+    srcs: [
+        //"ComponentAuth.cpp",
+        //"Component.cpp",
+        //"ComponentListener.cpp",
+        //"ComponentStore.cpp",
+        //"Configurable.cpp",
+        "InputSurface.cpp",
+        "InputSurfaceConnection.cpp",
+        //"types.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/internal",
+    ],
+
+    shared_libs: [
+        "libcutils",
+	"libgui",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libnativewindow",
+        "libstagefright_bufferqueue_helper",
+        "libstagefright_codec2_vndk",
+        "libui",
+        "libutils",
+
+        //"android.hardware.media.c2@1.0",
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hidl.token@1.0-utils",
+    ],
+}
+
diff --git a/media/libstagefright/codec2/1.0/InputSurface.cpp b/media/libstagefright/codec2/1.0/InputSurface.cpp
new file mode 100644
index 0000000..977d410
--- /dev/null
+++ b/media/libstagefright/codec2/1.0/InputSurface.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 "InputSurface"
+#include <utils/Log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2PlatformSupport.h>
+
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/codec2/1.0/InputSurface.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::GraphicBufferSource;
+
+sp<InputSurface> InputSurface::Create() {
+    sp<GraphicBufferSource> source = new GraphicBufferSource;
+    if (source->initCheck() != OK) {
+        return nullptr;
+    }
+    return new InputSurface(source->getIGraphicBufferProducer(), source);
+}
+
+InputSurface::InputSurface(
+        const sp<BGraphicBufferProducer> &base, const sp<GraphicBufferSource> &source)
+    : InputSurfaceBase(base),
+      mSource(source) {
+}
+
+sp<InputSurfaceConnection> InputSurface::connectToComponent(
+        const std::shared_ptr<C2Component> &comp) {
+    sp<InputSurfaceConnection> conn = new InputSurfaceConnection(mSource, comp);
+    if (!conn->init()) {
+        return nullptr;
+    }
+    return conn;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp b/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp
new file mode 100644
index 0000000..693eeea
--- /dev/null
+++ b/media/libstagefright/codec2/1.0/InputSurfaceConnection.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 "InputSurfaceConnection"
+#include <utils/Log.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2PlatformSupport.h>
+
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+#include <system/window.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::status_t;
+
+namespace {
+
+class Buffer2D : public C2Buffer {
+public:
+    explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {}
+};
+
+}  // namespace
+
+constexpr int32_t kBufferCount = 16;
+
+class InputSurfaceConnection::Impl : public ComponentWrapper {
+public:
+    Impl(const sp<GraphicBufferSource> &source, const std::shared_ptr<C2Component> &comp)
+        : mSource(source), mComp(comp) {
+    }
+
+    virtual ~Impl() = default;
+
+    bool init() {
+        sp<GraphicBufferSource> source = mSource.promote();
+        if (source == nullptr) {
+            return false;
+        }
+        status_t err = source->initCheck();
+        if (err != OK) {
+            ALOGE("Impl::init: GBS init failed: %d", err);
+            return false;
+        }
+        // TODO: proper color aspect & dataspace
+        android_dataspace dataSpace = HAL_DATASPACE_BT709;
+        // TODO: read settings properly from the interface
+        err = source->configure(
+                this, dataSpace, kBufferCount, 1080, 1920, GRALLOC_USAGE_SW_READ_OFTEN);
+        if (err != OK) {
+            ALOGE("Impl::init: GBS configure failed: %d", err);
+            return false;
+        }
+        for (int32_t i = 0; i < kBufferCount; ++i) {
+            if (!source->onInputBufferAdded(i).isOk()) {
+                ALOGE("Impl::init: population GBS slots failed");
+                return false;
+            }
+        }
+        if (!source->start().isOk()) {
+            ALOGE("Impl::init: GBS start failed");
+            return false;
+        }
+        c2_status_t c2err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
+                C2AllocatorStore::PLATFORM_START + 1,  // GRALLOC
+                &mAllocator);
+        if (c2err != OK) {
+            ALOGE("Impl::init: failed to fetch gralloc allocator: %d", c2err);
+            return false;
+        }
+        return true;
+    }
+
+    // From ComponentWrapper
+    status_t submitBuffer(
+            int32_t bufferId, const sp<GraphicBuffer> &buffer,
+            int64_t timestamp, int fenceFd) override {
+        ALOGV("Impl::submitBuffer bufferId = %d", bufferId);
+        // TODO: Use fd to construct fence
+        (void)fenceFd;
+
+        std::shared_ptr<C2Component> comp = mComp.lock();
+        if (!comp) {
+            return NO_INIT;
+        }
+
+        std::shared_ptr<C2GraphicAllocation> alloc;
+        C2Handle *handle = WrapNativeCodec2GrallocHandle(
+                buffer->handle, buffer->width, buffer->height,
+                buffer->format, buffer->usage, buffer->stride);
+        c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
+        if (err != OK) {
+            return UNKNOWN_ERROR;
+        }
+        std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
+
+        std::unique_ptr<C2Work> work(new C2Work);
+        work->input.flags = (C2FrameData::flags_t)0;
+        work->input.ordinal.timestamp = timestamp;
+        work->input.ordinal.frameIndex = mFrameIndex++;
+        work->input.buffers.clear();
+        std::shared_ptr<C2Buffer> c2Buffer(
+                // TODO: fence
+                new Buffer2D(block->share(
+                        C2Rect(block->width(), block->height()), ::C2Fence())),
+                [handle, bufferId, src = mSource](C2Buffer *ptr) {
+                    delete ptr;
+                    native_handle_delete(handle);
+                    sp<GraphicBufferSource> source = src.promote();
+                    if (source != nullptr) {
+                        // TODO: fence
+                        (void)source->onInputBufferEmptied(bufferId, -1);
+                    }
+                });
+        work->input.buffers.push_back(c2Buffer);
+        work->worklets.clear();
+        work->worklets.emplace_back(new C2Worklet);
+        std::list<std::unique_ptr<C2Work>> items;
+        items.push_back(std::move(work));
+
+        err = comp->queue_nb(&items);
+        if (err != C2_OK) {
+            return UNKNOWN_ERROR;
+        }
+
+        mLastTimestamp = timestamp;
+
+        return OK;
+    }
+
+    status_t submitEos(int32_t) override {
+        std::shared_ptr<C2Component> comp = mComp.lock();
+        if (!comp) {
+            return NO_INIT;
+        }
+
+        std::unique_ptr<C2Work> work(new C2Work);
+        work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
+        work->input.ordinal.timestamp = mLastTimestamp;
+        work->input.ordinal.frameIndex = mFrameIndex++;
+        work->input.buffers.clear();
+        work->worklets.clear();
+        work->worklets.emplace_back(new C2Worklet);
+        std::list<std::unique_ptr<C2Work>> items;
+        items.push_back(std::move(work));
+
+        c2_status_t err = comp->queue_nb(&items);
+        return (err == C2_OK) ? OK : UNKNOWN_ERROR;
+    }
+
+    void dispatchDataSpaceChanged(
+            int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
+        // TODO
+        (void)dataSpace;
+        (void)aspects;
+        (void)pixelFormat;
+    }
+
+private:
+    wp<GraphicBufferSource> mSource;
+    std::weak_ptr<C2Component> mComp;
+
+    // Needed for ComponentWrapper implementation
+    int64_t mLastTimestamp;
+    std::shared_ptr<C2Allocator> mAllocator;
+    std::atomic_uint64_t mFrameIndex;
+};
+
+InputSurfaceConnection::InputSurfaceConnection(
+        const sp<GraphicBufferSource> &source,
+        const std::shared_ptr<C2Component> &comp)
+    : mSource(source),
+      mImpl(new Impl(source, comp)) {
+}
+
+InputSurfaceConnection::~InputSurfaceConnection() {
+    disconnect();
+}
+
+bool InputSurfaceConnection::init() {
+    if (mImpl == nullptr) {
+        return false;
+    }
+    return mImpl->init();
+}
+
+void InputSurfaceConnection::disconnect() {
+    ALOGV("disconnect");
+    if (mSource != nullptr) {
+        (void)mSource->stop();
+        (void)mSource->release();
+    }
+    mImpl.clear();
+    mSource.clear();
+    ALOGV("disconnected");
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/codec2/Android.bp b/media/libstagefright/codec2/Android.bp
index ee5c3eb..1c32953 100644
--- a/media/libstagefright/codec2/Android.bp
+++ b/media/libstagefright/codec2/Android.bp
@@ -1,5 +1,9 @@
 cc_library_shared {
     name: "libstagefright_codec2",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     tags: [
         "optional",
@@ -21,6 +25,16 @@
         "include",
     ],
 
+    header_libs: [
+        "libhardware_headers",
+        "libutils_headers",
+    ],
+
+    export_header_lib_headers: [
+        "libhardware_headers",
+        "libutils_headers",
+    ],
+
     sanitize: {
         misc_undefined: [
             "unsigned-integer-overflow",
@@ -37,6 +51,7 @@
 
 cc_library_shared {
     name: "libstagefright_simple_c2component",
+    vendor_available: true,
 
     tags: [
         "optional",
diff --git a/media/libstagefright/codec2/C2.cpp b/media/libstagefright/codec2/C2.cpp
index a51b073..359d4e5 100644
--- a/media/libstagefright/codec2/C2.cpp
+++ b/media/libstagefright/codec2/C2.cpp
@@ -22,8 +22,6 @@
 #include <C2ParamDef.h>
 #include <C2Work.h>
 
-namespace android {
-
 /**
  * There is nothing here yet. This library is built to see what symbols and methods get
  * defined as part of the API include files.
@@ -32,5 +30,4 @@
  * Codec2 clients.
  */
 
-} // namespace android
 
diff --git a/media/libstagefright/codec2/SimpleC2Component.cpp b/media/libstagefright/codec2/SimpleC2Component.cpp
index 01e9e43..333cfeb 100644
--- a/media/libstagefright/codec2/SimpleC2Component.cpp
+++ b/media/libstagefright/codec2/SimpleC2Component.cpp
@@ -226,7 +226,9 @@
         releasing = std::move(state->mThread);
     }
     mExitRequested = true;
-    releasing.join();
+    if (releasing.joinable()) {
+        releasing.join();
+    }
     onRelease();
     return C2_OK;
 }
@@ -366,26 +368,6 @@
     }
 }
 
-namespace {
-
-class GraphicBuffer : public C2Buffer {
-public:
-    GraphicBuffer(
-            const std::shared_ptr<C2GraphicBlock> &block,
-            const C2Rect &crop)
-        : C2Buffer({ block->share(crop, ::android::C2Fence()) }) {}
-};
-
-
-class LinearBuffer : public C2Buffer {
-public:
-    LinearBuffer(
-            const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size)
-        : C2Buffer({ block->share(offset, size, ::android::C2Fence()) }) {}
-};
-
-}  // namespace
-
 std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
         const std::shared_ptr<C2LinearBlock> &block) {
     return createLinearBuffer(block, block->offset(), block->size());
@@ -393,7 +375,7 @@
 
 std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
         const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
-    return std::make_shared<LinearBuffer>(block, offset, size);
+    return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
 }
 
 std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
@@ -402,9 +384,8 @@
 }
 
 std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
-        const std::shared_ptr<C2GraphicBlock> &block,
-        const C2Rect &crop) {
-    return std::make_shared<GraphicBuffer>(block, crop);
+        const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
+    return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
 }
 
 } // namespace android
diff --git a/media/libstagefright/codec2/SimpleC2Interface.cpp b/media/libstagefright/codec2/SimpleC2Interface.cpp
index f082243..d159426 100644
--- a/media/libstagefright/codec2/SimpleC2Interface.cpp
+++ b/media/libstagefright/codec2/SimpleC2Interface.cpp
@@ -45,15 +45,38 @@
     if (heapParams) {
         heapParams->clear();
         for (const auto &index : heapParamIndices) {
-            if (index.coreIndex() != C2StreamFormatConfig::CORE_INDEX
-                    || !index.forStream()
-                    || index.stream() != 0u) {
-                heapParams->push_back(nullptr);
-            }
-            if (index.forInput()) {
-                heapParams->push_back(C2Param::Copy(mInputFormat));
-            } else {
-                heapParams->push_back(C2Param::Copy(mOutputFormat));
+            switch (index.type()) {
+                case C2StreamFormatConfig::input::PARAM_TYPE:
+                    if (index.stream() == 0u) {
+                        heapParams->push_back(C2Param::Copy(mInputFormat));
+                    } else {
+                        heapParams->push_back(nullptr);
+                    }
+                    break;
+                case C2StreamFormatConfig::output::PARAM_TYPE:
+                    if (index.stream() == 0u) {
+                        heapParams->push_back(C2Param::Copy(mOutputFormat));
+                    } else {
+                        heapParams->push_back(nullptr);
+                    }
+                    break;
+                case C2PortMimeConfig::input::PARAM_TYPE:
+                    if (mInputMediaType) {
+                        heapParams->push_back(C2Param::Copy(*mInputMediaType));
+                    } else {
+                        heapParams->push_back(nullptr);
+                    }
+                    break;
+                case C2PortMimeConfig::output::PARAM_TYPE:
+                    if (mOutputMediaType) {
+                        heapParams->push_back(C2Param::Copy(*mOutputMediaType));
+                    } else {
+                        heapParams->push_back(nullptr);
+                    }
+                    break;
+                default:
+                    heapParams->push_back(nullptr);
+                    break;
             }
         }
     }
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
index 00e3924..e90fe42 100644
--- a/media/libstagefright/codec2/include/C2.h
+++ b/media/libstagefright/codec2/include/C2.h
@@ -17,40 +17,18 @@
 #ifndef C2_H_
 #define C2_H_
 
-#include <string>
-#include <vector>
-#include <list>
-
-#ifdef __ANDROID__
-
-#include <utils/Errors.h>       // for status_t
-#include <utils/Timers.h>       // for nsecs_t
-
-namespace android {
-
-#else
-
 #include <errno.h>
-typedef int64_t nsecs_t;
 
-enum {
-    GRALLOC_USAGE_SW_READ_OFTEN,
-    GRALLOC_USAGE_RENDERSCRIPT,
-    GRALLOC_USAGE_HW_TEXTURE,
-    GRALLOC_USAGE_HW_COMPOSER,
-    GRALLOC_USAGE_HW_VIDEO_ENCODER,
-    GRALLOC_USAGE_PROTECTED,
-    GRALLOC_USAGE_SW_WRITE_OFTEN,
-    GRALLOC_USAGE_HW_RENDER,
-};
+#include <string>
 
-#endif
+/** nanoseconds with arbitrary origin. */
+typedef int64_t c2_nsecs_t;
 
 /** \mainpage Codec2
  *
- * Codec2 is a frame-based data processing API used by android.
+ * Codec2 is a generic frame-based data processing API.
  *
- * The framework accesses components via the \ref API.
+ * The media subsystem accesses components via the \ref API.
  */
 
 /** \ingroup API
@@ -109,53 +87,35 @@
  * c2_status_t: status codes used.
  */
 enum c2_status_t : int32_t {
-
 /*
- * Use android status constants if available. Otherwise, define the android status constants as
- * additional enum values using POSIX errno constants.
+ * Use POSIX errno constants.
  */
-#ifndef __ANDROID__
-    ALREADY_EXISTS      = -EEXIST,
-    BAD_VALUE           = -EINVAL,
-    BAD_INDEX           = -EOVERFLOW,
-    FAILED_TRANSACTION  = -ENOTSUP,
-    INVALID_OPERATION   = -ENOSYS,
-    NAME_NOT_FOUND      = -ENOENT,
-    NO_MEMORY           = -ENOMEM,
-    NO_INIT             = -ENODEV,
-    OK                  = 0,
-    PERMISSION_DENIED   = -EPERM,
-    TIMED_OUT           = -ETIMEDOUT,
-    UNKNOWN_ERROR       = -EFAULT,
-    UNKNOWN_TRANSACTION = -EBADMSG,
-    WOULD_BLOCK         = -EWOULDBLOCK,
-#endif
-
-    C2_OK        = OK,                   ///< operation completed successfully
+    C2_OK        = 0,            ///< operation completed successfully
 
     // bad input
-    C2_BAD_VALUE = BAD_VALUE,            ///< argument has invalid value (user error)
-    C2_BAD_INDEX = BAD_INDEX,            ///< argument uses invalid index (user error)
-    C2_CANNOT_DO = FAILED_TRANSACTION,   ///< argument/index is valid but not possible
+    C2_BAD_VALUE = EINVAL,       ///< argument has invalid value (user error)
+    C2_BAD_INDEX = ENXIO,        ///< argument uses invalid index (user error)
+    C2_CANNOT_DO = ENOTSUP,      ///< argument/index is valid but not possible
 
     // bad sequencing of events
-    C2_DUPLICATE = ALREADY_EXISTS,       ///< object already exists
-    C2_NOT_FOUND = NAME_NOT_FOUND,       ///< object not found
-    C2_BAD_STATE = INVALID_OPERATION,    ///< operation is not permitted in the current state
-    C2_BLOCKING  = WOULD_BLOCK,          ///< operation would block but blocking is not permitted
+    C2_DUPLICATE = EEXIST,       ///< object already exists
+    C2_NOT_FOUND = ENOENT,       ///< object not found
+    C2_BAD_STATE = EPERM,        ///< operation is not permitted in the current state
+    C2_BLOCKING  = EWOULDBLOCK,  ///< operation would block but blocking is not permitted
+    C2_CANCELED  = EINTR,        ///< operation interrupted/canceled
 
     // bad environment
-    C2_NO_MEMORY = NO_MEMORY,            ///< not enough memory to complete operation
-    C2_REFUSED   = PERMISSION_DENIED,    ///< missing permission to complete operation
+    C2_NO_MEMORY = ENOMEM,       ///< not enough memory to complete operation
+    C2_REFUSED   = EACCES,       ///< missing permission to complete operation
 
-    C2_TIMED_OUT = TIMED_OUT,            ///< operation did not complete within timeout
+    C2_TIMED_OUT = ETIMEDOUT,    ///< operation did not complete within timeout
 
     // bad versioning
-    C2_OMITTED   = UNKNOWN_TRANSACTION,  ///< operation is not implemented/supported (optional only)
+    C2_OMITTED   = ENOSYS,       ///< operation is not implemented/supported (optional only)
 
     // unknown fatal
-    C2_CORRUPTED = UNKNOWN_ERROR,        ///< some unexpected error prevented the operation
-    C2_NO_INIT   = NO_INIT,              ///< status has not been initialized
+    C2_CORRUPTED = EFAULT,       ///< some unexpected error prevented the operation
+    C2_NO_INIT   = ENODEV,       ///< status has not been initialized
 };
 
 /**
@@ -181,15 +141,20 @@
 /// \defgroup utils Utilities
 /// @{
 
-#define C2_DO_NOT_COPY(type, args...) \
-    type args& operator=(const type args&) = delete; \
-    type(const type args&) = delete; \
+#define C2_DO_NOT_COPY(type) \
+    type& operator=(const type &) = delete; \
+    type(const type &) = delete; \
 
-#define C2_PURE __attribute__((pure))
-#define C2_CONST __attribute__((const))
-#define C2_HIDE __attribute__((visibility("hidden")))
-#define C2_INTERNAL __attribute__((internal_linkage))
+#define C2_DEFAULT_MOVE(type) \
+    type& operator=(type &&) = default; \
+    type(type &&) = default; \
+
 #define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer")))
+#define C2_CONST    __attribute__((const))
+#define C2_HIDE     __attribute__((visibility("hidden")))
+#define C2_INTERNAL __attribute__((internal_linkage))
+#define C2_PACK     __attribute__((packed))
+#define C2_PURE     __attribute__((pure))
 
 #define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
     inline bool operator!=(const type &other) const { return !(*this == other); } \
@@ -313,7 +278,7 @@
     /**
      * Convert to a smaller counter type. This is always safe.
      */
-    template<typename U, typename E=typename std::enable_if<sizeof(U) < sizeof(T)>::type>
+    template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type>
     inline operator c2_cntr_t<U>() {
         return c2_cntr_t<U>(mValue);
     }
@@ -334,7 +299,7 @@
         return c2_cntr_t<T>(mValue op compat::get(value)); \
     } \
     \
-    template<typename U, typename E=typename std::enable_if<sizeof(U) < sizeof(T)>::type> \
+    template<typename U, typename E=typename std::enable_if<(sizeof(U) < sizeof(T))>::type> \
     attrib inline constexpr c2_cntr_t<U> operator op(const c2_cntr_t<U> &value) const { \
         return c2_cntr_t<U>(U(mValue) op value.peeku()); \
     }
@@ -548,32 +513,28 @@
 
 /// @}
 
-#ifdef __ANDROID__
-} // namespace android
-#endif
-
 #include <functional>
 template<typename T>
-struct std::less<::android::c2_cntr_t<T>> {
-    constexpr bool operator()(const ::android::c2_cntr_t<T> &lh, const ::android::c2_cntr_t<T> &rh) const {
+struct std::less<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
         return lh.peeku() < rh.peeku();
     }
 };
 template<typename T>
-struct std::less_equal<::android::c2_cntr_t<T>> {
-    constexpr bool operator()(const ::android::c2_cntr_t<T> &lh, const ::android::c2_cntr_t<T> &rh) const {
+struct std::less_equal<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
         return lh.peeku() <= rh.peeku();
     }
 };
 template<typename T>
-struct std::greater<::android::c2_cntr_t<T>> {
-    constexpr bool operator()(const ::android::c2_cntr_t<T> &lh, const ::android::c2_cntr_t<T> &rh) const {
+struct std::greater<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
         return lh.peeku() > rh.peeku();
     }
 };
 template<typename T>
-struct std::greater_equal<::android::c2_cntr_t<T>> {
-    constexpr bool operator()(const ::android::c2_cntr_t<T> &lh, const ::android::c2_cntr_t<T> &rh) const {
+struct std::greater_equal<::c2_cntr_t<T>> {
+    constexpr bool operator()(const ::c2_cntr_t<T> &lh, const ::c2_cntr_t<T> &rh) const {
         return lh.peeku() >= rh.peeku();
     }
 };
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 034075f..4bdd20f 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -18,27 +18,20 @@
 #define C2BUFFER_H_
 
 #include <C2.h>
+#include <C2BufferBase.h>
 #include <C2Param.h> // for C2Info
 
-#include <list>
 #include <memory>
+#include <vector>
 
 #ifdef __ANDROID__
-
-// #include <system/window.h>
-#include <cutils/native_handle.h>
-#include <hardware/gralloc.h> // TODO: remove
-
-typedef native_handle_t C2Handle;
-
+#include <android-C2Buffer.h>
 #else
 
 typedef void* C2Handle;
 
 #endif
 
-namespace android {
-
 /// \defgroup buffer Buffers
 /// @{
 
@@ -89,7 +82,7 @@
      * \retval C2_REFUSED       no permission to wait for the fence (unexpected - system)
      * \retval C2_CORRUPTED     some unknown error prevented waiting for the fence (unexpected)
      */
-    c2_status_t wait(nsecs_t timeoutNs);
+    c2_status_t wait(c2_nsecs_t timeoutNs);
 
     /**
      * Used to check if this fence is valid (if there is a chance for it to be signaled.)
@@ -550,41 +543,9 @@
   ALLOCATIONS
 **************************************************************************************************/
 
-/// \defgroup allocator Allocation and memory placement
+/// \ingroup allocator Allocation and memory placement
 /// @{
 
-/**
- * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
- * buffer layout.
- *
- * \note This struct has public fields without getters/setters. All methods are inline.
- */
-struct C2MemoryUsage {
-// public:
-    // TODO: match these to gralloc1.h
-    enum Consumer : uint64_t {
-        // \todo do we need to distinguish often from rarely?
-        CPU_READ          = GRALLOC_USAGE_SW_READ_OFTEN,
-        RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
-        HW_TEXTURE_READ   = GRALLOC_USAGE_HW_TEXTURE,
-        HW_COMPOSER_READ  = GRALLOC_USAGE_HW_COMPOSER,
-        HW_CODEC_READ     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
-        READ_PROTECTED    = GRALLOC_USAGE_PROTECTED,
-    };
-
-    enum Producer : uint64_t {
-        CPU_WRITE          = GRALLOC_USAGE_SW_WRITE_OFTEN,
-        RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
-        HW_TEXTURE_WRITE   = GRALLOC_USAGE_HW_RENDER,
-        HW_COMPOSER_WRITE  = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
-        HW_CODEC_WRITE     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
-        WRITE_PROTECTED    = GRALLOC_USAGE_PROTECTED,
-    };
-
-    uint64_t consumer; // e.g. input
-    uint64_t producer; // e.g. output
-};
-
 class C2LinearAllocation;
 class C2GraphicAllocation;
 
@@ -785,19 +746,19 @@
     /**
      * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
      * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
-     * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
-     * safe to access the buffer contents, then -1.
+     * |fence| will contain an acquire sync fence object. If it is already
+     * safe to access the buffer contents, then it will contain an empty (already fired) fence.
      *
-     * \param offset          starting position of the portion to be mapped (this does not have to
+     * \param offset        starting position of the portion to be mapped (this does not have to
      *                      be page aligned)
-     * \param size            size of the portion to be mapped (this does not have to be page
+     * \param size          size of the portion to be mapped (this does not have to be page
      *                      aligned)
-     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
+     * \param usage         the desired usage. \todo this must be kSoftwareRead and/or
      *                      kSoftwareWrite.
-     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
-     * \param addr            a pointer to where the starting address of the mapped portion will be
+     * \param fence         a pointer to a fence object if an async mapping is requested. If
+     *                      not-null, and acquire fence will be stored here on success, or empty
+     *                      fence on failure. If null, the mapping will be synchronous.
+     * \param addr          a pointer to where the starting address of the mapped portion will be
      *                      stored. On failure, nullptr will be stored here.
      *
      * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
@@ -814,19 +775,19 @@
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
      */
     virtual c2_status_t map(
-            size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
+            size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence /* nullable */,
             void **addr /* nonnull */) = 0;
 
     /**
      * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
-     * passed to |map|; otherwise, this operation is a no-op.
+     * passed to and returned by |map|; otherwise, this operation is a no-op.
      *
-     * \param addr            starting address of the mapped region
-     * \param size            size of the mapped region
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
+     * \param addr          starting address of the mapped region
+     * \param size          size of the mapped region
+     * \param fence         a pointer to a fence object if an async unmapping is requested. If
+     *                      not-null, a release fence will be stored here on success, or empty fence
      *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped region. If null, the unmapping
+     *                      all changes that happened to the mapped region. If null, the unmapping
      *                      will be synchronous.
      *
      * \retval C2_OK        the operation was successful
@@ -837,7 +798,7 @@
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
      * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
      */
-    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
+    virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fence /* nullable */) = 0;
 
     /**
      * Returns the allocator ID for this allocation. This is useful to put the handle into context.
@@ -1378,6 +1339,9 @@
     uint32_t width;
     uint32_t height;
 
+    constexpr inline C2Rect()
+        : C2Rect(0, 0, 0, 0) { }
+
     constexpr inline C2Rect(uint32_t width_, uint32_t height_)
         : C2Rect(width_, height_, 0, 0) { }
 
@@ -1546,6 +1510,15 @@
         BIG_END,    // BIG_ENDIAN is a reserved macro
     } endianness; ///< endianness of the samples
 
+    /**
+     * The following two fields define the relation between multiple planes. If multiple planes are
+     * interleaved, they share a root plane (whichever plane's start address is the lowest), and
+     * |offset| is the offset of this plane inside the root plane (in bytes). |rootIx| is the index
+     * of the root plane. If a plane is independent, rootIx is its index and offset is 0.
+     */
+    uint32_t rootIx; ///< index of the root plane
+    uint32_t offset; ///< offset of this plane inside of the root plane
+
     inline constexpr ssize_t minOffset(uint32_t width, uint32_t height) const {
         ssize_t offs = 0;
         if (width > 0 && colInc < 0) {
@@ -1580,7 +1553,8 @@
     };
 
     type_t type;                    // image type
-    uint32_t numPlanes;             // number of planes
+    uint32_t numPlanes;             // number of component planes
+    uint32_t rootPlanes;            // number of layout planes (root planes)
 
     enum plane_index_t : uint32_t {
         PLANE_Y = 0,
@@ -1732,22 +1706,19 @@
      * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
      * memory for flexible access. On success, it fills out |layout| with the plane specifications
      * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
-     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
-     * descriptor referring to an acquire sync fence object. If it is already safe to access the
-     * buffer contents, then -1.
+     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fence| will contain
+     * an acquire sync fence object. If it is already safe to access the
+     * buffer contents, then it will be an empty (already fired) fence.
      *
-     * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffse()/
+     * Safe regions for the pointer addresses returned can be gotten via C2LayoutInfo.minOffset()/
      * maxOffset().
      *
-     * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
-     * from gralloc1 limitation.)
-     *
      * \param rect          section to be mapped (this does not have to be aligned)
      * \param usage         the desired usage. \todo this must be kSoftwareRead and/or
      *                      kSoftwareWrite.
-     * \param fenceFd       a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
+     * \param fence         a pointer to a fence object if an async mapping is requested. If
+     *                      not-null, and acquire fence will be stored here on success, or empty
+     *                      fence on failure. If null, the mapping will be synchronous.
      * \param layout        a pointer to where the mapped planes' descriptors will be
      *                      stored. On failure, nullptr will be stored here.
      * \param addr          pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
@@ -1755,7 +1726,8 @@
      *
      * \retval C2_OK        the operation was successful
      * \retval C2_REFUSED   no permission to map the section
-     * \retval C2_DUPLICATE there is already a mapped region (caller error)
+     * \retval C2_DUPLICATE there is already a mapped region and this allocation cannot support
+     *                      multi-mapping (caller error)
      * \retval C2_TIMED_OUT the operation timed out
      * \retval C2_NO_MEMORY not enough memory to complete the operation
      * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
@@ -1764,25 +1736,30 @@
 
      */
     virtual c2_status_t map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
             C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
 
     /**
-     * Unmaps the last mapped rectangular section.
+     * Unmaps a section of an allocation at |addr| with |rect|. These must be parameters previously
+     * passed to and returned by |map|; otherwise, this operation is a no-op.
      *
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
+     * \param addr          pointer to an array with at least C2PlanarLayout::MAX_NUM_PLANES
+     *                      elements containing the starting addresses of the mapped layers
+     * \param rect          boundaries of the mapped section
+     * \param fence         a pointer to a fence object if an async unmapping is requested. If
+     *                      not-null, a release fence will be stored here on success, or empty fence
      *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped section. If null, the unmapping
+     *                      all changes that happened to the mapped section. If null, the unmapping
      *                      will be synchronous.
      *
      * \retval C2_OK        the operation was successful
      * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NOT_FOUND there is no mapped region (caller error)
+     * \retval C2_NOT_FOUND there is no such mapped region (caller error)
      * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
      * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
      */
-    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
+    virtual c2_status_t unmap(
+            uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) = 0;
 
     /**
      * Returns the allocator ID for this allocation. This is useful to put the handle into context.
@@ -2301,6 +2278,4 @@
 
 /// @}
 
-}  // namespace android
-
 #endif  // C2BUFFER_H_
diff --git a/media/libstagefright/codec2/include/C2BufferBase.h b/media/libstagefright/codec2/include/C2BufferBase.h
new file mode 100644
index 0000000..68411f2
--- /dev/null
+++ b/media/libstagefright/codec2/include/C2BufferBase.h
@@ -0,0 +1,94 @@
+/*
+ * 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 C2BUFFER_BASE_H_
+#define C2BUFFER_BASE_H_
+
+/// \defgroup allocator Allocation and memory placement
+/// @{
+
+/**
+ * Buffer/memory usage bits. These shall be used by the allocators to select optimal memory type/
+ * pool and buffer layout. Usage bits are conceptually separated into read and write usage, while
+ * the buffer use life-cycle is separated into producers (writers) and consumers (readers).
+ * These two concepts are related but not equivalent: consumers may only read buffers and only
+ * producers may write to buffers; note, however, that buffer producers may also want or need to
+ * read the buffers.
+ *
+ * Read and write buffer usage bits shall be or-ed to arrive at the full buffer usage. Admittedly,
+ * this does not account for the amount of reading and writing (e.g. a buffer may have one or more
+ * readers); however, the proper information necessary to properly weigh the various usages would be
+ * the amount of data read/written for each usage type. This would result in an integer array of
+ * size 64 (or the number of distinct usages) for memory usage, and likely such detailed information
+ * would not always be available.
+ *
+ * That platform-agnostic Codec 2.0 API only defines the bare minimum usages. Platforms shall define
+ * usage bits that are appropriate for the platform.
+ */
+struct C2MemoryUsage {
+// public:
+    /**
+     * Buffer read usage.
+     */
+    enum Read : uint64_t {
+        /** Buffer is read by the CPU. */
+        CPU_READ        = 1 << 0,
+        /**
+         * Buffer shall only be read by trusted hardware. The definition of trusted hardware is
+         * platform specific, but this flag is reserved to prevent mapping this block into CPU
+         * readable memory resulting in bus fault. This flag can be used when buffer access must be
+         * protected.
+         */
+        READ_PROTECTED  = 1 << 1,
+    };
+
+    /**
+     * Buffer write usage.
+     */
+    enum Write : uint64_t {
+        /** Buffer is writted to by the CPU. */
+        CPU_WRITE        = 1 << 2,
+        /**
+         * Buffer shall only be written to by trusted hardware. The definition of trusted hardware
+         * is platform specific, but this flag is reserved to prevent mapping this block into CPU
+         * writable memory resulting in bus fault. This flag can be used when buffer integrity must
+         * be protected.
+         */
+        WRITE_PROTECTED  = 1 << 3,
+    };
+
+    enum : uint64_t {
+        /**
+         * Buffer usage bits reserved for the platform. We don't separately reserve read and
+         * write usages as platforms may have asymmetric distribution between them.
+         */
+        PLATFORM_MASK     = ~(CPU_READ | CPU_WRITE | READ_PROTECTED | WRITE_PROTECTED),
+    };
+
+    /** Create a usage from separate consumer and producer usage mask. \deprecated */
+    inline C2MemoryUsage(uint64_t consumer, uint64_t producer)
+        : expected(consumer | producer) { }
+
+    inline explicit C2MemoryUsage(uint64_t expected_)
+        : expected(expected_) { }
+
+    uint64_t expected; // expected buffer usage
+};
+
+/// @}
+
+#endif  // C2BUFFER_BASE_H_
+
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index 721966b..dbcd82d 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -29,36 +29,38 @@
 #include <C2Param.h>
 #include <C2Work.h>
 
-namespace android {
-
 /// \defgroup components Components
 /// @{
 
-class C2Component;
-
 struct C2FieldSupportedValuesQuery {
     enum type_t : uint32_t {
         POSSIBLE, ///< query all possible values regardless of other settings
         CURRENT,  ///< query currently possible values given dependent settings
     };
 
-    const C2ParamField field;
-    const type_t type;
+private:
+    C2ParamField _mField;
+    type_t _mType;
+public:
     c2_status_t status;
     C2FieldSupportedValues values;
 
     C2FieldSupportedValuesQuery(const C2ParamField &field_, type_t type_)
-        : field(field_), type(type_), status(C2_NO_INIT) { }
+        : _mField(field_), _mType(type_), status(C2_NO_INIT) { }
 
-    static C2FieldSupportedValuesQuery&&
+    static C2FieldSupportedValuesQuery
     Current(const C2ParamField &field_) {
-        return std::move(C2FieldSupportedValuesQuery(field_, CURRENT));
+        return C2FieldSupportedValuesQuery(field_, CURRENT);
     }
 
-    static C2FieldSupportedValuesQuery&&
+    static C2FieldSupportedValuesQuery
     Possible(const C2ParamField &field_) {
-        return std::move(C2FieldSupportedValuesQuery(field_, POSSIBLE));
+        return C2FieldSupportedValuesQuery(field_, POSSIBLE);
     }
+
+    inline C2ParamField field() const { return _mField; };
+
+    inline type_t type() const { return _mType; }
 };
 
 /**
@@ -396,7 +398,7 @@
         domain_t domain; ///< component domain (e.g. audio or video)
         kind_t kind; ///< component kind (e.g. encoder, decoder or filter)
         rank_t rank; ///< rank used to determine component ordering (the lower the sooner)
-        C2StringLiteral mediaType; ///< media type supported by the component
+        C2String mediaType; ///< media type supported by the component
 
         /**
          * name alias(es) for backward compatibility.
@@ -947,6 +949,4 @@
 
 /// @}
 
-}  // namespace android
-
 #endif  // C2COMPONENT_H_
diff --git a/media/libstagefright/codec2/include/C2Config.h b/media/libstagefright/codec2/include/C2Config.h
index 2a2b9de..3f149bb 100644
--- a/media/libstagefright/codec2/include/C2Config.h
+++ b/media/libstagefright/codec2/include/C2Config.h
@@ -19,8 +19,6 @@
 
 #include <C2ParamDef.h>
 
-namespace android {
-
 /// \defgroup config Component configuration
 /// @{
 
@@ -262,6 +260,4 @@
 
 /// @}
 
-} // namespace android
-
 #endif
diff --git a/media/libstagefright/codec2/include/C2Param.h b/media/libstagefright/codec2/include/C2Param.h
index 4d9f707..e0a743c 100644
--- a/media/libstagefright/codec2/include/C2Param.h
+++ b/media/libstagefright/codec2/include/C2Param.h
@@ -23,13 +23,10 @@
 #include <stdint.h>
 
 #include <algorithm>
-#include <list>
 #include <string>
 #include <type_traits>
-
-#define C2_PACK __attribute__((packed))
-
-namespace android {
+#include <utility>
+#include <vector>
 
 /// \addtogroup Parameters
 /// @{
@@ -89,7 +86,6 @@
  */
 
 /// \ingroup internal
-struct _C2ParamManipulator;
 
 /**
  * Parameter base class.
@@ -303,7 +299,7 @@
         DEFINE_FIELD_BASED_COMPARISON_OPERATORS(Index, mIndex)
 
     private:
-        friend struct C2Param;           // for setStream, makeStreamId, isValid
+        friend struct C2Param;           // for setStream, MakeStreamId, isValid
         friend struct _C2ParamInspector; // for testing
 
         /**
@@ -324,7 +320,7 @@
 
         /// returns the streamId bitfield for a given |stream|. If stream is invalid,
         /// returns an invalid bitfield.
-        inline static uint32_t makeStreamId(unsigned stream) {
+        inline static uint32_t MakeStreamId(unsigned stream) {
             // saturate stream ID (max value is invalid)
             if (stream > MAX_STREAM_ID) {
                 stream = MAX_STREAM_ID;
@@ -338,7 +334,7 @@
          */
         inline bool setStream(unsigned stream) {
             if (forStream()) {
-                mIndex = (mIndex & ~STREAM_ID_MASK) | makeStreamId(stream);
+                mIndex = (mIndex & ~STREAM_ID_MASK) | MakeStreamId(stream);
                 return this->stream() < MAX_STREAM_ID;
             }
             return false;
@@ -459,7 +455,7 @@
     // allow undefined or different direction (e.g. as constructed from C2PortParam() vs.
     // C2PortParam::input), but still require equivalent type (stream, port or global); otherwise,
     // return null.
-    inline static const C2Param* ifSuitable(
+    inline static const C2Param* IfSuitable(
             const C2Param* o, size_t size, Type type, size_t flexSize = 0, bool checkDir = true) {
         if (o == nullptr || o->_mSize < size || (flexSize && ((o->_mSize - size) % flexSize))) {
             return nullptr;
@@ -484,7 +480,7 @@
     /// base constructor with stream set
     inline C2Param(uint32_t paramSize, Index paramIndex, unsigned stream)
         : _mSize(paramSize),
-          _mIndex(paramIndex | Index::makeStreamId(stream)) {
+          _mIndex(paramIndex | Index::MakeStreamId(stream)) {
         if (paramSize > sizeof(C2Param)) {
             memset(this + 1, 0, paramSize - sizeof(C2Param));
         }
@@ -668,7 +664,7 @@
     template<typename S, typename T>
     inline C2ParamField(S* param, T* offset)
         : _mIndex(param->index()),
-          _mFieldId(offset) {}
+          _mFieldId((T*)((uintptr_t)offset - (uintptr_t)param)) {}
 
     /**
      * Create a field identifier using a configuration parameter (variable),
@@ -702,7 +698,7 @@
      */
     template<typename S>
     inline C2ParamField(S* param)
-        : _mIndex(param->index()), _mFieldId(0u, param->size()) {}
+        : _mIndex(param->index()), _mFieldId(0u, param->size()) { }
 
     /**
      * Equality operator.
@@ -733,44 +729,33 @@
 };
 
 /**
- * Structure uniquely specifying a field, an array element of a field, or a
- * parameter in a configuration
- */
-struct C2ParamOrField : public C2ParamField {
-//public:
-    template<typename S>
-    inline C2ParamOrField(S* param)
-        : C2ParamField(param->index(), 0u, param->size()) {}
-};
-
-/**
  * A shared (union) representation of numeric values
  */
 class C2Value {
 public:
     /// A union of supported primitive types.
     union Primitive {
-        int32_t     i32;   ///< int32_t value
-        uint32_t    u32;   ///< uint32_t value
-        c2_cntr32_t c32;   ///< c2_cntr32_t value
-        int64_t     i64;   ///< int64_t value
+        // first member is always zero initialized so it must be the largest
         uint64_t    u64;   ///< uint64_t value
+        int64_t     i64;   ///< int64_t value
         c2_cntr64_t c64;   ///< c2_cntr64_t value
+        uint32_t    u32;   ///< uint32_t value
+        int32_t     i32;   ///< int32_t value
+        c2_cntr32_t c32;   ///< c2_cntr32_t value
         float       fp;    ///< float value
 
         // constructors - implicit
-        Primitive(int32_t value)     : i32(value) { }
-        Primitive(uint32_t value)    : u32(value) { }
-        Primitive(c2_cntr32_t value) : c32(value) { }
-        Primitive(int64_t value)     : i64(value) { }
         Primitive(uint64_t value)    : u64(value) { }
+        Primitive(int64_t value)     : i64(value) { }
         Primitive(c2_cntr64_t value) : c64(value) { }
+        Primitive(uint32_t value)    : u32(value) { }
+        Primitive(int32_t value)     : i32(value) { }
+        Primitive(c2_cntr32_t value) : c32(value) { }
         Primitive(float value)       : fp(value)  { }
 
         Primitive() : u64(0) { }
 
-    private:
-        friend class C2Value;
+        /** gets value out of the union */
         template<typename T> const T &ref() const;
     };
 
@@ -857,9 +842,9 @@
         STRUCT_FLAG = 0x20000, ///< structs. Marked with this flag in addition to their coreIndex.
     };
 
-    typedef std::pair<C2String, C2Value::Primitive> named_value_type;
-    typedef std::vector<const named_value_type> named_values_type;
-    //typedef std::pair<std::vector<C2String>, std::vector<C2Value::Primitive>> named_values_type;
+    typedef std::pair<C2String, C2Value::Primitive> NamedValueType;
+    typedef std::vector<const NamedValueType> NamedValuesType;
+    //typedef std::pair<std::vector<C2String>, std::vector<C2Value::Primitive>> NamedValuesType;
 
     /**
      * Template specialization that returns the named values for a type.
@@ -869,15 +854,15 @@
      * \return a vector of name-value pairs.
      */
     template<typename B>
-    static named_values_type namedValuesFor(const B &);
+    static NamedValuesType namedValuesFor(const B &);
 
-    inline C2FieldDescriptor(uint32_t type, uint32_t length, C2StringLiteral name, size_t offset, size_t size)
-        : _mType((type_t)type), _mLength(length), _mName(name), _mFieldId(offset, size) { }
+    inline C2FieldDescriptor(uint32_t type, uint32_t extent, C2StringLiteral name, size_t offset, size_t size)
+        : _mType((type_t)type), _mExtent(extent), _mName(name), _mFieldId(offset, size) { }
 
     template<typename T, class B=typename std::remove_extent<T>::type>
     inline C2FieldDescriptor(const T* offset, const char *name)
-        : _mType(this->getType((B*)nullptr)),
-          _mLength(std::is_array<T>::value ? std::extent<T>::value : 1),
+        : _mType(this->GetType((B*)nullptr)),
+          _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
           _mName(name),
           _mNamedValues(namedValuesFor(*(B*)0)),
           _mFieldId(offset) {}
@@ -885,8 +870,8 @@
 /*
     template<typename T, typename B=typename std::remove_extent<T>::type>
     inline C2FieldDescriptor<T, B, false>(T* offset, const char *name)
-        : _mType(this->getType((B*)nullptr)),
-          _mLength(std::is_array<T>::value ? std::extent<T>::value : 1),
+        : _mType(this->GetType((B*)nullptr)),
+          _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
           _mName(name),
           _mFieldId(offset) {}
 */
@@ -894,8 +879,8 @@
     /// \deprecated
     template<typename T, typename S, class B=typename std::remove_extent<T>::type>
     constexpr inline C2FieldDescriptor(S*, T S::* field, const char *name)
-        : _mType(this->getType((B*)nullptr)),
-          _mLength(std::is_array<T>::value ? std::extent<T>::value : 1),
+        : _mType(this->GetType((B*)nullptr)),
+          _mExtent(std::is_array<T>::value ? std::extent<T>::value : 1),
           _mName(name),
           _mFieldId(&(((S*)0)->*field)) {}
 
@@ -903,11 +888,11 @@
     inline type_t type() const { return _mType; }
     /// returns the length of the field in case it is an array. Returns 0 for
     /// T[] arrays, returns 1 for T[1] arrays as well as if the field is not an array.
-    inline size_t length() const { return _mLength; }
+    inline size_t extent() const { return _mExtent; }
     /// returns the name of the field
     inline C2StringLiteral name() const { return _mName; }
 
-    const named_values_type &namedValues() const { return _mNamedValues; }
+    const NamedValuesType &namedValues() const { return _mNamedValues; }
 
 #if defined(FRIEND_TEST)
     friend void PrintTo(const C2FieldDescriptor &, ::std::ostream*);
@@ -916,49 +901,51 @@
 #endif
 
 private:
-    const type_t _mType;
-    const uint32_t _mLength; // the last member can be arbitrary length if it is T[] array,
+    type_t _mType;
+    uint32_t _mExtent; // the last member can be arbitrary length if it is T[] array,
                        // extending to the end of the parameter (this is marked with
                        // 0). T[0]-s are not fields.
-    const C2StringLiteral _mName;
-    const named_values_type _mNamedValues;
+    C2StringLiteral _mName;
+    NamedValuesType _mNamedValues;
 
-    const _C2FieldId _mFieldId;   // field identifier (offset and size)
+    _C2FieldId _mFieldId;   // field identifier (offset and size)
 
     // NOTE: We do not capture default value(s) here as that may depend on the component.
     // NOTE: We also do not capture bestEffort, as 1) this should be true for most fields,
     // 2) this is at parameter granularity.
 
     // type resolution
-    inline static type_t getType(int32_t*)     { return INT32; }
-    inline static type_t getType(uint32_t*)    { return UINT32; }
-    inline static type_t getType(c2_cntr32_t*) { return CNTR32; }
-    inline static type_t getType(int64_t*)     { return INT64; }
-    inline static type_t getType(uint64_t*)    { return UINT64; }
-    inline static type_t getType(c2_cntr64_t*) { return CNTR64; }
-    inline static type_t getType(float*)       { return FLOAT; }
-    inline static type_t getType(char*)        { return STRING; }
-    inline static type_t getType(uint8_t*)     { return BLOB; }
+    inline static type_t GetType(int32_t*)     { return INT32; }
+    inline static type_t GetType(uint32_t*)    { return UINT32; }
+    inline static type_t GetType(c2_cntr32_t*) { return CNTR32; }
+    inline static type_t GetType(int64_t*)     { return INT64; }
+    inline static type_t GetType(uint64_t*)    { return UINT64; }
+    inline static type_t GetType(c2_cntr64_t*) { return CNTR64; }
+    inline static type_t GetType(float*)       { return FLOAT; }
+    inline static type_t GetType(char*)        { return STRING; }
+    inline static type_t GetType(uint8_t*)     { return BLOB; }
 
     template<typename T,
              class=typename std::enable_if<std::is_enum<T>::value>::type>
-    inline static type_t getType(T*) {
+    inline static type_t GetType(T*) {
         typename std::underlying_type<T>::type underlying(0);
-        return getType(&underlying);
+        return GetType(&underlying);
     }
 
     // verify C2Struct by having a FIELD_LIST and a CORE_INDEX.
     template<typename T,
              class=decltype(T::CORE_INDEX + 1), class=decltype(T::FIELD_LIST)>
-    inline static type_t getType(T*) {
+    inline static type_t GetType(T*) {
         static_assert(!std::is_base_of<C2Param, T>::value, "cannot use C2Params as fields");
         return (type_t)(T::CORE_INDEX | STRUCT_FLAG);
     }
+
+    friend struct _C2ParamInspector;
 };
 
 #define DEFINE_NO_NAMED_VALUES_FOR(type) \
-template<> inline C2FieldDescriptor::named_values_type C2FieldDescriptor::namedValuesFor(const type &) { \
-    return named_values_type(); \
+template<> inline C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const type &) { \
+    return NamedValuesType(); \
 }
 
 // We cannot subtype constructor for enumerated types so insted define no named values for
@@ -1031,6 +1018,14 @@
      */
     inline bool isPersistent() const { return _mAttrib & IS_PERSISTENT; }
 
+    inline bool isStrict() const { return _mAttrib & IS_STRICT; }
+
+    inline bool isReadOnly() const { return _mAttrib & IS_READ_ONLY; }
+
+    inline bool isVisible() const { return !(_mAttrib & IS_HIDDEN); }
+
+    inline bool isPublic() const { return !(_mAttrib & IS_INTERNAL); }
+
     /// Returns the name of this param.
     /// This defaults to the underlying C2Struct's name, but could be altered for a component.
     inline C2String name() const { return _mName; }
@@ -1039,31 +1034,52 @@
     inline C2Param::Index index() const { return _mIndex; }
 
     /// Returns the indices of parameters that this parameter has a dependency on
-    inline const std::vector<C2Param::Index> &dependencies() const { return mDependencies; }
+    inline const std::vector<C2Param::Index> &dependencies() const { return _mDependencies; }
 
-    // TODO: add more constructors that allow setting dependencies and attributes
-
+    /// \deprecated
     template<typename T>
     inline C2ParamDescriptor(bool isRequired, C2StringLiteral name, const T*)
         : _mIndex(T::PARAM_TYPE),
           _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
           _mName(name) { }
 
+    /// \deprecated
     inline C2ParamDescriptor(
             bool isRequired, C2StringLiteral name, C2Param::Index index)
         : _mIndex(index),
           _mAttrib(IS_PERSISTENT | (isRequired ? IS_REQUIRED : 0)),
           _mName(name) { }
 
-private:
     enum attrib_t : uint32_t {
-        IS_REQUIRED   = 1u << 0,
-        IS_PERSISTENT = 1u << 1,
+        // flags that default on
+        IS_REQUIRED   = 1u << 0, ///< parameter is required to be specified
+        IS_PERSISTENT = 1u << 1, ///< parameter retains its value
+        // flags that default off
+        IS_STRICT     = 1u << 2, ///< parameter is strict
+        IS_READ_ONLY  = 1u << 3, ///< parameter is publicly read-only
+        IS_HIDDEN     = 1u << 4, ///< parameter shall not be visible to clients
+        IS_INTERNAL   = 1u << 5, ///< parameter shall not be used by framework (other than testing)
     };
+
+    inline C2ParamDescriptor(
+        C2Param::Index index, attrib_t attrib, C2StringLiteral name)
+        : _mIndex(index),
+          _mAttrib(attrib),
+          _mName(name) { }
+
+    inline C2ParamDescriptor(
+        C2Param::Index index, attrib_t attrib, C2String &&name,
+        std::vector<C2Param::Index> &&dependencies)
+        : _mIndex(index),
+          _mAttrib(attrib),
+          _mName(name),
+          _mDependencies(std::move(dependencies)) { }
+
+private:
     const C2Param::Index _mIndex;
     const uint32_t _mAttrib;
     const C2String _mName;
-    std::vector<C2Param::Index> mDependencies;
+    std::vector<C2Param::Index> _mDependencies;
 
     friend struct _C2ParamInspector;
 };
@@ -1153,7 +1169,7 @@
  *  private:
  *      // may have private constructors taking number of widths as the first argument
  *      // This is used by the C2Param factory methods, e.g.
- *      //   C2VideoFlexWidthsGlobalParam::alloc_unique(size_t, int32_t);
+ *      //   C2VideoFlexWidthsGlobalParam::AllocUnique(size_t, int32_t);
  *      C2VideoFlexWidthsStruct(size_t flexCount, int32_t value) {
  *          for (size_t i = 0; i < flexCount; ++i) {
  *              widths[i] = value;
@@ -1163,7 +1179,7 @@
  *      // If the last argument is T[N] or std::initializer_list<T>, the flexCount will
  *      // be automatically calculated and passed by the C2Param factory methods, e.g.
  *      //   int widths[] = { 1, 2, 3 };
- *      //   C2VideoFlexWidthsGlobalParam::alloc_unique(widths);
+ *      //   C2VideoFlexWidthsGlobalParam::AllocUnique(widths);
  *      template<unsigned N>
  *      C2VideoFlexWidthsStruct(size_t flexCount, const int32_t(&init)[N]) {
  *          for (size_t i = 0; i < flexCount; ++i) {
@@ -1276,7 +1292,7 @@
      *  descriptions, but we want to conserve memory if client only wants the description
      *  of a few indices.
      */
-    virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) = 0;
+    virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const = 0;
 
 protected:
     virtual ~C2ParamReflector() = default;
@@ -1285,9 +1301,9 @@
 /**
  * Generic supported values for a field.
  *
- * This can be either a range or a set of values. The range can be linear or geometric with a
- * clear minimum and maximum value, and can have an optional step size or geometric ratio. Values
- * can optionally represent flags.
+ * This can be either a range or a set of values. The range can be a simple range, an arithmetic,
+ * geometric or multiply-accumulate series with a clear minimum and maximum value. Values can
+ * be discrete values, or can optionally represent flags to be or-ed.
  *
  * \note Do not use flags to represent bitfields. Use individual values or separate fields instead.
  */
@@ -1300,17 +1316,47 @@
         FLAGS       ///< a list of flags that can be OR-ed
     };
 
-    type_t type;
+    type_t type; /** Type of values for this field. */
 
     typedef C2Value::Primitive Primitive;
 
+    /**
+     * Range specifier for supported value. Used if type is RANGE.
+     *
+     * If step is 0 and num and denom are both 1, the supported values are any value, for which
+     * min <= value <= max.
+     *
+     * Otherwise, the range represents a geometric/arithmetic/multiply-accumulate series, where
+     * successive supported values can be derived from previous values (starting at min), using the
+     * following formula:
+     *  v[0] = min
+     *  v[i] = v[i-1] * num / denom + step for i >= 1, while min < v[i] <= max.
+     */
     struct {
+        /** Lower end of the range (inclusive). */
         Primitive min;
+        /** Upper end of the range (inclusive if permitted by series). */
         Primitive max;
+        /** Step between supported values. */
         Primitive step;
+        /** Numerator of a geometric series. */
         Primitive num;
+        /** Denominator of a geometric series. */
         Primitive denom;
     } range;
+
+    /**
+     * List of values. Used if type is VALUES or FLAGS.
+     *
+     * If type is VALUES, this is the list of supported values in decreasing preference.
+     *
+     * If type is FLAGS, this vector contains { min-mask, flag1, flag2... }. Basically, the first
+     * value is the required set of flags to be set, and the rest of the values are flags that can
+     * be set independently. FLAGS is only supported for integral types. Supported flags should
+     * not overlap, as it can make validation non-deterministic. The standard validation method
+     * is that starting from the original value, if each flag is removed when fully present (the
+     * min-mask must be fully present), we shall arrive at 0.
+     */
     std::vector<Primitive> values;
 
     C2FieldSupportedValues()
@@ -1328,14 +1374,21 @@
         range{min, max, (T)0, num, den} { }
 
     template<typename T>
+    C2FieldSupportedValues(T min, T max, T step, T num, T den)
+        : type(RANGE),
+          range{min, max, step, num, den} { }
+
+    /// \deprecated
+    template<typename T>
     C2FieldSupportedValues(bool flags, std::initializer_list<T> list)
         : type(flags ? FLAGS : VALUES),
           range{(T)0, (T)0, (T)0, (T)0, (T)0} {
-        for(T value : list) {
+        for (T value : list) {
             values.emplace_back(value);
         }
     }
 
+    /// \deprecated
     template<typename T>
     C2FieldSupportedValues(bool flags, const std::vector<T>& list)
         : type(flags ? FLAGS : VALUES),
@@ -1347,20 +1400,23 @@
 
     /// \internal
     /// \todo: create separate values vs. flags initializer as for flags we want
-    /// to list both allowed and disallowed flags
+    /// to list both allowed and required flags
     template<typename T, typename E=decltype(C2FieldDescriptor::namedValuesFor(*(T*)0))>
     C2FieldSupportedValues(bool flags, const T*)
         : type(flags ? FLAGS : VALUES),
           range{(T)0, (T)0, (T)0, (T)0, (T)0} {
-              C2FieldDescriptor::named_values_type named = C2FieldDescriptor::namedValuesFor(*(T*)0);
-        for (const C2FieldDescriptor::named_value_type &item : named) {
+              C2FieldDescriptor::NamedValuesType named = C2FieldDescriptor::namedValuesFor(*(T*)0);
+        if (flags) {
+            values.emplace_back(0); // min-mask defaults to 0
+        }
+        for (const C2FieldDescriptor::NamedValueType &item : named){
             values.emplace_back(item.second);
         }
     }
 };
 
 /**
- * Spported values for a specific field.
+ * Supported values for a specific field.
  *
  * This is a pair of the field specifier together with an optional supported values object.
  * This structure is used when reporting parameter configuration failures and conflicts.
@@ -1372,10 +1428,43 @@
     /// blobs) describe the supported values for each element (character for string, and bytes for
     /// blobs). It is optional for read-only strings and blobs.
     std::unique_ptr<C2FieldSupportedValues> values;
+
+    // This struct is meant to be move constructed.
+    C2_DEFAULT_MOVE(C2ParamFieldValues);
+
+    // Copy constructor/assignment is also provided as this object may get copied.
+    C2ParamFieldValues(const C2ParamFieldValues &other)
+        : paramOrField(other.paramOrField),
+          values(other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr) { }
+
+    C2ParamFieldValues& operator=(const C2ParamFieldValues &other) {
+        paramOrField = other.paramOrField;
+        values = other.values ? std::make_unique<C2FieldSupportedValues>(*other.values) : nullptr;
+        return *this;
+    }
+
+
+    /**
+     * Construct with no values.
+     */
+    C2ParamFieldValues(const C2ParamField &paramOrField_)
+        : paramOrField(paramOrField_) { }
+
+    /**
+     * Construct with values.
+     */
+    C2ParamFieldValues(const C2ParamField &paramOrField_, const C2FieldSupportedValues &values_)
+        : paramOrField(paramOrField_),
+          values(std::make_unique<C2FieldSupportedValues>(values_)) { }
+
+    /**
+     * Construct from fields.
+     */
+    C2ParamFieldValues(const C2ParamField &paramOrField_, std::unique_ptr<C2FieldSupportedValues> &&values_)
+        : paramOrField(paramOrField_),
+          values(std::move(values_)) { }
 };
 
 /// @}
 
-}  // namespace android
-
 #endif  // C2PARAM_H_
diff --git a/media/libstagefright/codec2/include/C2ParamDef.h b/media/libstagefright/codec2/include/C2ParamDef.h
index 3691e01..86c6833 100644
--- a/media/libstagefright/codec2/include/C2ParamDef.h
+++ b/media/libstagefright/codec2/include/C2ParamDef.h
@@ -24,8 +24,6 @@
 
 #include <C2Param.h>
 
-namespace android {
-
 /// \addtogroup Parameters
 /// @{
 
@@ -38,14 +36,14 @@
 struct C2_HIDE _C2Comparable_impl
 {
     template<typename S, typename=decltype(S() == S())>
-    static std::true_type __testEQ(int);
+    static std::true_type TestEqual(int);
     template<typename>
-    static std::false_type __testEQ(...);
+    static std::false_type TestEqual(...);
 
     template<typename S, typename=decltype(S() != S())>
-    static std::true_type __testNE(int);
+    static std::true_type TestNotEqual(int);
     template<typename>
-    static std::false_type __testNE(...);
+    static std::false_type TestNotEqual(...);
 };
 
 /**
@@ -55,30 +53,30 @@
  */
 template<typename S>
 struct C2_HIDE _C2Comparable
-    : public std::integral_constant<bool, decltype(_C2Comparable_impl::__testEQ<S>(0))::value
-                        || decltype(_C2Comparable_impl::__testNE<S>(0))::value> {
+    : public std::integral_constant<bool, decltype(_C2Comparable_impl::TestEqual<S>(0))::value
+                        || decltype(_C2Comparable_impl::TestNotEqual<S>(0))::value> {
 };
 
 ///  Helper class that checks if a type has a CORE_INDEX constant.
 struct C2_HIDE _C2CoreIndexHelper_impl
 {
     template<typename S, int=S::CORE_INDEX>
-    static std::true_type __testCoreIndex(int);
+    static std::true_type TestCoreIndex(int);
     template<typename>
-    static std::false_type __testCoreIndex(...);
+    static std::false_type TestCoreIndex(...);
 };
 
 /// Helper template that verifies a type's CORE_INDEX and creates it if the type does not have one.
 template<typename S, int CoreIndex,
-        bool HasBase=decltype(_C2CoreIndexHelper_impl::__testCoreIndex<S>(0))::value>
-struct C2_HIDE C2CoreIndexOverride {
+        bool HasBase=decltype(_C2CoreIndexHelper_impl::TestCoreIndex<S>(0))::value>
+struct C2_HIDE _C2CoreIndexOverride {
     // TODO: what if we allow structs without CORE_INDEX?
     static_assert(CoreIndex == S::CORE_INDEX, "CORE_INDEX differs from structure");
 };
 
 /// Specialization for types without a CORE_INDEX.
 template<typename S, int CoreIndex>
-struct C2_HIDE C2CoreIndexOverride<S, CoreIndex, false> {
+struct C2_HIDE _C2CoreIndexOverride<S, CoreIndex, false> {
 public:
     enum : uint32_t {
         CORE_INDEX = CoreIndex, ///< CORE_INDEX override.
@@ -87,7 +85,7 @@
 
 /// Helper template that adds a CORE_INDEX to a type if it does not have one.
 template<typename S, int CoreIndex>
-struct C2_HIDE C2AddCoreIndex : public S, public C2CoreIndexOverride<S, CoreIndex> {};
+struct C2_HIDE _C2AddCoreIndex : public S, public _C2CoreIndexOverride<S, CoreIndex> {};
 
 /**
  * \brief Helper class to check struct requirements for parameters.
@@ -97,7 +95,7 @@
  *  - expose PARAM_TYPE, and non-flex FLEX_SIZE.
  */
 template<typename S, int CoreIndex, unsigned TypeFlags>
-struct C2_HIDE C2StructCheck {
+struct C2_HIDE _C2StructCheck {
     static_assert(
             std::is_default_constructible<S>::value, "C2 structure must have default constructor");
     static_assert(!std::is_polymorphic<S>::value, "C2 structure must not have virtual methods");
@@ -118,15 +116,15 @@
 struct C2_HIDE _C2Flexible_impl {
     /// specialization for types that have a FLEX_SIZE member
     template<typename S, unsigned=S::FLEX_SIZE>
-    static std::true_type __testFlexSize(int);
+    static std::true_type TestFlexSize(int);
     template<typename>
-    static std::false_type __testFlexSize(...);
+    static std::false_type TestFlexSize(...);
 };
 
 /// Helper template that returns if a type has an integer FLEX_SIZE member.
 template<typename S>
 struct C2_HIDE _C2Flexible
-    : public std::integral_constant<bool, decltype(_C2Flexible_impl::__testFlexSize<S>(0))::value> {
+    : public std::integral_constant<bool, decltype(_C2Flexible_impl::TestFlexSize<S>(0))::value> {
 };
 
 /// Macro to test if a type is flexible (has a FLEX_SIZE member).
@@ -167,9 +165,9 @@
  *    flexible struct, so may not be needed here)
  */
 template<typename S, int ParamIndex, unsigned TypeFlags>
-struct C2_HIDE C2FlexStructCheck :
-// add flexible flag as C2StructCheck defines PARAM_TYPE
-        public C2StructCheck<S, ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, TypeFlags> {
+struct C2_HIDE _C2FlexStructCheck :
+// add flexible flag as _C2StructCheck defines PARAM_TYPE
+        public _C2StructCheck<S, ParamIndex | C2Param::CoreIndex::IS_FLEX_FLAG, TypeFlags> {
 public:
     enum : uint32_t {
         /// \hideinitializer
@@ -179,12 +177,12 @@
     const static std::initializer_list<const C2FieldDescriptor> FIELD_LIST; // TODO assign here
 
     // default constructor needed because of the disabled copy constructor
-    inline C2FlexStructCheck() = default;
+    inline _C2FlexStructCheck() = default;
 
 protected:
     // cannot copy flexible params
-    C2FlexStructCheck(const C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
-    C2FlexStructCheck& operator= (const C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
+    _C2FlexStructCheck(const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
+    _C2FlexStructCheck& operator= (const _C2FlexStructCheck<S, ParamIndex, TypeFlags> &) = delete;
 
     // constants used for helper methods
     enum : uint32_t {
@@ -197,7 +195,7 @@
     };
 
     /// returns the allocated size of this param with flexCount, or 0 if it would overflow.
-    inline static size_t calcSize(size_t flexCount, size_t size = BASE_SIZE) {
+    inline static size_t CalcSize(size_t flexCount, size_t size = BASE_SIZE) {
         if (flexCount <= (MAX_SIZE - size) / S::FLEX_SIZE) {
             return size + S::FLEX_SIZE * flexCount;
         }
@@ -207,7 +205,7 @@
     /// dynamic new operator usable for params of type S
     inline void* operator new(size_t size, size_t flexCount) noexcept {
         // TODO: assert(size == BASE_SIZE);
-        size = calcSize(flexCount, size);
+        size = CalcSize(flexCount, size);
         if (size > 0) {
             return ::operator new(size);
         }
@@ -219,12 +217,12 @@
 /// Expose FIELD_LIST from subClass;
 template<typename S, int ParamIndex, unsigned TypeFlags>
 const std::initializer_list<const C2FieldDescriptor>
-C2FlexStructCheck<S, ParamIndex, TypeFlags>::FIELD_LIST = S::FIELD_LIST;
+_C2FlexStructCheck<S, ParamIndex, TypeFlags>::FIELD_LIST = S::FIELD_LIST;
 
 /// Define From() cast operators for params.
 #define DEFINE_CAST_OPERATORS(_Type) \
     inline static _Type* From(C2Param *other) { \
-        return (_Type*)C2Param::ifSuitable( \
+        return (_Type*)C2Param::IfSuitable( \
                 other, sizeof(_Type), _Type::PARAM_TYPE, _Type::FLEX_SIZE, \
                 (_Type::PARAM_TYPE & T::Index::DIR_UNDEFINED) != T::Index::DIR_UNDEFINED); \
     } \
@@ -234,40 +232,40 @@
     inline static _Type* From(std::nullptr_t) { return nullptr; } \
 
 /**
- * Define flexible allocators (alloc_shared or alloc_unique) for flexible params.
- *  - P::alloc_xyz(flexCount, args...): allocate for given flex-count.
- *  - P::alloc_xyz(args..., T[]): allocate for size of (and with) init array.
- *  - P::alloc_xyz(T[]): allocate for size of (and with) init array with no other args.
- *  - P::alloc_xyz(args..., std::initializer_list<T>): allocate for size of (and with) initializer
+ * Define flexible allocators (AllocShared or AllocUnique) for flexible params.
+ *  - P::AllocXyz(flexCount, args...): allocate for given flex-count.
+ *  - P::AllocXyz(args..., T[]): allocate for size of (and with) init array.
+ *  - P::AllocXyz(T[]): allocate for size of (and with) init array with no other args.
+ *  - P::AllocXyz(args..., std::initializer_list<T>): allocate for size of (and with) initializer
  *    list.
  */
-#define DEFINE_FLEXIBLE_ALLOC(_Type, S, ptr) \
+#define DEFINE_FLEXIBLE_ALLOC(_Type, S, ptr, Ptr) \
     template<typename ...Args> \
-    inline static std::ptr##_ptr<_Type> alloc_##ptr(size_t flexCount, const Args(&... args)) { \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr(size_t flexCount, const Args(&... args)) { \
         return std::ptr##_ptr<_Type>(new(flexCount) _Type(flexCount, args...)); \
     } \
     /* NOTE: unfortunately this is not supported by clang yet */ \
     template<typename ...Args, typename U=typename S::FlexType, unsigned N> \
-    inline static std::ptr##_ptr<_Type> alloc_##ptr(const Args(&... args), const U(&init)[N]) { \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr(const Args(&... args), const U(&init)[N]) { \
         return std::ptr##_ptr<_Type>(new(N) _Type(N, args..., init)); \
     } \
     /* so for now, specialize for no args */ \
     template<typename U=typename S::FlexType, unsigned N> \
-    inline static std::ptr##_ptr<_Type> alloc_##ptr(const U(&init)[N]) { \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr(const U(&init)[N]) { \
         return std::ptr##_ptr<_Type>(new(N) _Type(N, init)); \
     } \
     template<typename ...Args, typename U=typename S::FlexType> \
-    inline static std::ptr##_ptr<_Type> alloc_##ptr( \
+    inline static std::ptr##_ptr<_Type> Alloc##Ptr( \
             const Args(&... args), const std::initializer_list<U> &init) { \
         return std::ptr##_ptr<_Type>(new(init.size()) _Type(init.size(), args..., init)); \
     } \
 
 /**
- * Define flexible methods alloc_shared, alloc_unique and flexCount.
+ * Define flexible methods AllocShared, AllocUnique and flexCount.
  */
 #define DEFINE_FLEXIBLE_METHODS(_Type, S) \
-    DEFINE_FLEXIBLE_ALLOC(_Type, S, shared) \
-    DEFINE_FLEXIBLE_ALLOC(_Type, S, unique) \
+    DEFINE_FLEXIBLE_ALLOC(_Type, S, shared, Shared) \
+    DEFINE_FLEXIBLE_ALLOC(_Type, S, unique, Unique) \
     inline size_t flexCount() const { \
         static_assert(sizeof(_Type) == _Type::BASE_SIZE, "incorrect BASE_SIZE"); \
         size_t sz = this->size(); \
@@ -314,8 +312,8 @@
  * structures.
  */
 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
-struct C2_HIDE C2GlobalParam : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
-        public C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
+struct C2_HIDE C2GlobalParam : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
+        public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
 private:
     typedef C2GlobalParam<T, S, ParamIndex> _Type;
 
@@ -344,14 +342,14 @@
  */
 template<typename T, typename S, int ParamIndex>
 struct C2_HIDE C2GlobalParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
-    : public T, public C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
+    : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_GLOBAL> {
 private:
     typedef C2GlobalParam<T, S, ParamIndex> _Type;
 
     /// Wrapper around base structure's constructor.
     template<typename ...Args>
     inline C2GlobalParam(size_t flexCount, const Args(&... args))
-        : T(_Type::calcSize(flexCount), _Type::PARAM_TYPE), m(flexCount, args...) { }
+        : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE), m(flexCount, args...) { }
 
 public:
     S m; ///< wrapped flexible structure
@@ -380,8 +378,8 @@
  * unspecified port expose a setPort method, and add an initial port parameter to the constructor.
  */
 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
-struct C2_HIDE C2PortParam : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
-        private C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_UNDEFINED> {
+struct C2_HIDE C2PortParam : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
+        private _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_UNDEFINED> {
 private:
     typedef C2PortParam<T, S, ParamIndex> _Type;
 
@@ -398,8 +396,8 @@
     DEFINE_CAST_OPERATORS(_Type)
 
     /// Specialization for an input port parameter.
-    struct input : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
-            public C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
+    struct input : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
+            public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
         /// Wrapper around base structure's constructor.
         template<typename ...Args>
         inline input(const Args(&... args)) : T(sizeof(_Type), input::PARAM_TYPE), S(args...) { }
@@ -409,8 +407,8 @@
     };
 
     /// Specialization for an output port parameter.
-    struct output : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
-            public C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
+    struct output : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
+            public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
         /// Wrapper around base structure's constructor.
         template<typename ...Args>
         inline output(const Args(&... args)) : T(sizeof(_Type), output::PARAM_TYPE), S(args...) { }
@@ -440,16 +438,16 @@
  */
 template<typename T, typename S, int ParamIndex>
 struct C2_HIDE C2PortParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
-    : public T, public C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_UNDEFINED> {
+    : public T, public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Type::DIR_UNDEFINED> {
 private:
     typedef C2PortParam<T, S, ParamIndex> _Type;
 
     /// Default constructor for basic allocation: new(flexCount) P.
-    inline C2PortParam(size_t flexCount) : T(_Type::calcSize(flexCount), _Type::PARAM_TYPE) { }
+    inline C2PortParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE) { }
     template<typename ...Args>
     /// Wrapper around base structure's constructor while also specifying port/direction.
     inline C2PortParam(size_t flexCount, bool _output, const Args(&... args))
-        : T(_Type::calcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE),
+        : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE),
           m(flexCount, args...) { }
 
 public:
@@ -463,12 +461,12 @@
 
     /// Specialization for an input port parameter.
     struct input : public T,
-            public C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
+            public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
     private:
         /// Wrapper around base structure's constructor while also specifying port/direction.
         template<typename ...Args>
         inline input(size_t flexCount, const Args(&... args))
-            : T(_Type::calcSize(flexCount), input::PARAM_TYPE), m(flexCount, args...) { }
+            : T(_Type::CalcSize(flexCount), input::PARAM_TYPE), m(flexCount, args...) { }
 
     public:
         S m; ///< wrapped flexible structure
@@ -479,12 +477,12 @@
 
     /// Specialization for an output port parameter.
     struct output : public T,
-            public C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
+            public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
     private:
         /// Wrapper around base structure's constructor while also specifying port/direction.
         template<typename ...Args>
         inline output(size_t flexCount, const Args(&... args))
-            : T(_Type::calcSize(flexCount), output::PARAM_TYPE), m(flexCount, args...) { }
+            : T(_Type::CalcSize(flexCount), output::PARAM_TYPE), m(flexCount, args...) { }
 
     public:
         S m; ///< wrapped flexible structure
@@ -516,8 +514,8 @@
  * parameter to the constructor.
  */
 template<typename T, typename S, int ParamIndex=S::CORE_INDEX, class Flex=void>
-struct C2_HIDE C2StreamParam : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
-        private C2StructCheck<S, ParamIndex,
+struct C2_HIDE C2StreamParam : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
+        private _C2StructCheck<S, ParamIndex,
                 T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
 private:
     typedef C2StreamParam<T, S, ParamIndex> _Type;
@@ -539,8 +537,8 @@
     DEFINE_CAST_OPERATORS(_Type)
 
     /// Specialization for an input stream parameter.
-    struct input : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
-            public C2StructCheck<S, ParamIndex,
+    struct input : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
+            public _C2StructCheck<S, ParamIndex,
                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
         /// Default constructor. Stream-ID is undefined.
         inline input() : T(sizeof(_Type), input::PARAM_TYPE) { }
@@ -555,8 +553,8 @@
     };
 
     /// Specialization for an output stream parameter.
-    struct output : public T, public S, public C2CoreIndexOverride<S, ParamIndex>,
-            public C2StructCheck<S, ParamIndex,
+    struct output : public T, public S, public _C2CoreIndexOverride<S, ParamIndex>,
+            public _C2StructCheck<S, ParamIndex,
                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
         /// Default constructor. Stream-ID is undefined.
         inline output() : T(sizeof(_Type), output::PARAM_TYPE) { }
@@ -595,17 +593,17 @@
 template<typename T, typename S, int ParamIndex>
 struct C2_HIDE C2StreamParam<T, S, ParamIndex, IF_FLEXIBLE(S)>
     : public T,
-      public C2FlexStructCheck<S, ParamIndex,
+      public _C2FlexStructCheck<S, ParamIndex,
               T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Index::DIR_UNDEFINED> {
 private:
     typedef C2StreamParam<T, S, ParamIndex> _Type;
     /// Default constructor. Port/direction and stream-ID is undefined.
-    inline C2StreamParam(size_t flexCount) : T(_Type::calcSize(flexCount), _Type::PARAM_TYPE, 0u) { }
+    inline C2StreamParam(size_t flexCount) : T(_Type::CalcSize(flexCount), _Type::PARAM_TYPE, 0u) { }
     /// Wrapper around base structure's constructor while also specifying port/direction and
     /// stream-ID.
     template<typename ...Args>
     inline C2StreamParam(size_t flexCount, bool _output, unsigned stream, const Args(&... args))
-        : T(_Type::calcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
+        : T(_Type::CalcSize(flexCount), _output ? output::PARAM_TYPE : input::PARAM_TYPE, stream),
           m(flexCount, args...) { }
 
 public:
@@ -621,15 +619,15 @@
 
     /// Specialization for an input stream parameter.
     struct input : public T,
-            public C2FlexStructCheck<S, ParamIndex,
+            public _C2FlexStructCheck<S, ParamIndex,
                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
     private:
         /// Default constructor. Stream-ID is undefined.
-        inline input(size_t flexCount) : T(_Type::calcSize(flexCount), input::PARAM_TYPE) { }
+        inline input(size_t flexCount) : T(_Type::CalcSize(flexCount), input::PARAM_TYPE) { }
         /// Wrapper around base structure's constructor while also specifying stream-ID.
         template<typename ...Args>
         inline input(size_t flexCount, unsigned stream, const Args(&... args))
-            : T(_Type::calcSize(flexCount), input::PARAM_TYPE, stream), m(flexCount, args...) { }
+            : T(_Type::CalcSize(flexCount), input::PARAM_TYPE, stream), m(flexCount, args...) { }
 
     public:
         S m; ///< wrapped flexible structure
@@ -643,15 +641,15 @@
 
     /// Specialization for an output stream parameter.
     struct output : public T,
-            public C2FlexStructCheck<S, ParamIndex,
+            public _C2FlexStructCheck<S, ParamIndex,
                     T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
     private:
         /// Default constructor. Stream-ID is undefined.
-        inline output(size_t flexCount) : T(_Type::calcSize(flexCount), output::PARAM_TYPE) { }
+        inline output(size_t flexCount) : T(_Type::CalcSize(flexCount), output::PARAM_TYPE) { }
         /// Wrapper around base structure's constructor while also specifying stream-ID.
         template<typename ...Args>
         inline output(size_t flexCount, unsigned stream, const Args(&... args))
-            : T(_Type::calcSize(flexCount), output::PARAM_TYPE, stream), m(flexCount, args...) { }
+            : T(_Type::CalcSize(flexCount), output::PARAM_TYPE, stream), m(flexCount, args...) { }
 
     public:
         S m; ///< wrapped flexible structure
@@ -820,19 +818,19 @@
 
 private:
     /// Construct from a C2MemoryBlock.
-    /// Used only by the flexible parameter allocators (alloc_unique & alloc_shared).
+    /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
     inline C2SimpleArrayStruct(size_t flexCount, const C2MemoryBlock<T> &block) {
         _C2ValueArrayHelper::init(values, flexCount, block);
     }
 
     /// Construct from an initializer list.
-    /// Used only by the flexible parameter allocators (alloc_unique & alloc_shared).
+    /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
     inline C2SimpleArrayStruct(size_t flexCount, const std::initializer_list<T> &init) {
         _C2ValueArrayHelper::init(values, flexCount, init);
     }
 
     /// Construct from another flexible array.
-    /// Used only by the flexible parameter allocators (alloc_unique & alloc_shared).
+    /// Used only by the flexible parameter allocators (AllocUnique & AllocShared).
     template<unsigned N>
     inline C2SimpleArrayStruct(size_t flexCount, const T(&init)[N]) {
         _C2ValueArrayHelper::init(values, flexCount, init);
@@ -905,6 +903,4 @@
 
 /// @}
 
-}  // namespace android
-
 #endif  // C2PARAM_DEF_H_
diff --git a/media/libstagefright/codec2/include/C2Work.h b/media/libstagefright/codec2/include/C2Work.h
index b6c5814..1a35519 100644
--- a/media/libstagefright/codec2/include/C2Work.h
+++ b/media/libstagefright/codec2/include/C2Work.h
@@ -28,8 +28,6 @@
 #include <list>
 #include <vector>
 
-namespace android {
-
 /// \defgroup work Work and data processing
 /// @{
 
@@ -39,17 +37,20 @@
  */
 struct C2SettingResult {
     enum Failure : uint32_t {
-        READ_ONLY,  ///< parameter is read-only and cannot be set
-        MISMATCH,   ///< parameter mismatches input data
-        BAD_VALUE,  ///< parameter does not accept value
+        /* parameter failures below */
         BAD_TYPE,   ///< parameter is not supported
         BAD_PORT,   ///< parameter is not supported on the specific port
         BAD_INDEX,  ///< parameter is not supported on the specific stream
-        CONFLICT,   ///< parameter is in conflict with an/other setting(s)
-        /// parameter is out of range due to other settings (this failure mode
-        /// can only be used for strict parameters)
-        UNSUPPORTED,
+        READ_ONLY,  ///< parameter is read-only and cannot be set
+        MISMATCH,   ///< parameter mismatches input data
 
+        /* field failures below */
+        BAD_VALUE,  ///< parameter does not accept value for the field at all
+        CONFLICT,   ///< parameter field value is in conflict with an/other setting(s)
+
+        /// parameter field is out of range due to other settings (this failure mode
+        /// can only be used for strict calculated parameters)
+        UNSUPPORTED,
 
         /// requested parameter value is in conflict with an/other setting(s)
         /// and has been corrected to the closest supported value. This failure
@@ -60,14 +61,15 @@
 
     Failure failure;    ///< failure code
 
-    /// Failing (or corrected) field. Currently supported values for the field. This is set if
+    /// Failing (or corrected) field or parameterand optionally, currently supported values for the
+    /// field. Values must only be set for field failures other than BAD_VALUE, and only if they are
     /// different from the globally supported values (e.g. due to restrictions by another param or
-    /// input data)
-    /// \todo need to define suggestions for masks to be set and unset.
+    /// input data).
     C2ParamFieldValues field;
 
     /// Conflicting parameters or fields with optional suggestions with (optional) suggested values
-    /// for any conflicting fields to avoid the conflict.
+    /// for any conflicting fields to avoid the conflict. Must only be set for CONFLICT, UNSUPPORTED
+    /// and INFO_CONFLICT failure codes.
     std::vector<C2ParamFieldValues> conflicts;
 };
 
@@ -75,9 +77,8 @@
 //  WORK
 // ================================================================================================
 
-// c2_node_id_t-s
+/** Unique ID for a processing node. */
 typedef uint32_t c2_node_id_t;
-typedef c2_node_id_t c2_node_id_t;
 
 enum {
     kParamIndexWorkOrdinal,
@@ -211,6 +212,4 @@
 
 /// @}
 
-}  // namespace android
-
 #endif  // C2WORK_H_
diff --git a/media/libstagefright/codec2/include/SimpleC2Interface.h b/media/libstagefright/codec2/include/SimpleC2Interface.h
index b934f12..310096f 100644
--- a/media/libstagefright/codec2/include/SimpleC2Interface.h
+++ b/media/libstagefright/codec2/include/SimpleC2Interface.h
@@ -27,13 +27,9 @@
     public:
         inline Builder(
                 const char *name,
-                c2_node_id_t id)
-            : mIntf(new SimpleC2Interface(name, id)) {}
-
-        inline Builder(
-                const char *name,
                 c2_node_id_t id,
-                std::function<void(::android::SimpleC2Interface*)> deleter)
+                std::function<void(C2ComponentInterface*)> deleter =
+                    std::default_delete<C2ComponentInterface>())
             : mIntf(new SimpleC2Interface(name, id), deleter) {}
 
         inline Builder &inputFormat(C2FormatKind input) {
@@ -46,6 +42,28 @@
             return *this;
         }
 
+        inline Builder &inputMediaType(const char *mediaType, size_t maxLen = 128) {
+            mIntf->mInputMediaType = C2PortMimeConfig::input::AllocShared(maxLen);
+            std::strncpy(mIntf->mInputMediaType->m.value, mediaType, maxLen);
+            return *this;
+        }
+
+        inline Builder &outputMediaType(const char *mediaType, size_t maxLen = 128) {
+            mIntf->mOutputMediaType = C2PortMimeConfig::output::AllocShared(maxLen);
+            std::strncpy(mIntf->mOutputMediaType->m.value, mediaType, maxLen);
+            return *this;
+        }
+
+        template<size_t N>
+        inline Builder &inputMediaType(const char mediaType[N]) {
+            return inputMediaType(mediaType, N);
+        }
+
+        template<size_t N>
+        inline Builder &outputMediaType(const char mediaType[N]) {
+            return outputMediaType(mediaType, N);
+        }
+
         inline std::shared_ptr<SimpleC2Interface> build() {
             return mIntf;
         }
@@ -89,6 +107,8 @@
     const c2_node_id_t mId;
     C2StreamFormatConfig::input mInputFormat;
     C2StreamFormatConfig::output mOutputFormat;
+    std::shared_ptr<C2PortMimeConfig::input> mInputMediaType;
+    std::shared_ptr<C2PortMimeConfig::output> mOutputMediaType;
 
     SimpleC2Interface() = delete;
 };
diff --git a/media/libstagefright/codec2/include/android-C2Buffer.h b/media/libstagefright/codec2/include/android-C2Buffer.h
new file mode 100644
index 0000000..c71f2cf
--- /dev/null
+++ b/media/libstagefright/codec2/include/android-C2Buffer.h
@@ -0,0 +1,65 @@
+/*
+ * 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_C2BUFFER_H_
+#define ANDROID_C2BUFFER_H_
+
+#include <cutils/native_handle.h>
+#include <hardware/gralloc.h>
+
+/* Use android native handle for C2Handle */
+typedef ::native_handle_t C2Handle;
+
+namespace android {
+
+/**
+ * Android platform buffer/memory usage bits.
+ */
+struct C2AndroidMemoryUsage : public C2MemoryUsage {
+// public:
+    /**
+     * Reuse gralloc flags where possible, as Codec 2.0 API only uses bits 0 and 1.
+     */
+    enum Consumer : uint64_t {
+        RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_READ   = GRALLOC_USAGE_HW_TEXTURE,
+        HW_COMPOSER_READ  = GRALLOC_USAGE_HW_COMPOSER,
+        HW_CODEC_READ     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        READ_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    enum Producer : uint64_t {
+        RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_WRITE   = GRALLOC_USAGE_HW_RENDER,
+        HW_COMPOSER_WRITE  = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
+        HW_CODEC_WRITE     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        WRITE_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    /**
+     * Convert from gralloc usage.
+     */
+    static C2MemoryUsage FromGrallocUsage(uint64_t usage);
+
+    /**
+     * Convert to gralloc usage.
+     */
+    uint64_t asGrallocUsage() const;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_C2BUFFER_H_
diff --git a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
new file mode 100644
index 0000000..b011a06
--- /dev/null
+++ b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurface.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
+#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
+
+#include <memory>
+
+#include <C2Component.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+
+namespace android {
+
+class GraphicBufferSource;
+
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
+        HGraphicBufferProducer;
+typedef ::android::IGraphicBufferProducer BGraphicBufferProducer;
+
+// TODO: ::android::TWGraphicBufferProducer<IInputSurface>
+typedef ::android::TWGraphicBufferProducer<HGraphicBufferProducer> InputSurfaceBase;
+
+class InputSurface : public InputSurfaceBase {
+public:
+    virtual ~InputSurface() = default;
+
+    // Methods from IInputSurface
+    sp<InputSurfaceConnection> connectToComponent(
+            const std::shared_ptr<::C2Component> &comp);
+    // TODO: intf()
+
+    static sp<InputSurface> Create();
+
+private:
+    InputSurface(
+            const sp<BGraphicBufferProducer> &base,
+            const sp<::android::GraphicBufferSource> &source);
+
+    sp<::android::GraphicBufferSource> mSource;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_H
diff --git a/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
new file mode 100644
index 0000000..b24a416
--- /dev/null
+++ b/media/libstagefright/codec2/include/media/stagefright/codec2/1.0/InputSurfaceConnection.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
+#define ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
+
+#include <memory>
+
+#include <C2Component.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/codec2/1.0/InputSurfaceConnection.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace implementation {
+
+// TODO: inherit from IInputSurfaceConnection
+class InputSurfaceConnection : public RefBase {
+public:
+    virtual ~InputSurfaceConnection();
+
+    // From IInputSurfaceConnection
+    void disconnect();
+
+private:
+    friend class InputSurface;
+
+    // For InputSurface
+    InputSurfaceConnection(
+            const sp<GraphicBufferSource> &source, const std::shared_ptr<C2Component> &comp);
+    bool init();
+
+    InputSurfaceConnection() = delete;
+
+    class Impl;
+
+    sp<GraphicBufferSource> mSource;
+    sp<Impl> mImpl;
+
+    DISALLOW_EVIL_CONSTRUCTORS(InputSurfaceConnection);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace c2
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_C2_V1_0_INPUT_SURFACE_CONNECTION_H
diff --git a/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp b/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
index 7da824b..e555e8c 100644
--- a/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
+++ b/media/libstagefright/codec2/tests/C2ComponentInterface_test.cpp
@@ -37,7 +37,7 @@
 
 template <class T> std::unique_ptr<T> alloc_unique_cstr(const char *cstr) {
     size_t len = strlen(cstr);
-    std::unique_ptr<T> ptr = T::alloc_unique(len);
+    std::unique_ptr<T> ptr = T::AllocUnique(len);
     memcpy(ptr->m.value, cstr, len);
     return ptr;
 }
@@ -182,7 +182,7 @@
 
 template <> std::unique_ptr<C2PortMimeConfig::input> makeParam() {
     // TODO(hiroh): Set more precise length.
-    return C2PortMimeConfig::input::alloc_unique(100);
+    return C2PortMimeConfig::input::AllocUnique(100);
 }
 
 #define TRACED_FAILURE(func)                            \
diff --git a/media/libstagefright/codec2/tests/C2Param_test.cpp b/media/libstagefright/codec2/tests/C2Param_test.cpp
index 1a29add..fcfbafd 100644
--- a/media/libstagefright/codec2/tests/C2Param_test.cpp
+++ b/media/libstagefright/codec2/tests/C2Param_test.cpp
@@ -23,8 +23,6 @@
 #include <util/C2ParamUtils.h>
 #include <C2ParamDef.h>
 
-namespace android {
-
 void PrintTo(const _C2FieldId &id, ::std::ostream* os) {
     *os << "@" << id._mOffset << "+" << id._mSize;
 }
@@ -47,14 +45,14 @@
         }
     }
     *os << " " << fd.name();
-    if (fd.length() > 1) {
-        *os << "[" << fd.length() << "]";
-    } else if (fd.length() == 0) {
+    if (fd.extent() > 1) {
+        *os << "[" << fd.extent() << "]";
+    } else if (fd.extent() == 0) {
         *os << "[]";
     }
     *os << " (";
     PrintTo(fd._mFieldId, os);
-    *os << "*" << fd.length() << ")";
+    *os << "*" << fd.extent() << ")";
 }
 
 enum C2ParamIndexType : C2Param::type_index_t {
@@ -104,7 +102,7 @@
 
 bool operator==(const C2FieldDescriptor &a, const C2FieldDescriptor &b) {
     return a.type() == b.type()
-            && a.length() == b.length()
+            && a.extent() == b.extent()
             && strcmp(a.name(), b.name()) == 0
             && a._mFieldId == b._mFieldId;
 }
@@ -142,7 +140,7 @@
     // verify first field descriptor
     EXPECT_EQ(FD::INT32, fields[0].type());
     EXPECT_STREQ("s32", fields[0].name());
-    EXPECT_EQ(1u, fields[0].length());
+    EXPECT_EQ(1u, fields[0].extent());
     EXPECT_EQ(_C2FieldId(0, 4), fields[0]._mFieldId);
 
     EXPECT_EQ(expected[0], fields[0]);
@@ -738,7 +736,7 @@
     s.value = 11;
     s = 12;
     (void)C2NumberConfig3::FIELD_LIST;
-    std::shared_ptr<C2VideoNameConfig> n = C2VideoNameConfig::alloc_shared(25);
+    std::shared_ptr<C2VideoNameConfig> n = C2VideoNameConfig::AllocShared(25);
     strcpy(n->m.value, "lajos");
     C2NumberConfig4 t(false, 0, 11);
     t.value = 15;
@@ -766,10 +764,10 @@
 
 std::list<const C2FieldDescriptor> myList = C2NumberConfig::FIELD_LIST;
 
-    std::unique_ptr<android::C2ParamDescriptor> __test_describe(uint32_t paramType) {
+    std::unique_ptr<C2ParamDescriptor> __test_describe(uint32_t paramType) {
         std::list<const C2FieldDescriptor> fields = describeC2Params<C2NumberConfig>();
 
-        auto widths = C2NumbersInfo::alloc_shared(5);
+        auto widths = C2NumbersInfo::AllocShared(5);
         widths->flexCount();
         widths->m.mNumbers[4] = 1;
 
@@ -1112,7 +1110,7 @@
 
     {
       C2NumberInfo inf(100);
-      std::unique_ptr<C2NumbersTuning> tun_ = C2NumbersTuning::alloc_unique(1);
+      std::unique_ptr<C2NumbersTuning> tun_ = C2NumbersTuning::AllocUnique(1);
 
       EXPECT_EQ(tun.coreIndex(), inf.coreIndex());
       EXPECT_NE(tun.coreIndex(), tun_->coreIndex());
@@ -1663,8 +1661,8 @@
 void StaticTestAddCoreIndex() {
     struct nobase {};
     struct base { enum : uint32_t { CORE_INDEX = 1 }; };
-    static_assert(C2AddCoreIndex<nobase, 2>::CORE_INDEX == 2, "should be 2");
-    static_assert(C2AddCoreIndex<base, 1>::CORE_INDEX == 1, "should be 1");
+    static_assert(_C2AddCoreIndex<nobase, 2>::CORE_INDEX == 2, "should be 2");
+    static_assert(_C2AddCoreIndex<base, 1>::CORE_INDEX == 1, "should be 1");
 }
 
 class TestFlexHelper {
@@ -1711,10 +1709,10 @@
         EXPECT_EQ(index.typeIndex(), kParamIndexNumbers);
     }
 
-    std::unique_ptr<C2NumbersTuning> tun_ = C2NumbersTuning::alloc_unique(1);
+    std::unique_ptr<C2NumbersTuning> tun_ = C2NumbersTuning::AllocUnique(1);
     tun_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersTuning> tun = std::move(tun_);
-    std::shared_ptr<C2NumbersTuning> btun = C2NumbersTuning::alloc_shared(1);
+    std::shared_ptr<C2NumbersTuning> btun = C2NumbersTuning::AllocShared(1);
 
     {
         // flags & invariables
@@ -1776,24 +1774,24 @@
         EXPECT_EQ(*(C2Param::Copy(*tun)), *tun);
     }
 
-    std::unique_ptr<C2NumbersPortTuning> outp1_(C2NumbersPortTuning::alloc_unique(1, true)),
-            inp1_ = C2NumbersPortTuning::alloc_unique(1, false);
+    std::unique_ptr<C2NumbersPortTuning> outp1_(C2NumbersPortTuning::AllocUnique(1, true)),
+            inp1_ = C2NumbersPortTuning::AllocUnique(1, false);
     outp1_->m.mNumbers[0] = 100;
     inp1_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersPortTuning> outp1 = std::move(outp1_);
     std::unique_ptr<const C2NumbersPortTuning> inp1 = std::move(inp1_);
-    std::shared_ptr<C2NumbersPortTuning> boutp1(C2NumbersPortTuning::alloc_shared(1)),
-            binp1 = C2NumbersPortTuning::alloc_shared(1),
-            binp3 = C2NumbersPortTuning::alloc_shared(1, false);
+    std::shared_ptr<C2NumbersPortTuning> boutp1(C2NumbersPortTuning::AllocShared(1)),
+            binp1 = C2NumbersPortTuning::AllocShared(1),
+            binp3 = C2NumbersPortTuning::AllocShared(1, false);
     binp3->m.mNumbers[0] = 100;
-    std::unique_ptr<C2NumbersPortTuning::input> inp2_(C2NumbersPortTuning::input::alloc_unique(1));
+    std::unique_ptr<C2NumbersPortTuning::input> inp2_(C2NumbersPortTuning::input::AllocUnique(1));
     inp2_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersPortTuning::input> inp2 = std::move(inp2_);
-    std::shared_ptr<C2NumbersPortTuning::input> binp2(C2NumbersPortTuning::input::alloc_shared(1));
-    std::unique_ptr<C2NumbersPortTuning::output> outp2_(C2NumbersPortTuning::output::alloc_unique(1));
+    std::shared_ptr<C2NumbersPortTuning::input> binp2(C2NumbersPortTuning::input::AllocShared(1));
+    std::unique_ptr<C2NumbersPortTuning::output> outp2_(C2NumbersPortTuning::output::AllocUnique(1));
     outp2_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersPortTuning::output> outp2 = std::move(outp2_);
-    std::shared_ptr<C2NumbersPortTuning::output> boutp2(C2NumbersPortTuning::output::alloc_shared(1));
+    std::shared_ptr<C2NumbersPortTuning::output> boutp2(C2NumbersPortTuning::output::AllocShared(1));
 
     {
         static_assert(canCallSetPort(*binp3), "should be able to");
@@ -2001,24 +1999,24 @@
         EXPECT_EQ(*(C2Param::Copy(*outp2)), *outp2);
     }
 
-    std::unique_ptr<C2NumbersStreamTuning> outs1_(C2NumbersStreamTuning::alloc_unique(1, true, 1u));
+    std::unique_ptr<C2NumbersStreamTuning> outs1_(C2NumbersStreamTuning::AllocUnique(1, true, 1u));
     outs1_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersStreamTuning> outs1 = std::move(outs1_);
-    std::unique_ptr<C2NumbersStreamTuning> ins1_(C2NumbersStreamTuning::alloc_unique(1, false, 1u));
+    std::unique_ptr<C2NumbersStreamTuning> ins1_(C2NumbersStreamTuning::AllocUnique(1, false, 1u));
     ins1_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersStreamTuning> ins1 = std::move(ins1_);
-    std::shared_ptr<C2NumbersStreamTuning> bouts1(C2NumbersStreamTuning::alloc_shared(1));
-    std::shared_ptr<C2NumbersStreamTuning> bins1(C2NumbersStreamTuning::alloc_shared(1));
-    std::shared_ptr<C2NumbersStreamTuning> bins3(C2NumbersStreamTuning::alloc_shared(1, false, 1u));
+    std::shared_ptr<C2NumbersStreamTuning> bouts1(C2NumbersStreamTuning::AllocShared(1));
+    std::shared_ptr<C2NumbersStreamTuning> bins1(C2NumbersStreamTuning::AllocShared(1));
+    std::shared_ptr<C2NumbersStreamTuning> bins3(C2NumbersStreamTuning::AllocShared(1, false, 1u));
     bins3->m.mNumbers[0] = 100;
-    std::unique_ptr<C2NumbersStreamTuning::input> ins2_(C2NumbersStreamTuning::input::alloc_unique(1, 1u));
+    std::unique_ptr<C2NumbersStreamTuning::input> ins2_(C2NumbersStreamTuning::input::AllocUnique(1, 1u));
     ins2_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersStreamTuning::input> ins2 = std::move(ins2_);
-    std::shared_ptr<C2NumbersStreamTuning::input> bins2(C2NumbersStreamTuning::input::alloc_shared(1));
-    std::unique_ptr<C2NumbersStreamTuning::output> outs2_(C2NumbersStreamTuning::output::alloc_unique(1, 1u));
+    std::shared_ptr<C2NumbersStreamTuning::input> bins2(C2NumbersStreamTuning::input::AllocShared(1));
+    std::unique_ptr<C2NumbersStreamTuning::output> outs2_(C2NumbersStreamTuning::output::AllocUnique(1, 1u));
     outs2_->m.mNumbers[0] = 100;
     std::unique_ptr<const C2NumbersStreamTuning::output> outs2 = std::move(outs2_);
-    std::shared_ptr<C2NumbersStreamTuning::output> bouts2(C2NumbersStreamTuning::output::alloc_shared(1));
+    std::shared_ptr<C2NumbersStreamTuning::output> bouts2(C2NumbersStreamTuning::output::AllocShared(1));
 
     {
         static_assert(canCallSetPort(*bins3), "should be able to");
@@ -2241,7 +2239,7 @@
         std::list<const C2FieldDescriptor> fields = int32Value.FIELD_LIST;
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::INT32, fields.cbegin()->type());
-        EXPECT_EQ(1u, fields.cbegin()->length());
+        EXPECT_EQ(1u, fields.cbegin()->extent());
         EXPECT_EQ(C2String("value"), fields.cbegin()->name());
     }
 
@@ -2252,7 +2250,7 @@
         std::list<const C2FieldDescriptor> fields = uint32Value.FIELD_LIST;
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::UINT32, fields.cbegin()->type());
-        EXPECT_EQ(1u, fields.cbegin()->length());
+        EXPECT_EQ(1u, fields.cbegin()->extent());
         EXPECT_EQ(C2String("value"), fields.cbegin()->name());
     }
 
@@ -2263,7 +2261,7 @@
         std::list<const C2FieldDescriptor> fields = int64Value.FIELD_LIST;
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::INT64, fields.cbegin()->type());
-        EXPECT_EQ(1u, fields.cbegin()->length());
+        EXPECT_EQ(1u, fields.cbegin()->extent());
         EXPECT_EQ(C2String("value"), fields.cbegin()->name());
     }
 
@@ -2274,7 +2272,7 @@
         std::list<const C2FieldDescriptor> fields = uint64Value.FIELD_LIST;
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::UINT64, fields.cbegin()->type());
-        EXPECT_EQ(1u, fields.cbegin()->length());
+        EXPECT_EQ(1u, fields.cbegin()->extent());
         EXPECT_EQ(C2String("value"), fields.cbegin()->name());
     }
 
@@ -2285,24 +2283,24 @@
         std::list<const C2FieldDescriptor> fields = floatValue.FIELD_LIST;
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::FLOAT, fields.cbegin()->type());
-        EXPECT_EQ(1u, fields.cbegin()->length());
+        EXPECT_EQ(1u, fields.cbegin()->extent());
         EXPECT_EQ(C2String("value"), fields.cbegin()->name());
     }
 
     {
         uint8_t initValue[] = "ABCD";
         typedef C2GlobalParam<C2Setting, C2BlobValue, 0> BlobSetting;
-        std::unique_ptr<BlobSetting> blobValue = BlobSetting::alloc_unique(6, C2ConstMemoryBlock<uint8_t>(initValue));
+        std::unique_ptr<BlobSetting> blobValue = BlobSetting::AllocUnique(6, C2ConstMemoryBlock<uint8_t>(initValue));
         static_assert(std::is_same<decltype(blobValue->m.value), uint8_t[]>::value, "should be uint8_t[]");
         EXPECT_EQ(0, memcmp(blobValue->m.value, "ABCD\0", 6));
         EXPECT_EQ(6u, blobValue->flexCount());
         std::list<const C2FieldDescriptor> fields = blobValue->FIELD_LIST;
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::BLOB, fields.cbegin()->type());
-        EXPECT_EQ(0u, fields.cbegin()->length());
+        EXPECT_EQ(0u, fields.cbegin()->extent());
         EXPECT_EQ(C2String("value"), fields.cbegin()->name());
 
-        blobValue = BlobSetting::alloc_unique(3, C2ConstMemoryBlock<uint8_t>(initValue));
+        blobValue = BlobSetting::AllocUnique(3, C2ConstMemoryBlock<uint8_t>(initValue));
         EXPECT_EQ(0, memcmp(blobValue->m.value, "ABC", 3));
         EXPECT_EQ(3u, blobValue->flexCount());
     }
@@ -2310,30 +2308,30 @@
     {
         constexpr char initValue[] = "ABCD";
         typedef C2GlobalParam<C2Setting, C2StringValue, 0> StringSetting;
-        std::unique_ptr<StringSetting> stringValue = StringSetting::alloc_unique(6, C2ConstMemoryBlock<char>(initValue));
-        stringValue = StringSetting::alloc_unique(6, initValue);
+        std::unique_ptr<StringSetting> stringValue = StringSetting::AllocUnique(6, C2ConstMemoryBlock<char>(initValue));
+        stringValue = StringSetting::AllocUnique(6, initValue);
         static_assert(std::is_same<decltype(stringValue->m.value), char[]>::value, "should be char[]");
         EXPECT_EQ(0, memcmp(stringValue->m.value, "ABCD\0", 6));
         EXPECT_EQ(6u, stringValue->flexCount());
         std::list<const C2FieldDescriptor> fields = stringValue->FIELD_LIST;
         EXPECT_EQ(1u, fields.size());
         EXPECT_EQ(FD::STRING, fields.cbegin()->type());
-        EXPECT_EQ(0u, fields.cbegin()->length());
+        EXPECT_EQ(0u, fields.cbegin()->extent());
         EXPECT_EQ(C2String("value"), fields.cbegin()->name());
 
-        stringValue = StringSetting::alloc_unique(3, C2ConstMemoryBlock<char>(initValue));
+        stringValue = StringSetting::AllocUnique(3, C2ConstMemoryBlock<char>(initValue));
         EXPECT_EQ(0, memcmp(stringValue->m.value, "AB", 3));
         EXPECT_EQ(3u, stringValue->flexCount());
 
-        stringValue = StringSetting::alloc_unique(11, "initValue");
+        stringValue = StringSetting::AllocUnique(11, "initValue");
         EXPECT_EQ(0, memcmp(stringValue->m.value, "initValue\0", 11));
         EXPECT_EQ(11u, stringValue->flexCount());
 
-        stringValue = StringSetting::alloc_unique(initValue);
+        stringValue = StringSetting::AllocUnique(initValue);
         EXPECT_EQ(0, memcmp(stringValue->m.value, "ABCD", 5));
         EXPECT_EQ(5u, stringValue->flexCount());
 
-        stringValue = StringSetting::alloc_unique({ 'A', 'B', 'C', 'D' });
+        stringValue = StringSetting::AllocUnique({ 'A', 'B', 'C', 'D' });
         EXPECT_EQ(0, memcmp(stringValue->m.value, "ABC", 4));
         EXPECT_EQ(4u, stringValue->flexCount());
     }
@@ -2397,15 +2395,11 @@
 
 // ***********************
 
-}
-
 #include <util/C2ParamUtils.h>
 #include <C2Config.h>
 #include <C2Component.h>
 #include <unordered_map>
 
-namespace android {
-
 C2ENUM(
     MetadataType, int32_t,
     kInvalid = -1,
@@ -2519,7 +2513,7 @@
     public:
         MyParamReflector(const MyComponentInstance *i) : instance(i) { }
 
-        virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex paramIndex) override {
+        virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex paramIndex) const override {
             switch (paramIndex.typeIndex()) {
             case decltype(instance->mDomainInfo)::CORE_INDEX:
             default:
@@ -2537,7 +2531,7 @@
             c2_blocking_t mayBlock) const override {
         (void)mayBlock;
         for (C2FieldSupportedValuesQuery &query : fields) {
-            if (query.field == C2ParamField(&mDomainInfo, &C2ComponentDomainInfo::value)) {
+            if (query.field() == C2ParamField(&mDomainInfo, &C2ComponentDomainInfo::value)) {
                 query.values = C2FieldSupportedValues(
                     false /* flag */,
                     &mDomainInfo.value
@@ -2708,7 +2702,7 @@
         if (f.namedValues().size()) {
             cout << ".named(";
             const char *sep = "";
-            for (const FD::named_value_type &p : f.namedValues()) {
+            for (const FD::NamedValueType &p : f.namedValues()) {
                 cout << sep << p.first << "=";
                 switch (f.type()) {
                 case C2Value::INT32: cout << get(p.second, (int32_t *)0); break;
@@ -2935,4 +2929,3 @@
     EXPECT_EQ(15.25f, fp);
 }
 
-} // namespace android
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index f0e57e2..038be48 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -312,13 +312,15 @@
             addr[C2PlanarLayout::PLANE_V] = nullptr;
             FAIL() << "C2GraphicAllocation::map() failed: " << err;
         }
+        mMappedRect = rect;
+        memcpy(mAddrGraphic, addr, sizeof(uint8_t*) * C2PlanarLayout::MAX_NUM_PLANES);
     }
 
     void unmapGraphic() {
         ASSERT_TRUE(mGraphicAllocation);
 
         // TODO: fence
-        ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(nullptr));
+        ASSERT_EQ(C2_OK, mGraphicAllocation->unmap(mAddrGraphic, mMappedRect, nullptr));
     }
 
     std::shared_ptr<C2BlockPool> makeGraphicBlockPool() {
@@ -330,6 +332,8 @@
     std::shared_ptr<C2LinearAllocation> mLinearAllocation;
     size_t mSize;
     void *mAddr;
+    C2Rect mMappedRect;
+    uint8_t* mAddrGraphic[C2PlanarLayout::MAX_NUM_PLANES];
 
     std::shared_ptr<C2Allocator> mGraphicAllocator;
     std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
diff --git a/media/libstagefright/codec2/vndk/Android.bp b/media/libstagefright/codec2/vndk/Android.bp
index cdd0488..d7709a0 100644
--- a/media/libstagefright/codec2/vndk/Android.bp
+++ b/media/libstagefright/codec2/vndk/Android.bp
@@ -10,6 +10,10 @@
 
 cc_library_shared {
     name: "libstagefright_codec2_vndk",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
 
     srcs: [
         "C2AllocatorIon.cpp",
@@ -23,12 +27,9 @@
         "include",
     ],
 
-    header_libs:[
-        "libstagefright_codec2_internal",
-    ],
-
     include_dirs: [
         "frameworks/av/media/libstagefright/codec2/include",
+        "frameworks/av/media/libstagefright/codec2/vndk/internal",
         "frameworks/native/include/media/hardware",
     ],
 
@@ -42,7 +43,6 @@
         "libhidlbase",
         "libion",
         "liblog",
-        "libmedia",
         "libstagefright_foundation",
         "libui",
         "libutils",
@@ -54,3 +54,7 @@
         "-std=c++14",
     ],
 }
+
+subdirs = [
+    "bufferpool",
+]
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index b287ca8..3d7fc8d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -29,6 +29,36 @@
 
 namespace android {
 
+namespace {
+    enum : uint64_t {
+        /**
+         * Usage mask that is passed through from gralloc to Codec 2.0 usage.
+         */
+        PASSTHROUGH_USAGE_MASK =
+            ~(GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_PROTECTED)
+    };
+
+    // verify that passthrough mask is within the platform mask
+    static_assert((~C2MemoryUsage::PLATFORM_MASK & PASSTHROUGH_USAGE_MASK) == 0, "");
+}
+
+C2MemoryUsage C2AndroidMemoryUsage::FromGrallocUsage(uint64_t usage) {
+    // gralloc does not support WRITE_PROTECTED
+    return C2MemoryUsage(
+            ((usage & GRALLOC_USAGE_SW_READ_MASK) ? C2MemoryUsage::CPU_READ : 0) |
+            ((usage & GRALLOC_USAGE_SW_WRITE_MASK) ? C2MemoryUsage::CPU_WRITE : 0) |
+            ((usage & GRALLOC_USAGE_PROTECTED) ? C2MemoryUsage::READ_PROTECTED : 0) |
+            (usage & PASSTHROUGH_USAGE_MASK));
+}
+
+uint64_t C2AndroidMemoryUsage::asGrallocUsage() const {
+    // gralloc does not support WRITE_PROTECTED
+    return (((expected & C2MemoryUsage::CPU_READ) ? GRALLOC_USAGE_SW_READ_MASK : 0) |
+            ((expected & C2MemoryUsage::CPU_WRITE) ? GRALLOC_USAGE_SW_WRITE_MASK : 0) |
+            ((expected & C2MemoryUsage::READ_PROTECTED) ? GRALLOC_USAGE_PROTECTED : 0) |
+            (expected & PASSTHROUGH_USAGE_MASK));
+}
+
 using ::android::hardware::graphics::allocator::V2_0::IAllocator;
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -183,9 +213,10 @@
     virtual ~C2AllocationGralloc() override;
 
     virtual c2_status_t map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
             C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) override;
-    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) override;
+    virtual c2_status_t unmap(
+            uint8_t **addr /* nonnull */, C2Rect rect, C2Fence *fence /* nullable */) override;
     virtual C2Allocator::id_t getAllocatorId() const override { return mAllocatorId; }
     virtual const C2Handle *handle() const override { return mLockedHandle ? : mHandle; }
     virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const override;
@@ -233,16 +264,18 @@
         return;
     }
     if (mLocked) {
-        unmap(nullptr);
+        // implementation ignores addresss and rect
+        uint8_t* addr[C2PlanarLayout::MAX_NUM_PLANES] = {};
+        unmap(addr, C2Rect(), nullptr);
     }
     mMapper->freeBuffer(const_cast<native_handle_t *>(mBuffer));
 }
 
 c2_status_t C2AllocationGralloc::map(
-        C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+        C2Rect rect, C2MemoryUsage usage, C2Fence *fence,
         C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) {
     // TODO
-    (void) fenceFd;
+    (void) fence;
     (void) usage;
 
     if (mBuffer && mLocked) {
@@ -296,6 +329,7 @@
             addr[C2PlanarLayout::PLANE_V] = (uint8_t *)ycbcrLayout.cr;
             layout->type = C2PlanarLayout::TYPE_YUV;
             layout->numPlanes = 3;
+            layout->rootPlanes = 3;
             layout->planes[C2PlanarLayout::PLANE_Y] = {
                 C2PlaneInfo::CHANNEL_Y,         // channel
                 1,                              // colInc
@@ -306,6 +340,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_Y,        // rootIx
+                0,                              // offset
             };
             layout->planes[C2PlanarLayout::PLANE_U] = {
                 C2PlaneInfo::CHANNEL_CB,          // channel
@@ -317,6 +353,8 @@
                 8,                                // bitDepth
                 0,                                // rightShift
                 C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_U,          // rootIx
+                0,                                // offset
             };
             layout->planes[C2PlanarLayout::PLANE_V] = {
                 C2PlaneInfo::CHANNEL_CR,          // channel
@@ -328,7 +366,20 @@
                 8,                                // bitDepth
                 0,                                // rightShift
                 C2PlaneInfo::NATIVE,              // endianness
+                C2PlanarLayout::PLANE_V,          // rootIx
+                0,                                // offset
             };
+            // handle interleaved formats
+            intptr_t uvOffset = addr[C2PlanarLayout::PLANE_V] - addr[C2PlanarLayout::PLANE_U];
+            if (uvOffset > 0 && uvOffset < (intptr_t)ycbcrLayout.chromaStep) {
+                layout->rootPlanes = 2;
+                layout->planes[C2PlanarLayout::PLANE_V].rootIx = C2PlanarLayout::PLANE_U;
+                layout->planes[C2PlanarLayout::PLANE_V].offset = uvOffset;
+            } else if (uvOffset < 0 && uvOffset > -(intptr_t)ycbcrLayout.chromaStep) {
+                layout->rootPlanes = 2;
+                layout->planes[C2PlanarLayout::PLANE_U].rootIx = C2PlanarLayout::PLANE_V;
+                layout->planes[C2PlanarLayout::PLANE_U].offset = -uvOffset;
+            }
             break;
         }
 
@@ -357,6 +408,7 @@
             addr[C2PlanarLayout::PLANE_B] = (uint8_t *)pointer + 2;
             layout->type = C2PlanarLayout::TYPE_RGB;
             layout->numPlanes = 3;
+            layout->rootPlanes = 1;
             layout->planes[C2PlanarLayout::PLANE_R] = {
                 C2PlaneInfo::CHANNEL_R,         // channel
                 4,                              // colInc
@@ -367,6 +419,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                0,                              // offset
             };
             layout->planes[C2PlanarLayout::PLANE_G] = {
                 C2PlaneInfo::CHANNEL_G,         // channel
@@ -378,6 +432,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                1,                              // offset
             };
             layout->planes[C2PlanarLayout::PLANE_B] = {
                 C2PlaneInfo::CHANNEL_B,         // channel
@@ -389,6 +445,8 @@
                 8,                              // bitDepth
                 0,                              // rightShift
                 C2PlaneInfo::NATIVE,            // endianness
+                C2PlanarLayout::PLANE_R,        // rootIx
+                2,                              // offset
             };
             break;
         }
@@ -401,14 +459,17 @@
     return C2_OK;
 }
 
-c2_status_t C2AllocationGralloc::unmap(C2Fence *fenceFd /* nullable */) {
-    // TODO: fence
+c2_status_t C2AllocationGralloc::unmap(
+        uint8_t **addr, C2Rect rect, C2Fence *fence /* nullable */) {
+    // TODO: check addr and size, use fence
+    (void)addr;
+    (void)rect;
     c2_status_t err = C2_OK;
     mMapper->unlock(
             const_cast<native_handle_t *>(mBuffer),
-            [&err, &fenceFd](const auto &maperr, const auto &releaseFence) {
+            [&err, &fence](const auto &maperr, const auto &releaseFence) {
                 // TODO
-                (void) fenceFd;
+                (void) fence;
                 (void) releaseFence;
                 err = maperr2error(maperr);
                 if (err == C2_OK) {
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index 4328a8d..6b0cffb 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -20,6 +20,7 @@
 
 #include <ion/ion.h>
 #include <sys/mman.h>
+#include <unistd.h>
 
 #include <C2AllocatorIon.h>
 #include <C2Buffer.h>
@@ -116,9 +117,9 @@
 public:
     /* Interface methods */
     virtual c2_status_t map(
-        size_t offset, size_t size, C2MemoryUsage usage, int *fence,
+        size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence,
         void **addr /* nonnull */) override;
-    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd) override;
+    virtual c2_status_t unmap(void *addr, size_t size, C2Fence *fenceFd) override;
     virtual ~C2AllocationIon() override;
     virtual const C2Handle *handle() const override;
     virtual id_t getAllocatorId() const override;
@@ -217,8 +218,8 @@
         return new Impl(ionFd, size, bufferFd, buffer, id, ret);
     }
 
-    c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-        (void)fenceFd; // TODO: wait for fence
+    c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
+        (void)fence; // TODO: wait for fence
         *addr = nullptr;
         if (mMapSize > 0) {
             // TODO: technically we should return DUPLICATE here, but our block views don't
@@ -232,10 +233,10 @@
 
         int prot = PROT_NONE;
         int flags = MAP_PRIVATE;
-        if (usage.consumer & C2MemoryUsage::CPU_READ) {
+        if (usage.expected & C2MemoryUsage::CPU_READ) {
             prot |= PROT_READ;
         }
-        if (usage.producer & C2MemoryUsage::CPU_WRITE) {
+        if (usage.expected & C2MemoryUsage::CPU_WRITE) {
             prot |= PROT_WRITE;
             flags = MAP_SHARED;
         }
@@ -271,7 +272,7 @@
         return err;
     }
 
-    c2_status_t unmap(void *addr, size_t size, int *fenceFd) {
+    c2_status_t unmap(void *addr, size_t size, C2Fence *fence) {
         if (mMapFd < 0 || mMapSize == 0) {
             return C2_NOT_FOUND;
         }
@@ -283,8 +284,8 @@
         if (err != 0) {
             return c2_map_errno<EINVAL>(errno);
         }
-        if (fenceFd) {
-            *fenceFd = -1; // not using fences
+        if (fence) {
+            *fence = C2Fence(); // not using fences
         }
         mMapSize = 0;
         return C2_OK;
@@ -333,12 +334,12 @@
 };
 
 c2_status_t C2AllocationIon::map(
-    size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
-    return mImpl->map(offset, size, usage, fenceFd, addr);
+    size_t offset, size_t size, C2MemoryUsage usage, C2Fence *fence, void **addr) {
+    return mImpl->map(offset, size, usage, fence, addr);
 }
 
-c2_status_t C2AllocationIon::unmap(void *addr, size_t size, int *fenceFd) {
-    return mImpl->unmap(addr, size, fenceFd);
+c2_status_t C2AllocationIon::unmap(void *addr, size_t size, C2Fence *fence) {
+    return mImpl->unmap(addr, size, fence);
 }
 
 c2_status_t C2AllocationIon::status() const {
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 0de8cde..dc765f5 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -18,14 +18,13 @@
 #define LOG_TAG "C2Buffer"
 #include <utils/Log.h>
 
+#include <list>
 #include <map>
 #include <mutex>
 
 #include <C2BufferPriv.h>
 #include <C2BlockInternal.h>
 
-namespace android {
-
 namespace {
 
 // This anonymous namespace contains the helper classes that allow our implementation to create
@@ -34,63 +33,63 @@
 // Inherit from the parent, share with the friend.
 class ReadViewBuddy : public C2ReadView {
     using C2ReadView::C2ReadView;
-    friend class ::android::C2ConstLinearBlock;
+    friend class ::C2ConstLinearBlock;
 };
 
 class WriteViewBuddy : public C2WriteView {
     using C2WriteView::C2WriteView;
-    friend class ::android::C2LinearBlock;
+    friend class ::C2LinearBlock;
 };
 
 class ConstLinearBlockBuddy : public C2ConstLinearBlock {
     using C2ConstLinearBlock::C2ConstLinearBlock;
-    friend class ::android::C2LinearBlock;
+    friend class ::C2LinearBlock;
 };
 
 class LinearBlockBuddy : public C2LinearBlock {
     using C2LinearBlock::C2LinearBlock;
-    friend class ::android::C2BasicLinearBlockPool;
+    friend class ::C2BasicLinearBlockPool;
 };
 
 class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
     using C2Acquirable::C2Acquirable;
-    friend class ::android::C2ConstLinearBlock;
+    friend class ::C2ConstLinearBlock;
 };
 
 class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
     using C2Acquirable::C2Acquirable;
-    friend class ::android::C2LinearBlock;
+    friend class ::C2LinearBlock;
 };
 
 class GraphicViewBuddy : public C2GraphicView {
     using C2GraphicView::C2GraphicView;
-    friend class ::android::C2ConstGraphicBlock;
-    friend class ::android::C2GraphicBlock;
+    friend class ::C2ConstGraphicBlock;
+    friend class ::C2GraphicBlock;
 };
 
 class AcquirableConstGraphicViewBuddy : public C2Acquirable<const C2GraphicView> {
     using C2Acquirable::C2Acquirable;
-    friend class ::android::C2ConstGraphicBlock;
+    friend class ::C2ConstGraphicBlock;
 };
 
 class AcquirableGraphicViewBuddy : public C2Acquirable<C2GraphicView> {
     using C2Acquirable::C2Acquirable;
-    friend class ::android::C2GraphicBlock;
+    friend class ::C2GraphicBlock;
 };
 
 class ConstGraphicBlockBuddy : public C2ConstGraphicBlock {
     using C2ConstGraphicBlock::C2ConstGraphicBlock;
-    friend class ::android::C2GraphicBlock;
+    friend class ::C2GraphicBlock;
 };
 
 class GraphicBlockBuddy : public C2GraphicBlock {
     using C2GraphicBlock::C2GraphicBlock;
-    friend class ::android::C2BasicGraphicBlockPool;
+    friend class ::C2BasicGraphicBlockPool;
 };
 
 class BufferDataBuddy : public C2BufferData {
     using C2BufferData::C2BufferData;
-    friend class ::android::C2Buffer;
+    friend class ::C2Buffer;
 };
 
 }  // namespace
@@ -271,6 +270,7 @@
                 new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
                 [base, len](ReadViewBuddy::Impl *i) {
                     (void)i->getAllocation()->unmap(base, len, nullptr);
+                    delete i;
         });
         return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
     } else {
@@ -300,6 +300,7 @@
                 new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
                 [base, len](WriteViewBuddy::Impl *i) {
                     (void)i->getAllocation()->unmap(base, len, nullptr);
+                    delete i;
         });
         return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
     } else {
@@ -413,6 +414,7 @@
             if (mError != C2_OK) {
                 memset(&mLayout, 0, sizeof(mLayout));
                 memset(mData, 0, sizeof(mData));
+                memset(mOffsetData, 0, sizeof(mData));
             } else {
                 // TODO: validate plane layout and
                 // adjust data pointers to the crop region's top left corner.
@@ -423,14 +425,16 @@
                     if (crop.left % colSampling || crop.right() % colSampling
                             || crop.top % rowSampling || crop.bottom() % rowSampling) {
                         // cannot calculate data pointer
-                        mImpl->getAllocation()->unmap(nullptr);
+                        mImpl->getAllocation()->unmap(mData, crop, nullptr);
                         memset(&mLayout, 0, sizeof(mLayout));
                         memset(mData, 0, sizeof(mData));
+                        memset(mOffsetData, 0, sizeof(mData));
                         mError = C2_BAD_VALUE;
                         return;
                     }
-                    mData[planeIx] += (ssize_t)crop.left * mLayout.planes[planeIx].colInc
-                            + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
+                    mOffsetData[planeIx] =
+                        mData[planeIx] + (ssize_t)crop.left * mLayout.planes[planeIx].colInc
+                                + (ssize_t)crop.top * mLayout.planes[planeIx].rowInc;
                 }
             }
         }
@@ -440,12 +444,13 @@
             // CHECK(error != C2_OK);
             memset(&mLayout, 0, sizeof(mLayout));
             memset(mData, 0, sizeof(mData));
+            memset(mOffsetData, 0, sizeof(mData));
         }
 
     public:
         ~Mapped() {
             if (mData[0] != nullptr) {
-                mImpl->getAllocation()->unmap(nullptr);
+                mImpl->getAllocation()->unmap(mData, mImpl->crop(), nullptr);
             }
         }
 
@@ -453,7 +458,7 @@
         c2_status_t error() const { return mError; }
 
         /** returns data pointer */
-        uint8_t *const *data() const { return mData; }
+        uint8_t *const *data() const { return mOffsetData; }
 
         /** returns the plane layout */
         C2PlanarLayout layout() const { return mLayout; }
@@ -466,6 +471,7 @@
         bool mWritable;
         c2_status_t mError;
         uint8_t *mData[C2PlanarLayout::MAX_NUM_PLANES];
+        uint8_t *mOffsetData[C2PlanarLayout::MAX_NUM_PLANES];
         C2PlanarLayout mLayout;
     };
 
@@ -791,4 +797,13 @@
     return mImpl->removeInfo(index);
 }
 
-} // namespace android
+// static
+std::shared_ptr<C2Buffer> C2Buffer::CreateLinearBuffer(const C2ConstLinearBlock &block) {
+    return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
+}
+
+// static
+std::shared_ptr<C2Buffer> C2Buffer::CreateGraphicBuffer(const C2ConstGraphicBlock &block) {
+    return std::shared_ptr<C2Buffer>(new C2Buffer({ block }));
+}
+
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
index 05b46c3..f612b4f 100644
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -136,13 +136,13 @@
     switch (id) {
     case C2BlockPool::BASIC_LINEAR:
         res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
-        if (res == OK) {
+        if (res == C2_OK) {
             *pool = std::make_shared<C2BasicLinearBlockPool>(allocator);
         }
         break;
     case C2BlockPool::BASIC_GRAPHIC:
         res = allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
-        if (res == OK) {
+        if (res == C2_OK) {
             *pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
         }
         break;
@@ -203,9 +203,17 @@
         /**
          * Creates an uninitialized component module.
          *
+         * \param name[in]  component name.
+         *
          * \note Only used by ComponentLoader.
          */
-        ComponentModule() : mInit(C2_NO_INIT) {}
+        ComponentModule()
+            : mInit(C2_NO_INIT),
+              mLibHandle(nullptr),
+              createFactory(nullptr),
+              destroyFactory(nullptr),
+              mComponentFactory(nullptr) {
+        }
 
         /**
          * Initializes a component module with a given library path. Must be called exactly once.
@@ -345,7 +353,7 @@
 
 c2_status_t C2PlatformComponentStore::ComponentModule::createInterface(
         c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *interface,
-        std::function<void(::android::C2ComponentInterface*)> deleter) {
+        std::function<void(::C2ComponentInterface*)> deleter) {
     interface->reset();
     if (mInit != C2_OK) {
         return mInit;
@@ -362,7 +370,7 @@
 
 c2_status_t C2PlatformComponentStore::ComponentModule::createComponent(
         c2_node_id_t id, std::shared_ptr<C2Component> *component,
-        std::function<void(::android::C2Component*)> deleter) {
+        std::function<void(::C2Component*)> deleter) {
     component->reset();
     if (mInit != C2_OK) {
         return mInit;
@@ -383,12 +391,35 @@
         std::shared_ptr<C2ComponentInterface> intf;
         c2_status_t res = createInterface(0, &intf);
         if (res != C2_OK) {
+            ALOGD("failed to create interface: %d", res);
             return nullptr;
         }
 
         std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
         if (traits) {
-            // traits->name = intf->getName();
+            traits->name = intf->getName();
+            // TODO: get this from interface properly.
+            bool encoder = (traits->name.find("encoder") != std::string::npos);
+            uint32_t mediaTypeIndex = encoder ? C2PortMimeConfig::output::PARAM_TYPE
+                    : C2PortMimeConfig::input::PARAM_TYPE;
+            std::vector<std::unique_ptr<C2Param>> params;
+            res = intf->query_vb({}, { mediaTypeIndex }, C2_MAY_BLOCK, &params);
+            if (res != C2_OK) {
+                ALOGD("failed to query interface: %d", res);
+                return nullptr;
+            }
+            if (params.size() != 1u) {
+                ALOGD("failed to query interface: unexpected vector size: %zu", params.size());
+                return nullptr;
+            }
+            C2PortMimeConfig *mediaTypeConfig = (C2PortMimeConfig *)(params[0].get());
+            if (mediaTypeConfig == nullptr) {
+                ALOGD("failed to query media type");
+                return nullptr;
+            }
+            traits->mediaType = mediaTypeConfig->m.value;
+            // TODO: get this properly.
+            traits->rank = 0x200;
         }
 
         mTraits = traits;
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp b/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp
new file mode 100644
index 0000000..3571ed5
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/Accessor.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Accessor.h"
+#include "AccessorImpl.h"
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::bufferpool::V1_0::IAccessor follow.
+Return<void> Accessor::connect(connect_cb _hidl_cb) {
+    sp<Connection> connection;
+    ConnectionId connectionId;
+    const QueueDescriptor* fmqDesc;
+
+    ResultStatus status = connect(&connection, &connectionId, &fmqDesc);
+    if (status == ResultStatus::OK) {
+        _hidl_cb(status, connection, connectionId, *fmqDesc);
+    } else {
+        _hidl_cb(status, nullptr, -1LL,
+                 android::hardware::MQDescriptorSync<BufferStatusMessage>(
+                         std::vector<android::hardware::GrantorDescriptor>(),
+                         nullptr /* nhandle */, 0 /* size */));
+    }
+    return Void();
+}
+
+Accessor::Accessor(const std::shared_ptr<C2Allocator> &allocator, bool linear)
+    : mImpl(new Impl(allocator, linear)) {}
+
+Accessor::~Accessor() {
+}
+
+bool Accessor::isValid() {
+    return (bool)mImpl;
+}
+
+ResultStatus Accessor::allocate(
+        ConnectionId connectionId,
+        const std::vector<uint8_t> &params,
+        BufferId *bufferId, const native_handle_t** handle) {
+    if (mImpl) {
+        return mImpl->allocate(connectionId, params, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus Accessor::fetch(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, const native_handle_t** handle) {
+    if (mImpl) {
+        return mImpl->fetch(connectionId, transactionId, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus Accessor::connect(
+        sp<Connection> *connection, ConnectionId *pConnectionId,
+        const QueueDescriptor** fmqDescPtr) {
+    if (mImpl) {
+        return mImpl->connect(this, connection, pConnectionId, fmqDescPtr);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus Accessor::close(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->close(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+//IAccessor* HIDL_FETCH_IAccessor(const char* /* name */) {
+//    return new Accessor();
+//}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Accessor.h b/media/libstagefright/codec2/vndk/bufferpool/Accessor.h
new file mode 100644
index 0000000..6fd82ba
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/Accessor.h
@@ -0,0 +1,144 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
+
+#include <android/hardware/media/bufferpool/1.0/IAccessor.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <C2Buffer.h>
+#include <BufferPoolTypes.h>
+#include "BufferStatus.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Connection;
+
+/**
+ * A buffer pool accessor which enables a buffer pool to communicate with buffer
+ * pool clients. 1:1 correspondense holds between a buffer pool and an accessor.
+ */
+struct Accessor : public IAccessor {
+    // Methods from ::android::hardware::media::bufferpool::V1_0::IAccessor follow.
+    Return<void> connect(connect_cb _hidl_cb) override;
+
+    /**
+     * Creates a buffer pool accessor which uses the specified allocator.
+     *
+     * @param allocator buffer allocator.
+     * @param linear    whether the allocator is linear or not.
+     */
+    Accessor(const std::shared_ptr<C2Allocator> &allocator, bool linear);
+
+    /** Destructs a buffer pool accessor. */
+    ~Accessor();
+
+    /** Returns whether the accessor is valid. */
+    bool isValid();
+
+    /** Allocates a buffer form a buffer pool.
+     *
+     * @param connectionId  the connection id of the client.
+     * @param params        the allocation parameters.
+     * @param bufferId      the id of the allocated buffer.
+     * @param handle        the native handle of the allocated buffer.
+     *
+     * @return OK when a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus allocate(
+            ConnectionId connectionId,
+            const std::vector<uint8_t>& params,
+            BufferId *bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Fetches a buffer for the specified transaction.
+     *
+     * @param connectionId  the id of receiving connection(client).
+     * @param transactionId the id of the transfer transaction.
+     * @param bufferId      the id of the buffer to be fetched.
+     * @param handle        the native handle of the fetched buffer.
+     *
+     * @return OK when a buffer is successfully fetched.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus fetch(
+            ConnectionId connectionId,
+            TransactionId transactionId,
+            BufferId bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Makes a connection to the buffer pool. The buffer pool client uses the
+     * created connection in order to communicate with the buffer pool. An
+     * FMQ for buffer status message is also created for the client.
+     *
+     * @param connection    created connection
+     * @param pConnectionId the id of the created connection
+     * @param fmqDescPtr    FMQ descriptor for shared buffer status message
+     *                      queue between a buffer pool and the client.
+     *
+     * @return OK when a connection is successfully made.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus connect(
+            sp<Connection> *connection, ConnectionId *pConnectionId,
+            const QueueDescriptor** fmqDescPtr);
+
+    /**
+     * Closes the specified connection to the client.
+     *
+     * @param connectionId  the id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus close(ConnectionId connectionId);
+
+private:
+    class Impl;
+    std::unique_ptr<Impl> mImpl;
+};
+
+// FIXME: most likely delete, this is only for passthrough implementations
+// extern "C" IAccessor* HIDL_FETCH_IAccessor(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSOR_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp
new file mode 100644
index 0000000..f8aec53
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.cpp
@@ -0,0 +1,542 @@
+/*
+ * 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_TAG "bufferpool"
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <C2Buffer.h>
+#include "AccessorImpl.h"
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+// Buffer structure in bufferpool process
+struct InternalBuffer {
+    BufferId mId;
+    size_t mOwnerCount;
+    size_t mTransactionCount;
+    const bool mLinear;
+    const std::shared_ptr<C2LinearAllocation> mLinearAllocation;
+    const std::shared_ptr<C2GraphicAllocation> mGraphicAllocation;
+    const std::vector<uint8_t> mConfig;
+
+    InternalBuffer(
+            BufferId id,
+            const std::shared_ptr<C2LinearAllocation> &alloc,
+            const std::vector<uint8_t> &allocConfig)
+            : mId(id), mOwnerCount(0), mTransactionCount(0),
+            mLinear(true), mLinearAllocation(alloc),
+            mGraphicAllocation(nullptr),
+            mConfig(allocConfig) {}
+
+    InternalBuffer(
+            BufferId id,
+            const std::shared_ptr<C2GraphicAllocation> &alloc,
+            const std::vector<uint8_t> &allocConfig)
+            : mId(id), mOwnerCount(0), mTransactionCount(0),
+            mLinear(false), mLinearAllocation(nullptr),
+            mGraphicAllocation(alloc),
+            mConfig(allocConfig) {}
+
+    const native_handle_t *handle() {
+        if (mLinear) {
+            return mLinearAllocation->handle();
+        } else {
+            return mGraphicAllocation->handle();
+        }
+    }
+
+    // TODO : support non exact matching. e.g) capacity
+    bool isRecyclable(const std::vector<uint8_t> &config) {
+        if (mConfig.size() == config.size()) {
+            for (size_t i = 0; i < config.size(); ++i) {
+                if (mConfig[i] != config[i]) {
+                    return false;
+                }
+            }
+                return true;
+        }
+        return false;
+    }
+};
+
+struct TransactionStatus {
+    TransactionId mId;
+    BufferId mBufferId;
+    ConnectionId mSender;
+    ConnectionId mReceiver;
+    BufferStatus mStatus;
+    int64_t mTimestampUs;
+    bool mSenderValidated;
+
+    TransactionStatus(const BufferStatusMessage &message, int64_t timestampUs) {
+        mId = message.transactionId;
+        mBufferId = message.bufferId;
+        mStatus = message.newStatus;
+        mTimestampUs = timestampUs;
+        if (mStatus == BufferStatus::TRANSFER_TO) {
+            mSender = message.connectionId;
+            mReceiver = message.targetConnectionId;
+            mSenderValidated = true;
+        } else {
+            mSender = -1LL;
+            mReceiver = message.connectionId;
+            mSenderValidated = false;
+        }
+    }
+};
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter == mapOfSet->end()) {
+        std::set<U> valueSet{value};
+        mapOfSet->insert(std::make_pair(key, valueSet));
+        return true;
+    } else if (iter->second.find(value)  == iter->second.end()) {
+        iter->second.insert(value);
+        return true;
+    }
+    return false;
+}
+
+template<class T, class U>
+bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    bool ret = false;
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        if (iter->second.erase(value) > 0) {
+            ret = true;
+        }
+        if (iter->second.size() == 0) {
+            mapOfSet->erase(iter);
+        }
+    }
+    return ret;
+}
+
+template<class T, class U>
+bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        auto setIter = iter->second.find(value);
+        return setIter != iter->second.end();
+    }
+    return false;
+}
+
+
+int32_t Accessor::Impl::sPid = getpid();
+uint32_t Accessor::Impl::sSeqId = time(NULL);
+
+Accessor::Impl::Impl(
+        const std::shared_ptr<C2Allocator> &allocator, bool linear)
+        : mAllocator(allocator), mLinear(linear) {}
+
+Accessor::Impl::~Impl() {
+}
+
+ResultStatus Accessor::Impl::connect(
+        const sp<Accessor> &accessor, sp<Connection> *connection,
+        ConnectionId *pConnectionId, const QueueDescriptor** fmqDescPtr) {
+    sp<Connection> newConnection = new Connection();
+    ResultStatus status = ResultStatus::CRITICAL_ERROR;
+    if (newConnection) {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        ConnectionId id = (int64_t)sPid << 32 | sSeqId;
+        status = mBufferPool.mObserver.open(id, fmqDescPtr);
+        if (status == ResultStatus::OK) {
+            newConnection->initialize(accessor, id);
+            *connection = newConnection;
+            *pConnectionId = id;
+            ++sSeqId;
+        }
+    }
+    return status;
+}
+
+ResultStatus Accessor::Impl::close(ConnectionId connectionId) {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.handleClose(connectionId);
+    mBufferPool.mObserver.close(connectionId);
+    return ResultStatus::OK;
+}
+
+ResultStatus Accessor::Impl::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t>& params,
+        BufferId *bufferId, const native_handle_t** handle) {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    ResultStatus status = ResultStatus::OK;
+    if (!mBufferPool.getFreeBuffer(params, bufferId, handle)) {
+        if (mLinear) {
+            status = mBufferPool.getNewLinearBuffer(
+                    mAllocator, params, bufferId, handle);
+        } else {
+            status = mBufferPool.getNewGraphicBuffer(
+                    mAllocator, params, bufferId, handle);
+        }
+        ALOGV("create a buffer %d : %u %p",
+              status == ResultStatus::OK, *bufferId, *handle);
+    }
+    if (status == ResultStatus::OK) {
+        // TODO: handle ownBuffer failure
+        mBufferPool.handleOwnBuffer(connectionId, *bufferId);
+    }
+    return status;
+}
+
+ResultStatus Accessor::Impl::fetch(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, const native_handle_t** handle) {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    auto found = mBufferPool.mTransactions.find(transactionId);
+    if (found != mBufferPool.mTransactions.end() &&
+            contains(&mBufferPool.mPendingTransactions,
+                     connectionId, transactionId)) {
+        if (found->second->mSenderValidated &&
+                found->second->mStatus == BufferStatus::TRANSFER_FROM &&
+                found->second->mBufferId == bufferId) {
+            found->second->mStatus = BufferStatus::TRANSFER_FETCH;
+            auto bufferIt = mBufferPool.mBuffers.find(bufferId);
+            if (bufferIt != mBufferPool.mBuffers.end()) {
+                *handle = bufferIt->second->handle();
+                return ResultStatus::OK;
+            }
+        }
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void Accessor::Impl::sync() {
+    // TODO: periodic jobs
+    // transaction timeout, buffer cacheing TTL handling
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+}
+
+Accessor::Impl::Impl::BufferPool::BufferPool()
+        : mTimestampUs(getTimestampNow()), mSeq(0) {}
+
+bool Accessor::Impl::BufferPool::handleOwnBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+
+    bool added = insert(&mUsingBuffers, connectionId, bufferId);
+    if (added) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount++;
+    }
+    insert(&mUsingConnections, bufferId, connectionId);
+    return added;
+}
+
+bool Accessor::Impl::BufferPool::handleReleaseBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+    bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
+    if (deleted) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount--;
+        if (iter->second->mOwnerCount == 0 &&
+                iter->second->mTransactionCount == 0) {
+            mFreeBuffers.insert(bufferId);
+        }
+    }
+    erase(&mUsingConnections, bufferId, connectionId);
+    ALOGV("release buffer %u : %d", bufferId, deleted);
+    return deleted;
+}
+
+bool Accessor::Impl::BufferPool::handleTransferTo(const BufferStatusMessage &message) {
+    auto completed = mCompletedTransactions.find(
+            message.transactionId);
+    if (completed != mCompletedTransactions.end()) {
+        // already completed
+        mCompletedTransactions.erase(completed);
+        return true;
+    }
+    // the buffer should exist and be owned.
+    auto bufferIter = mBuffers.find(message.bufferId);
+    if (bufferIter == mBuffers.end() ||
+            !contains(&mUsingBuffers, message.connectionId, message.bufferId)) {
+        return false;
+    }
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        // transfer_from was received earlier.
+        found->second->mSender = message.connectionId;
+        found->second->mSenderValidated = true;
+        return true;
+    }
+    // TODO: verify there is target connection Id
+    mTransactions.insert(std::make_pair(
+            message.transactionId,
+            std::make_unique<TransactionStatus>(message, mTimestampUs)));
+    insert(&mPendingTransactions, message.targetConnectionId,
+           message.transactionId);
+    bufferIter->second->mTransactionCount++;
+    return true;
+}
+
+bool Accessor::Impl::BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found == mTransactions.end()) {
+        // TODO: is it feasible to check ownership here?
+        mTransactions.insert(std::make_pair(
+                message.transactionId,
+                std::make_unique<TransactionStatus>(message, mTimestampUs)));
+        insert(&mPendingTransactions, message.connectionId,
+               message.transactionId);
+        auto bufferIter = mBuffers.find(message.bufferId);
+        bufferIter->second->mTransactionCount++;
+    } else {
+        if (message.connectionId == found->second->mReceiver) {
+            found->second->mStatus = BufferStatus::TRANSFER_FROM;
+        }
+    }
+    return true;
+}
+
+bool Accessor::Impl::BufferPool::handleTransferResult(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        bool deleted = erase(&mPendingTransactions, message.connectionId,
+                             message.transactionId);
+        if (deleted) {
+            if (!found->second->mSenderValidated) {
+                mCompletedTransactions.insert(message.transactionId);
+            }
+            auto bufferIter = mBuffers.find(message.bufferId);
+            if (message.newStatus == BufferStatus::TRANSFER_OK) {
+                handleOwnBuffer(message.connectionId, message.bufferId);
+            }
+            bufferIter->second->mTransactionCount--;
+            if (bufferIter->second->mOwnerCount == 0
+                && bufferIter->second->mTransactionCount == 0) {
+                mFreeBuffers.insert(message.bufferId);
+            }
+        }
+        ALOGV("transfer finished %" PRIu64 " %u - %d", message.transactionId,
+              message.bufferId, deleted);
+        return deleted;
+    }
+    ALOGV("transfer not found %" PRIu64 " %u", message.transactionId,
+          message.bufferId);
+    return false;
+}
+
+void Accessor::Impl::BufferPool::processStatusMessages() {
+    std::vector<BufferStatusMessage> messages;
+    mObserver.getBufferStatusChanges(messages);
+    mTimestampUs = getTimestampNow();
+    for (BufferStatusMessage& message: messages) {
+        bool ret = false;
+        switch (message.newStatus) {
+            case BufferStatus::NOT_USED:
+                ret = handleReleaseBuffer(
+                        message.connectionId, message.bufferId);
+                break;
+            case BufferStatus::USED:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_TO:
+                ret = handleTransferTo(message);
+                break;
+            case BufferStatus::TRANSFER_FROM:
+                ret = handleTransferFrom(message);
+                break;
+            case BufferStatus::TRANSFER_TIMEOUT:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_LOST:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_FETCH:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_OK:
+            case BufferStatus::TRANSFER_ERROR:
+                ret = handleTransferResult(message);
+                break;
+        }
+        if (ret == false) {
+            ALOGW("buffer status message processing failure - message : %d "
+                  "connection : %" PRId64,
+                  message.newStatus, message.connectionId);
+        }
+    }
+    messages.clear();
+}
+
+bool Accessor::Impl::BufferPool::handleClose(ConnectionId connectionId) {
+    // Cleaning buffers
+    auto buffers = mUsingBuffers.find(connectionId);
+    if (buffers != mUsingBuffers.end()) {
+        for (const BufferId& bufferId : buffers->second) {
+            bool deleted = erase(&mUsingConnections, bufferId, connectionId);
+            if (deleted) {
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mOwnerCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                        bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    mFreeBuffers.insert(bufferId);
+                }
+            }
+        }
+        mUsingBuffers.erase(buffers);
+    }
+
+    // Cleaning transactions
+    auto pending = mPendingTransactions.find(connectionId);
+    if (pending != mPendingTransactions.end()) {
+        for (const TransactionId& transactionId : pending->second) {
+            auto iter = mTransactions.find(transactionId);
+            if (iter != mTransactions.end()) {
+                if (!iter->second->mSenderValidated) {
+                    mCompletedTransactions.insert(transactionId);
+                }
+                BufferId bufferId = iter->second->mBufferId;
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mTransactionCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                    bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    mFreeBuffers.insert(bufferId);
+                }
+                mTransactions.erase(iter);
+            }
+        }
+    }
+    return true;
+}
+
+bool Accessor::Impl::BufferPool::getFreeBuffer(
+        const std::vector<uint8_t> &params, BufferId *pId,
+        const native_handle_t** handle) {
+    auto bufferIt = mFreeBuffers.begin();
+    for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
+        BufferId bufferId = *bufferIt;
+        if (mBuffers[bufferId]->isRecyclable(params)) {
+            break;
+        }
+    }
+    if (bufferIt != mFreeBuffers.end()) {
+        BufferId id = *bufferIt;
+        mFreeBuffers.erase(bufferIt);
+        *handle = mBuffers[id]->handle();
+        *pId = id;
+        ALOGV("recycle a buffer %u %p", id, *handle);
+        return true;
+    }
+    return false;
+}
+
+ResultStatus Accessor::Impl::BufferPool::getNewLinearBuffer(
+        const std::shared_ptr<C2Allocator> &allocator,
+        const std::vector<uint8_t> &params, BufferId *pId,
+        const native_handle_t** handle) {
+    union LinearParam {
+        struct {
+            uint32_t capacity;
+            C2MemoryUsage usage;
+        } data;
+        uint8_t array[0];
+        LinearParam() : data{0, {0, 0}} {}
+    } linearParam;
+    memcpy(&linearParam, params.data(),
+           std::min(sizeof(linearParam), params.size()));
+    std::shared_ptr<C2LinearAllocation> linearAlloc;
+    c2_status_t status = allocator->newLinearAllocation(
+            linearParam.data.capacity, linearParam.data.usage, &linearAlloc);
+    if (status == C2_OK) {
+        BufferId bufferId = mSeq++;
+        std::unique_ptr<InternalBuffer> buffer =
+                std::make_unique<InternalBuffer>(
+                        bufferId, linearAlloc, params);
+        if (buffer) {
+            auto res = mBuffers.insert(std::make_pair(
+                    bufferId, std::move(buffer)));
+            if (res.second) {
+                *handle = linearAlloc->handle();
+                *pId = bufferId;
+                return ResultStatus::OK;
+            }
+        }
+        return ResultStatus::NO_MEMORY;
+    }
+    // TODO: map C2 error code
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus Accessor::Impl::BufferPool::getNewGraphicBuffer(
+        const std::shared_ptr<C2Allocator> &allocator,
+        const std::vector<uint8_t> &params, BufferId *pId,
+        const native_handle_t** handle) {
+    union GraphicParam {
+        struct {
+            uint32_t width;
+            uint32_t height;
+            uint32_t format;
+            C2MemoryUsage usage;
+        } data;
+        uint8_t array[0];
+        GraphicParam() : data{0, 0, 0, {0, 0}} {}
+    } graphicParam;
+    memcpy(&graphicParam, params.data(),
+           std::min(sizeof(graphicParam), params.size()));
+    std::shared_ptr<C2GraphicAllocation> graphicAlloc;
+    c2_status_t status = allocator->newGraphicAllocation(
+            graphicParam.data.width, graphicParam.data.height,
+            graphicParam.data.format, graphicParam.data.usage, &graphicAlloc);
+    if (status == C2_OK) {
+        BufferId bufferId = mSeq;
+        std::unique_ptr<InternalBuffer> buffer =
+                std::make_unique<InternalBuffer>(
+                        bufferId, graphicAlloc, params);
+        if (buffer) {
+            auto res = mBuffers.insert(std::make_pair(
+                    bufferId, std::move(buffer)));
+            if (res.second) {
+                *handle = graphicAlloc->handle();
+                *pId = bufferId;
+                return ResultStatus::OK;
+            }
+        }
+        return ResultStatus::NO_MEMORY;
+    }
+    // TODO: map C2 error code
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h
new file mode 100644
index 0000000..92d926c
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/AccessorImpl.h
@@ -0,0 +1,230 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
+
+#include <map>
+#include <set>
+#include "Accessor.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+struct InternalBuffer;
+struct TransactionStatus;
+
+/**
+ * An implementation of a buffer pool accessor(or a buffer pool implementation.) */
+class Accessor::Impl {
+public:
+    Impl(const std::shared_ptr<C2Allocator> &allocator, bool linear);
+
+    ~Impl();
+
+    ResultStatus connect(
+            const sp<Accessor> &accessor, sp<Connection> *connection,
+            ConnectionId *pConnectionId, const QueueDescriptor** fmqDescPtr);
+
+    ResultStatus close(ConnectionId connectionId);
+
+    ResultStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t>& params,
+                          BufferId *bufferId,
+                          const native_handle_t** handle);
+
+    ResultStatus fetch(ConnectionId connectionId,
+                       TransactionId transactionId,
+                       BufferId bufferId,
+                       const native_handle_t** handle);
+
+    /** Processes pending buffer status messages */
+    void sync();
+
+private:
+    // ConnectionId = pid : (timestamp_created + seqId)
+    // in order to guarantee uniqueness for each connection
+    static uint32_t sSeqId;
+    static int32_t sPid;
+
+    const std::shared_ptr<C2Allocator> mAllocator;
+    bool mLinear;
+
+    /**
+     * Buffer pool implementation.
+     *
+     * Handles buffer status messages. Handles buffer allocation/recycling.
+     * Handles buffer transfer between buffer pool clients.
+     */
+    struct BufferPool {
+    private:
+        std::mutex mMutex;
+        int64_t mTimestampUs;
+        BufferId mSeq;
+        BufferStatusObserver mObserver;
+
+        std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
+        std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
+
+        std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
+        // Transactions completed before TRANSFER_TO message arrival.
+        // Fetch does not occur for the transactions.
+        // Only transaction id is kept for the transactions in short duration.
+        std::set<TransactionId> mCompletedTransactions;
+        // Currently active(pending) transations' status & information.
+        std::map<TransactionId, std::unique_ptr<TransactionStatus>>
+                mTransactions;
+
+        std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
+        std::set<BufferId> mFreeBuffers;
+
+    public:
+        /** Creates a buffer pool. */
+        BufferPool();
+
+        /**
+         * Processes all pending buffer status messages, and returns the result.
+         * Each status message is handled by methods with 'handle' prefix.
+         */
+        void processStatusMessages();
+
+        /**
+         * Handles a buffer being owned by a connection.
+         *
+         * @param connectionId  the id of the buffer owning connection.
+         * @param bufferId      the id of the buffer.
+         *
+         * @return {@code true} when the buffer is owned,
+         *         {@code false} otherwise.
+         */
+        bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
+
+        /**
+         * Handles a buffer being released by a connection.
+         *
+         * @param connectionId  the id of the buffer owning connection.
+         * @param bufferId      the id of the buffer.
+         *
+         * @return {@code true} when the buffer ownership is released,
+         *         {@code false} otherwise.
+         */
+        bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
+
+        /**
+         * Handles a transfer transaction start message from the sender.
+         *
+         * @param message   a buffer status message for the transaction.
+         *
+         * @result {@code true} when transfer_to message is acknowledged,
+         *         {@code false} otherwise.
+         */
+        bool handleTransferTo(const BufferStatusMessage &message);
+
+        /**
+         * Handles a transfer transaction being acked by the receiver.
+         *
+         * @param message   a buffer status message for the transaction.
+         *
+         * @result {@code true} when transfer_from message is acknowledged,
+         *         {@code false} otherwise.
+         */
+        bool handleTransferFrom(const BufferStatusMessage &message);
+
+        /**
+         * Handles a transfer transaction result message from the receiver.
+         *
+         * @param message   a buffer status message for the transaction.
+         *
+         * @result {@code true} when the exisitng transaction is finished,
+         *         {@code false} otherwise.
+         */
+        bool handleTransferResult(const BufferStatusMessage &message);
+
+        /**
+         * Handles a connection being closed, and returns the result. All the
+         * buffers and transactions owned by the connection will be cleaned up.
+         * The related FMQ will be cleaned up too.
+         *
+         * @param connectionId  the id of the connection.
+         *
+         * @result {@code true} when the connection existed,
+         *         {@code false} otherwise.
+         */
+        bool handleClose(ConnectionId connectionId);
+
+        /**
+         * Recycles a existing free buffer if it is possible.
+         *
+         * @param params    the allocation parameters.
+         * @param pId       the id of the recycled buffer.
+         * @param handle    the native handle of the recycled buffer.
+         *
+         * @return {@code true} when a buffer is recycled, {@code false}
+         *         otherwise.
+         */
+        bool getFreeBuffer(const std::vector<uint8_t> &params, BufferId *pId,
+                           const native_handle_t **handle);
+
+        /**
+         * Creates a new linear buffer.
+         *
+         * @param allocator the linear buffer allocator
+         * @param params    the allocator parameters
+         * @param pId       the buffer id for the newly allocated buffer.
+         * @param handle    the native handle for the newly allocated buffer.
+         *
+         * @return OK when a linear allocation is successfully allocated.
+         *         NO_MEMORY when there is no memory.
+         *         CRITICAL_ERROR otherwise.
+         */
+        ResultStatus getNewLinearBuffer(
+                const std::shared_ptr<C2Allocator> &allocator,
+                const std::vector<uint8_t> &params, BufferId *pId,
+                const native_handle_t **handle);
+
+        /**
+         * Creates a new graphic buffer.
+         *
+         * @param allocator the graphic buffer allocator
+         * @param params    the allocator parameters
+         * @param pId       the buffer id for the newly allocated buffer.
+         * @param handle    the native handle for the newly allocated buffer.
+         *
+         * @return OK when a graphic allocation is successfully allocated.
+         *         NO_MEMORY when there is no memory.
+         *         CRITICAL_ERROR otherwise.
+         */
+        ResultStatus getNewGraphicBuffer(
+                const std::shared_ptr<C2Allocator> &allocator,
+                const std::vector<uint8_t> &params, BufferId *pId,
+                const native_handle_t **handle);
+
+        friend class Accessor::Impl;
+    } mBufferPool;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace ufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_ACCESSORIMPL_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Android.bp b/media/libstagefright/codec2/vndk/bufferpool/Android.bp
new file mode 100644
index 0000000..f0588d5
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/Android.bp
@@ -0,0 +1,31 @@
+cc_library_shared {
+    name: "android.hardware.media.bufferpool@1.0-impl",
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "Accessor.cpp",
+        "AccessorImpl.cpp",
+        "BufferPoolClient.cpp",
+        "BufferStatus.cpp",
+        "ClientManager.cpp",
+        "Connection.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    include_dirs: [
+        "frameworks/av/media/libstagefright/codec2/vndk/bufferpool/include",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libstagefright_codec2",
+        "libutils",
+        "android.hardware.media.bufferpool@1.0",
+    ],
+}
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.cpp b/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.cpp
new file mode 100644
index 0000000..7cb4ba9
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.cpp
@@ -0,0 +1,566 @@
+/*
+ * 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_TAG "bufferpool"
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+#include <thread>
+#include <utils/Log.h>
+#include "BufferPoolClient.h"
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+static constexpr int64_t kReceiveTimeoutUs = 5000; // 5ms
+static constexpr int kPostMaxRetry = 3;
+static constexpr int kCacheTtlUs = 500000; // TODO: tune
+
+class BufferPoolClient::Impl
+        : public std::enable_shared_from_this<BufferPoolClient::Impl> {
+public:
+    explicit Impl(const sp<Accessor> &accessor);
+
+    explicit Impl(const sp<IAccessor> &accessor);
+
+    bool isValid() {
+        return mValid;
+    }
+
+    ConnectionId getConnectionId() {
+        return mConnectionId;
+    }
+
+    sp<IAccessor> &getAccessor() {
+        return mAccessor;
+    }
+
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                         std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    ResultStatus receive(
+            TransactionId transactionId, BufferId bufferId,
+            int64_t timestampUs, std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    void postBufferRelease(BufferId bufferId);
+
+    bool postSend(
+            BufferId bufferId, ConnectionId receiver,
+            TransactionId *transactionId, int64_t *timestampUs);
+private:
+
+    bool postReceive(
+            BufferId bufferId, TransactionId transactionId,
+            int64_t timestampUs);
+
+    bool postReceiveResult(
+            BufferId bufferId, TransactionId transactionId, bool result);
+
+    bool syncReleased();
+
+    ResultStatus allocateBufferHandle(
+            const std::vector<uint8_t>& params, BufferId *bufferId,
+            native_handle_t **handle);
+
+    ResultStatus fetchBufferHandle(
+            TransactionId transactionId, BufferId bufferId,
+            native_handle_t **handle);
+
+
+    struct BlockPoolDataDtor;
+    struct ClientBuffer;
+
+    bool mLocal;
+    bool mValid;
+    sp<IAccessor> mAccessor;
+    sp<Connection> mLocalConnection;
+    sp<IConnection> mRemoteConnection;
+    uint32_t mSeqId;
+    ConnectionId mConnectionId;
+
+    // CachedBuffers
+    struct {
+        std::mutex mLock;
+        bool creating;
+        std::condition_variable mCreateCv;
+        std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
+    } mCache;
+
+    // FMQ - release notifier
+    struct {
+        std::mutex mLock;
+        // TODO: use only one list?(using one list may dealy sending messages?)
+        std::list<BufferId> mReleasingIds;
+        std::list<BufferId> mReleasedIds;
+        std::unique_ptr<BufferStatusChannel> mStatusChannel;
+    } mReleasing;
+};
+
+struct BufferPoolClient::Impl::BlockPoolDataDtor {
+    BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
+            : mImpl(impl) {}
+
+    void operator()(_C2BlockPoolData *buffer) {
+        BufferId id = buffer->mId;
+        delete buffer;
+
+        auto impl = mImpl.lock();
+        if (impl && impl->isValid()) {
+            impl->postBufferRelease(id);
+        }
+    }
+    const std::weak_ptr<BufferPoolClient::Impl> mImpl;
+};
+
+struct BufferPoolClient::Impl::ClientBuffer {
+private:
+    bool mInvalidated; // TODO: implement
+    int64_t mExpireUs;
+    bool mHasCache;
+    _C2BlockPoolData mBuffer;
+    std::weak_ptr<_C2BlockPoolData> mCache;
+
+    void updateExpire() {
+        mExpireUs = getTimestampNow() + kCacheTtlUs;
+    }
+
+public:
+    ClientBuffer(BufferId id, native_handle_t *handle)
+            : mInvalidated(false), mHasCache(false), mBuffer(id, handle) {
+        (void)mInvalidated;
+        mExpireUs = getTimestampNow() + kCacheTtlUs;
+    }
+
+    bool expire() const {
+        int64_t now = getTimestampNow();
+        return now >= mExpireUs;
+    }
+
+    bool hasCache() const {
+        return mHasCache;
+    }
+
+    std::shared_ptr<_C2BlockPoolData> fetchCache() {
+        if (mHasCache) {
+            std::shared_ptr<_C2BlockPoolData> cache = mCache.lock();
+            if (cache) {
+                updateExpire();
+            }
+            return cache;
+        }
+        return nullptr;
+    }
+
+    std::shared_ptr<_C2BlockPoolData> createCache(
+            const std::shared_ptr<BufferPoolClient::Impl> &impl) {
+        if (!mHasCache) {
+            // Allocates a raw ptr in order to avoid sending #postBufferRelease
+            // from deleter, in case of native_handle_clone failure.
+            _C2BlockPoolData *ptr = new _C2BlockPoolData(
+                    mBuffer.mId, native_handle_clone(mBuffer.mHandle));
+            if (ptr && ptr->mHandle != NULL) {
+                std::shared_ptr<_C2BlockPoolData>
+                        cache(ptr, BlockPoolDataDtor(impl));
+                if (cache) {
+                    mCache = cache;
+                    mHasCache = true;
+                    updateExpire();
+                    return cache;
+                }
+            }
+            if (ptr) {
+                delete ptr;
+            }
+        }
+        return nullptr;
+    }
+
+    bool onCacheRelease() {
+        if (mHasCache) {
+            // TODO: verify mCache is not valid;
+            mHasCache = false;
+            return true;
+        }
+        return false;
+    }
+};
+
+BufferPoolClient::Impl::Impl(const sp<Accessor> &accessor)
+    : mLocal(true), mAccessor(accessor), mSeqId(0) {
+    mValid = false;
+    const QueueDescriptor *fmqDesc;
+    ResultStatus status = accessor->connect(
+            &mLocalConnection, &mConnectionId, &fmqDesc);
+    if (status == ResultStatus::OK) {
+        mReleasing.mStatusChannel =
+                std::make_unique<BufferStatusChannel>(*fmqDesc);
+        mValid = mReleasing.mStatusChannel &&
+                mReleasing.mStatusChannel->isValid();
+    }
+}
+
+BufferPoolClient::Impl::Impl(const sp<IAccessor> &accessor)
+    : mLocal(false), mAccessor(accessor), mSeqId(0) {
+    mValid = false;
+    bool& valid = mValid;
+    sp<IConnection>& outConnection = mRemoteConnection;
+    ConnectionId& id = mConnectionId;
+    std::unique_ptr<BufferStatusChannel>& outChannel =
+            mReleasing.mStatusChannel;
+    accessor->connect(
+            [&valid, &outConnection, &id, &outChannel]
+            (ResultStatus status, sp<IConnection> connection,
+             ConnectionId connectionId, const QueueDescriptor& desc) {
+                if (status == ResultStatus::OK) {
+                    outConnection = connection;
+                    id = connectionId;
+                    outChannel = std::make_unique<BufferStatusChannel>(desc);
+                    if (outChannel && outChannel->isValid()) {
+                        valid = true;
+                    }
+                }
+            });
+}
+
+ResultStatus BufferPoolClient::Impl::allocate(
+        const std::vector<uint8_t> &params,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    if (!mLocal || !mLocalConnection || !mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    BufferId bufferId;
+    native_handle_t *handle = NULL;
+    buffer->reset();
+    ResultStatus status = allocateBufferHandle(params, &bufferId, &handle);
+    if (status == ResultStatus::OK) {
+        if (handle) {
+            std::unique_lock<std::mutex> lock(mCache.mLock);
+            syncReleased();
+            auto cacheIt = mCache.mBuffers.find(bufferId);
+            if (cacheIt != mCache.mBuffers.end()) {
+                // TODO: verify it is recycled. (not having active ref)
+                mCache.mBuffers.erase(cacheIt);
+            }
+            auto clientBuffer = std::make_unique<ClientBuffer>(
+                    bufferId, handle);
+            if (clientBuffer) {
+                auto result = mCache.mBuffers.insert(std::make_pair(
+                        bufferId, std::move(clientBuffer)));
+                if (result.second) {
+                    *buffer = result.first->second->createCache(
+                            shared_from_this());
+                }
+            }
+        }
+        if (!*buffer) {
+            ALOGV("client cache creation failure %d: %" PRId64,
+                  handle != NULL, mConnectionId);
+            status = ResultStatus::NO_MEMORY;
+            postBufferRelease(bufferId);
+        }
+    }
+    return status;
+}
+
+ResultStatus BufferPoolClient::Impl::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    if (!mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    if (timestampUs != 0) {
+        timestampUs += kReceiveTimeoutUs;
+    }
+    if (!postReceive(bufferId, transactionId, timestampUs)) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    ResultStatus status = ResultStatus::CRITICAL_ERROR;
+    buffer->reset();
+    while(1) {
+        std::unique_lock<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        auto cacheIt = mCache.mBuffers.find(bufferId);
+        if (cacheIt != mCache.mBuffers.end()) {
+            if (cacheIt->second->hasCache()) {
+                *buffer = cacheIt->second->fetchCache();
+                if (!*buffer) {
+                    // check transfer time_out
+                    lock.unlock();
+                    std::this_thread::yield();
+                    continue;
+                }
+                ALOGV("client receive from reference %" PRId64, mConnectionId);
+                break;
+            } else {
+                *buffer = cacheIt->second->createCache(shared_from_this());
+                ALOGV("client receive from cache %" PRId64, mConnectionId);
+                break;
+            }
+        } else {
+            if (!mCache.creating) {
+                mCache.creating = true;
+                lock.unlock();
+                native_handle_t* handle = NULL;
+                status = fetchBufferHandle(transactionId, bufferId, &handle);
+                lock.lock();
+                if (status == ResultStatus::OK) {
+                    if (handle) {
+                        auto clientBuffer = std::make_unique<ClientBuffer>(
+                                bufferId, handle);
+                        if (clientBuffer) {
+                            auto result = mCache.mBuffers.insert(
+                                    std::make_pair(bufferId, std::move(
+                                            clientBuffer)));
+                            if (result.second) {
+                                *buffer = result.first->second->createCache(
+                                        shared_from_this());
+                            }
+                        }
+                    }
+                    if (!*buffer) {
+                        status = ResultStatus::NO_MEMORY;
+                    }
+                }
+                mCache.creating = false;
+                lock.unlock();
+                mCache.mCreateCv.notify_all();
+                break;
+            }
+            mCache.mCreateCv.wait(lock);
+        }
+    }
+    bool posted = postReceiveResult(bufferId, transactionId,
+                                      *buffer ? true : false);
+    ALOGV("client receive %" PRId64 " - %u : %s (%d)", mConnectionId, bufferId,
+          *buffer ? "ok" : "fail", posted);
+    if (*buffer) {
+        if (!posted) {
+            buffer->reset();
+            return ResultStatus::CRITICAL_ERROR;
+        }
+        return ResultStatus::OK;
+    }
+    return status;
+}
+
+
+void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    mReleasing.mReleasingIds.push_back(bufferId);
+    mReleasing.mStatusChannel->postBufferRelease(
+            mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+}
+
+// TODO: revise ad-hoc posting data structure
+bool BufferPoolClient::Impl::postSend(
+        BufferId bufferId, ConnectionId receiver,
+        TransactionId *transactionId, int64_t *timestampUs) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    *timestampUs = getTimestampNow();
+    *transactionId = (mConnectionId << 32) | mSeqId++;
+    // TODO: retry, add timeout, target?
+    return  mReleasing.mStatusChannel->postBufferStatusMessage(
+            *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
+            receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+}
+
+bool BufferPoolClient::Impl::postReceive(
+        BufferId bufferId, TransactionId transactionId, int64_t timestampUs) {
+    for (int i = 0; i < kPostMaxRetry; ++i) {
+        std::unique_lock<std::mutex> lock(mReleasing.mLock);
+        int64_t now = getTimestampNow();
+        if (timestampUs == 0 || now < timestampUs) {
+            bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_FROM,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            if (result) {
+                return true;
+            }
+            lock.unlock();
+            std::this_thread::yield();
+        } else {
+            mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            return false;
+        }
+    }
+    return false;
+}
+
+bool BufferPoolClient::Impl::postReceiveResult(
+        BufferId bufferId, TransactionId transactionId, bool result) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    // TODO: retry, add timeout
+    return mReleasing.mStatusChannel->postBufferStatusMessage(
+            transactionId, bufferId,
+            result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
+            mConnectionId, -1, mReleasing.mReleasingIds,
+            mReleasing.mReleasedIds);
+}
+
+// should have mCache.mLock
+bool BufferPoolClient::Impl::syncReleased() {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    if (mReleasing.mReleasingIds.size() > 0) {
+        mReleasing.mStatusChannel->postBufferRelease(
+                mConnectionId, mReleasing.mReleasingIds,
+                mReleasing.mReleasedIds);
+    }
+    if (mReleasing.mReleasedIds.size() > 0) {
+        for (BufferId& id: mReleasing.mReleasedIds) {
+            ALOGV("client release buffer %" PRId64 " - %u", mConnectionId, id);
+            auto found = mCache.mBuffers.find(id);
+            if (found != mCache.mBuffers.end()) {
+                if (!found->second->onCacheRelease()) {
+                    // should not happen!
+                    ALOGW("client %" PRId64 "cache release status inconsitent!",
+                          mConnectionId);
+                }
+                if (found->second->expire()) {
+                    ALOGV("client evict buffer from cache %" PRId64 " - %u",
+                          mConnectionId, id);
+                    mCache.mBuffers.erase(found);
+                }
+            } else {
+                // should not happen!
+                ALOGW("client %" PRId64 "cache status inconsitent!",
+                      mConnectionId);
+            }
+        }
+        mReleasing.mReleasedIds.clear();
+        return true;
+    }
+    return false;
+}
+
+ResultStatus BufferPoolClient::Impl::allocateBufferHandle(
+        const std::vector<uint8_t>& params, BufferId *bufferId,
+        native_handle_t** handle) {
+    if (mLocalConnection) {
+        const native_handle_t* allocHandle = NULL;
+        ResultStatus status = mLocalConnection->allocate(
+                params, bufferId, &allocHandle);
+        if (status == ResultStatus::OK) {
+            *handle = native_handle_clone(allocHandle);
+        }
+        ALOGV("client allocate result %" PRId64 "%d : %u clone %p",
+              mConnectionId, status == ResultStatus::OK,
+              *handle ? *bufferId : 0 , *handle);
+        return status;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::Impl::fetchBufferHandle(
+        TransactionId transactionId, BufferId bufferId,
+        native_handle_t **handle) {
+    sp<IConnection> connection;
+    if (mLocal) {
+        connection = mLocalConnection;
+    } else {
+        connection = mRemoteConnection;
+    }
+    ResultStatus status;
+    connection->fetch(
+            transactionId, bufferId,
+            [&status, &handle]
+            (ResultStatus outStatus, Buffer outBuffer) {
+                status = outStatus;
+                if (status == ResultStatus::OK) {
+                    *handle = native_handle_clone(
+                            outBuffer.buffer.getNativeHandle());
+                }
+            });
+    return status;
+}
+
+
+BufferPoolClient::BufferPoolClient(const sp<Accessor> &accessor) {
+    mImpl = std::make_shared<Impl>(accessor);
+}
+
+BufferPoolClient::BufferPoolClient(const sp<IAccessor> &accessor) {
+    mImpl = std::make_shared<Impl>(accessor);
+}
+
+BufferPoolClient::~BufferPoolClient() {
+    // TODO: how to handle orphaned buffers?
+}
+
+bool BufferPoolClient::isValid() {
+    return mImpl && mImpl->isValid();
+}
+
+ConnectionId BufferPoolClient::getConnectionId() {
+    if (isValid()) {
+        return mImpl->getConnectionId();
+    }
+    return -1;
+}
+
+ResultStatus BufferPoolClient::getAccessor(sp<IAccessor> *accessor) {
+    if (isValid()) {
+        *accessor = mImpl->getAccessor();
+        return ResultStatus::OK;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::allocate(
+        const std::vector<uint8_t> &params,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->allocate(params, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampUs,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->receive(transactionId, bufferId, timestampUs, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus BufferPoolClient::postSend(
+        ConnectionId receiverId,
+        const std::shared_ptr<_C2BlockPoolData> &buffer,
+        TransactionId *transactionId,
+        int64_t *timestampUs) {
+    if (isValid()) {
+        bool result = mImpl->postSend(
+                buffer->mId, receiverId, transactionId, timestampUs);
+        return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.h b/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.h
new file mode 100644
index 0000000..a6111b5
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/BufferPoolClient.h
@@ -0,0 +1,96 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
+
+#include <memory>
+#include <cutils/native_handle.h>
+#include <android/hardware/media/bufferpool/1.0/IAccessor.h>
+#include <android/hardware/media/bufferpool/1.0/IConnection.h>
+#include <BufferPoolTypes.h>
+#include "Accessor.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::bufferpool::V1_0::IAccessor;
+using ::android::hardware::media::bufferpool::V1_0::IConnection;
+using ::android::hardware::media::bufferpool::V1_0::ResultStatus;
+using ::android::sp;
+
+/**
+ * A buffer pool client for a buffer pool. For a specific buffer pool, at most
+ * one buffer pool client exists per process. This class will not be exposed
+ * outside. A buffer pool client will be used via ClientManager.
+ */
+class BufferPoolClient {
+public:
+    /**
+     * Creates a buffer pool client from a local buffer pool
+     * (via ClientManager#create).
+     */
+    explicit BufferPoolClient(const sp<Accessor> &accessor);
+
+    /**
+     * Creates a buffer pool client from a remote buffer pool
+     * (via ClientManager#registerSender).
+     * Note: A buffer pool client created with remote buffer pool cannot
+     * allocate a buffer.
+     */
+    explicit BufferPoolClient(const sp<IAccessor> &accessor);
+
+    /** Destructs a buffer pool client. */
+    ~BufferPoolClient();
+
+private:
+    bool isValid();
+
+    ConnectionId getConnectionId();
+
+    ResultStatus getAccessor(sp<IAccessor> *accessor);
+
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                          std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    ResultStatus receive(TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampUs,
+                         std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    ResultStatus postSend(ConnectionId receiver,
+                          const std::shared_ptr<_C2BlockPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampUs);
+
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+
+    friend struct ClientManager;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLCLIENT_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.cpp b/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.cpp
new file mode 100644
index 0000000..4fc88c6
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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_TAG "bufferpool"
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+#include <time.h>
+#include "BufferStatus.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+int64_t getTimestampNow() {
+    int64_t stamp;
+    struct timespec ts;
+    // TODO: CLOCK_MONOTONIC_COARSE?
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    stamp = ts.tv_nsec / 1000;
+    stamp += (ts.tv_sec * 1000000LL);
+    return stamp;
+}
+
+static constexpr int kNumElementsInQueue = 1024*16;
+
+ResultStatus BufferStatusObserver::open(
+        ConnectionId id, const QueueDescriptor** fmqDescPtr) {
+    if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
+        // TODO: id collision log?
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    std::unique_ptr<BufferStatusQueue> queue =
+            std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
+    if (!queue || queue->isValid() == false) {
+        *fmqDescPtr = NULL;
+        return ResultStatus::NO_MEMORY;
+    } else {
+        *fmqDescPtr = queue->getDesc();
+    }
+    auto result = mBufferStatusQueues.insert(
+            std::make_pair(id, std::move(queue)));
+    if (!result.second) {
+        *fmqDescPtr = NULL;
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+}
+
+ResultStatus BufferStatusObserver::close(ConnectionId id) {
+    if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    mBufferStatusQueues.erase(id);
+    return ResultStatus::OK;
+}
+
+void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
+    for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
+        BufferStatusMessage message;
+        size_t avail = it->second->availableToRead();
+        while (avail > 0) {
+            if (!it->second->read(&message, 1)) {
+                // Since avaliable # of reads are already confiremd,
+                // this should not happen.
+                // TODO: error handling (supurious client?)
+                ALOGW("FMQ message cannot be read from %" PRId64, it->first);
+                return;
+            }
+            message.connectionId = it->first;
+            messages.push_back(message);
+            --avail;
+        }
+    }
+}
+
+BufferStatusChannel::BufferStatusChannel(
+        const QueueDescriptor &fmqDesc) {
+    std::unique_ptr<BufferStatusQueue> queue =
+            std::make_unique<BufferStatusQueue>(fmqDesc);
+    if (!queue || queue->isValid() == false) {
+        mValid = false;
+        return;
+    }
+    mValid  = true;
+    mBufferStatusQueue = std::move(queue);
+}
+
+bool BufferStatusChannel::isValid() {
+    return mValid;
+}
+
+void BufferStatusChannel::postBufferRelease(
+        ConnectionId connectionId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid && pending.size() > 0) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        avail = std::min(avail, pending.size());
+        BufferStatusMessage message;
+        for (size_t i = 0 ; i < avail; ++i) {
+            BufferId id = pending.front();
+            message.newStatus = BufferStatus::NOT_USED;
+            message.bufferId = id;
+            message.connectionId = connectionId;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since avaliable # of writes are already confiremd,
+                // this should not happen.
+                // TODO: error handing?
+                ALOGW("FMQ message cannot be sent from %" PRId64, connectionId);
+                return;
+            }
+            pending.pop_front();
+            posted.push_back(id);
+        }
+    }
+}
+
+bool BufferStatusChannel::postBufferStatusMessage(
+        TransactionId transactionId, BufferId bufferId,
+        BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        size_t numPending = pending.size();
+        if (avail >= numPending + 1) {
+            BufferStatusMessage release, message;
+            for (size_t i = 0; i < numPending; ++i) {
+                BufferId id = pending.front();
+                release.newStatus = BufferStatus::NOT_USED;
+                release.bufferId = id;
+                release.connectionId = connectionId;
+                if (!mBufferStatusQueue->write(&release, 1)) {
+                    // Since avaliable # of writes are already confiremd,
+                    // this should not happen.
+                    // TODO: error handling?
+                    ALOGW("FMQ message cannot be sent from %" PRId64,
+                          connectionId);
+                    return false;
+                }
+                pending.pop_front();
+                posted.push_back(id);
+            }
+            message.transactionId = transactionId;
+            message.bufferId = bufferId;
+            message.newStatus = status;
+            message.connectionId = connectionId;
+            message.targetConnectionId = targetId;
+            // TODO : timesatamp
+            message.timestampUs = 0;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since avaliable # of writes are already confiremd,
+                // this should not happen.
+                ALOGW("FMQ message cannot be sent from %" PRId64, connectionId);
+                return false;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
diff --git a/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.h b/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.h
new file mode 100644
index 0000000..82303cb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/BufferStatus.h
@@ -0,0 +1,140 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
+
+#include <android/hardware/media/bufferpool/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <memory>
+#include <mutex>
+#include <vector>
+#include <list>
+#include <BufferPoolTypes.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+/** Returns monotonic timestamp in Us since fixed point in time. */
+int64_t getTimestampNow();
+
+/**
+ * A collection of FMQ for a buffer pool. buffer ownership/status change
+ * messages are sent via the FMQs from the clients.
+ */
+class BufferStatusObserver {
+private:
+    std::map<ConnectionId, std::unique_ptr<BufferStatusQueue>>
+            mBufferStatusQueues;
+
+public:
+    /** Creates an FMQ for the specified connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     * @param fmqDescPtr    double ptr of created FMQ's descriptor.
+     *
+     * @return OK if FMQ is created successfully.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus open(ConnectionId id, const QueueDescriptor** fmqDescPtr);
+
+    /** Closes an FMQ for the specified connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     *
+     * @return OK if the specified connection is closed successfully.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus close(ConnectionId id);
+
+    /** Retrieves all pending FMQ buffer status messages from clients.
+     *
+     * @param messages  retrieved pending messages.
+     */
+    void getBufferStatusChanges(std::vector<BufferStatusMessage> &messages);
+};
+
+/**
+ * An FMQ for a buffer pool client. buffer ownership/status change messages
+ * are sent via the fmq to the buffer pool.
+ */
+class BufferStatusChannel {
+private:
+    bool mValid;
+    std::unique_ptr<BufferStatusQueue> mBufferStatusQueue;
+
+public:
+    /**
+     * Connects to an FMQ from a descriptor of the created FMQ.
+     *
+     * @param fmqDesc   Descriptor of the created FMQ.
+     */
+    BufferStatusChannel(const QueueDescriptor &fmqDesc);
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+
+    /**
+     * Posts a buffer release message to the buffer pool.
+     *
+     * @param connectionId  connection Id of the client.
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     */
+    void postBufferRelease(
+            ConnectionId connectionId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+    /**
+     * Posts a buffer status message regarding the specified buffer
+     * transfer transaction.
+     *
+     * @param transactionId Id of the specified transaction.
+     * @param bufferId      buffer Id of the specified transaction.
+     * @param status        new status of the buffer.
+     * @param connectionId  connection Id of the client.
+     * @param targetId      connection Id of the receiver(only when the sender
+     *                      posts a status message).
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     *
+     * @return {@code true} when the specified message is posted,
+     *         {@code false} otherwise.
+     */
+    bool postBufferStatusMessage(
+            TransactionId transactionId,
+            BufferId bufferId,
+            BufferStatus status,
+            ConnectionId connectionId,
+            ConnectionId targetId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERSTATUS_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp b/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp
new file mode 100644
index 0000000..97efee4
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/ClientManager.cpp
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ClientManager.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include "BufferPoolClient.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+static constexpr int64_t kRegisterTimeoutUs = 500000; // 0.5 sec
+
+class ClientManager::Impl {
+public:
+    Impl();
+
+    ResultStatus registerSender(const sp<IAccessor> &accessor,
+                                ConnectionId *pConnectionId);
+
+    ResultStatus create(const std::shared_ptr<C2Allocator> &allocator,
+                        bool linear,
+                        ConnectionId *pConnectionId);
+
+    ResultStatus close(ConnectionId connectionId);
+
+    ResultStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    ResultStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampUs,
+                         std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    ResultStatus postSend(ConnectionId connectionId,
+                          ConnectionId receiverId,
+                          const std::shared_ptr<_C2BlockPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampUs);
+
+    ResultStatus getAccessor(ConnectionId connectionId,
+                             sp<IAccessor> *accessor);
+
+private:
+    // In order to prevent deadlock between multiple locks,
+    // Always lock ClientCache.lock before locking ActiveClients.lock.
+    struct ClientCache {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed holding the lock.
+        std::mutex mMutex;
+        std::map<const wp<IAccessor>, const std::weak_ptr<BufferPoolClient>>
+                mClients;
+        std::condition_variable mConnectCv;
+        bool mConnecting;
+
+        ClientCache() : mConnecting(false) {}
+    } mCache;
+
+    // Active clients which can be retrieved via ConnectionId
+    struct ActiveClients {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed holding the lock.
+        std::mutex mMutex;
+        std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
+                mClients;
+    } mActive;
+
+};
+
+ClientManager::Impl::Impl() {}
+
+ResultStatus ClientManager::Impl::registerSender(
+        const sp<IAccessor> &accessor, ConnectionId *pConnectionId) {
+    int64_t timeoutUs = getTimestampNow() + kRegisterTimeoutUs;
+    do {
+        std::unique_lock<std::mutex> lock(mCache.mMutex);
+        auto it = mCache.mClients.find(accessor);
+        if (it != mCache.mClients.end()) {
+            const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+            if (client) {
+                *pConnectionId = client->getConnectionId();
+                return ResultStatus::ALREADY_EXISTS;
+            }
+            mCache.mClients.erase(it);
+        }
+        if (!mCache.mConnecting) {
+            mCache.mConnecting = true;
+            lock.unlock();
+            ResultStatus result = ResultStatus::OK;
+            const std::shared_ptr<BufferPoolClient> client =
+                    std::make_shared<BufferPoolClient>(accessor);
+            lock.lock();
+            if (!client) {
+                result = ResultStatus::NO_MEMORY;
+            } else if (!client->isValid()) {
+                result = ResultStatus::CRITICAL_ERROR;
+            }
+            if (result == ResultStatus::OK) {
+                // TODO: handle insert fail. (malloc fail)
+                const std::weak_ptr<BufferPoolClient> wclient = client;
+                mCache.mClients.insert(std::make_pair(accessor, wclient));
+                ConnectionId conId = client->getConnectionId();
+                {
+                    std::lock_guard<std::mutex> lock(mActive.mMutex);
+                    mActive.mClients.insert(std::make_pair(conId, client));
+                }
+                *pConnectionId = conId;
+            }
+            mCache.mConnecting = false;
+            lock.unlock();
+            mCache.mConnectCv.notify_all();
+            return result;
+        }
+        mCache.mConnectCv.wait_for(
+                lock, std::chrono::microseconds(kRegisterTimeoutUs));
+    } while (getTimestampNow() < timeoutUs);
+    // TODO: return timeout error
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::Impl::create(
+        const std::shared_ptr<C2Allocator> &allocator,
+        bool linear,
+        ConnectionId *pConnectionId) {
+    const sp<Accessor> accessor = new Accessor(allocator, linear);
+    if (!accessor || !accessor->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    std::shared_ptr<BufferPoolClient> client =
+            std::make_shared<BufferPoolClient>(accessor);
+    if (!client || !client->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    {
+        // TODO: handle insert fail. (malloc fail)
+        std::lock_guard<std::mutex> lock(mCache.mMutex);
+        const wp<Accessor> waccessor = accessor;
+        const std::weak_ptr<BufferPoolClient> wclient = client;
+        mCache.mClients.insert(std::make_pair(waccessor, wclient));
+        ConnectionId conId = client->getConnectionId();
+        {
+            std::lock_guard<std::mutex> lock(mActive.mMutex);
+            mActive.mClients.insert(std::make_pair(conId, client));
+        }
+        *pConnectionId = conId;
+    }
+    return ResultStatus::OK;
+}
+
+ResultStatus ClientManager::Impl::close(ConnectionId connectionId) {
+    std::lock_guard<std::mutex> lock1(mCache.mMutex);
+    std::lock_guard<std::mutex> lock2(mActive.mMutex);
+    auto it = mActive.mClients.find(connectionId);
+    if (it != mActive.mClients.end()) {
+        sp<IAccessor> accessor;
+        if (it->second->getAccessor(&accessor) == ResultStatus::OK) {
+            mCache.mClients.erase(accessor);
+        }
+        mActive.mClients.erase(connectionId);
+        return ResultStatus::OK;
+    }
+    return ResultStatus::NOT_FOUND;
+}
+
+ResultStatus ClientManager::Impl::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->allocate(params, buffer);
+}
+
+ResultStatus ClientManager::Impl::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampUs,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->receive(transactionId, bufferId, timestampUs, buffer);
+}
+
+ResultStatus ClientManager::Impl::postSend(
+        ConnectionId connectionId, ConnectionId receiverId,
+        const std::shared_ptr<_C2BlockPoolData> &buffer,
+        TransactionId *transactionId, int64_t *timestampUs) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->postSend(receiverId, buffer, transactionId, timestampUs);
+}
+
+ResultStatus ClientManager::Impl::getAccessor(
+        ConnectionId connectionId, sp<IAccessor> *accessor) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->getAccessor(accessor);
+}
+
+// Methods from ::android::hardware::media::bufferpool::V1_0::IClientManager follow.
+Return<void> ClientManager::registerSender(const sp<::android::hardware::media::bufferpool::V1_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) {
+    if (mImpl) {
+        ConnectionId connectionId = -1;
+        ResultStatus status = mImpl->registerSender(bufferPool, &connectionId);
+        _hidl_cb(status, connectionId);
+    } else {
+        _hidl_cb(ResultStatus::CRITICAL_ERROR, -1);
+    }
+    return Void();
+}
+
+// Methods for local use.
+sp<ClientManager> ClientManager::sInstance;
+std::mutex ClientManager::sInstanceLock;
+
+sp<ClientManager> ClientManager::getInstance() {
+    std::lock_guard<std::mutex> lock(sInstanceLock);
+    if (!sInstance) {
+        sInstance = new ClientManager();
+    }
+    return sInstance;
+}
+
+ClientManager::ClientManager() : mImpl(new Impl()) {}
+
+ClientManager::~ClientManager() {
+}
+
+ResultStatus ClientManager::create(
+        const std::shared_ptr<C2Allocator> &allocator,
+        bool linear,
+        ConnectionId *pConnectionId) {
+    if (mImpl) {
+        return mImpl->create(allocator, linear, pConnectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::close(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->close(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->allocate(connectionId, params, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampUs,
+        std::shared_ptr<_C2BlockPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->receive(connectionId, transactionId, bufferId,
+                              timestampUs, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::postSend(
+        ConnectionId connectionId, ConnectionId receiverId,
+        const std::shared_ptr<_C2BlockPoolData> &buffer,
+        TransactionId *transactionId, int64_t* timestampUs) {
+    if (mImpl) {
+        return mImpl->postSend(connectionId, receiverId, buffer,
+                               transactionId, timestampUs);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+ResultStatus ClientManager::getAccessor(
+        ConnectionId connectionId, sp<IAccessor> *accessor) {
+    if (mImpl) {
+        return mImpl->getAccessor(connectionId, accessor);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+//IClientManager* HIDL_FETCH_IClientManager(const char* /* name */) {
+//    return new ClientManager();
+//}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Connection.cpp b/media/libstagefright/codec2/vndk/bufferpool/Connection.cpp
new file mode 100644
index 0000000..7b385b8
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/Connection.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Connection.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::media::bufferpool::V1_0::IConnection follow.
+Return<void> Connection::fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) {
+    ResultStatus status = ResultStatus::CRITICAL_ERROR;
+    if (mInitialized && mAccessor) {
+        const native_handle_t *handle = NULL;
+        status = mAccessor->fetch(
+                mConnectionId, transactionId, bufferId, &handle);
+        if (status == ResultStatus::OK) {
+            _hidl_cb(status, Buffer{bufferId, handle});
+            return Void();
+        }
+    }
+    _hidl_cb(status, Buffer{0, nullptr});
+    return Void();
+}
+
+Connection::Connection() : mInitialized(false), mConnectionId(-1LL) {}
+
+Connection::~Connection() {
+    if (mInitialized && mAccessor) {
+        mAccessor->close(mConnectionId);
+    }
+}
+
+void Connection::initialize(
+        const sp<Accessor>& accessor, ConnectionId connectionId) {
+    if (!mInitialized) {
+        mAccessor = accessor;
+        mConnectionId = connectionId;
+        mInitialized = true;
+    }
+}
+
+ResultStatus Connection::allocate(
+        const std::vector<uint8_t> &params, BufferId *bufferId,
+        const native_handle_t **handle) {
+    if (mInitialized && mAccessor) {
+        return mAccessor->allocate(mConnectionId, params, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+//IConnection* HIDL_FETCH_IConnection(const char* /* name */) {
+//    return new Connection();
+//}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/codec2/vndk/bufferpool/Connection.h b/media/libstagefright/codec2/vndk/bufferpool/Connection.h
new file mode 100644
index 0000000..47ddbcb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/Connection.h
@@ -0,0 +1,93 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
+
+#include <android/hardware/media/bufferpool/1.0/IConnection.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <BufferPoolTypes.h>
+#include "Accessor.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::media::bufferpool::V1_0::implementation::Accessor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct Connection : public IConnection {
+    // Methods from ::android::hardware::media::bufferpool::V1_0::IConnection follow.
+    Return<void> fetch(uint64_t transactionId, uint32_t bufferId, fetch_cb _hidl_cb) override;
+
+    /**
+     * Allocates a buffer using the specified parameters. Recycles a buffer if
+     * it is possible. The returned buffer can be transferred to other remote
+     * clients(Connection).
+     *
+     * @param params    allocation parameters.
+     * @param bufferId  Id of the allocated buffer.
+     * @param handle    native handle of the allocated buffer.
+     *
+     * @return OK if a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus allocate(const std::vector<uint8_t> &params,
+                          BufferId *bufferId, const native_handle_t **handle);
+
+    /** Destructs a connection. */
+    ~Connection();
+
+    /** Creates a connection. */
+    Connection();
+
+    /**
+     * Initializes with the specified buffer pool and the connection id.
+     * The connection id should be unique in the whole system.
+     *
+     * @param accessor      the specified buffer pool.
+     * @param connectionId  Id.
+     */
+    void initialize(const sp<Accessor> &accessor, ConnectionId connectionId);
+
+private:
+    bool mInitialized;
+    sp<Accessor> mAccessor;
+    ConnectionId mConnectionId;
+};
+
+// FIXME: most likely delete, this is only for passthrough implementations
+// extern "C" IConnection* HIDL_FETCH_IConnection(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CONNECTION_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h b/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h
new file mode 100644
index 0000000..4b7363f
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/include/BufferPoolTypes.h
@@ -0,0 +1,67 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
+
+#include <android/hardware/media/bufferpool/1.0/types.h>
+#include <cutils/native_handle.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <C2Buffer.h>
+
+struct C2_HIDE _C2BlockPoolData {
+    uint32_t mId; //BufferId
+    native_handle_t *mHandle;
+
+    _C2BlockPoolData() : mId(0), mHandle(NULL) {}
+
+    _C2BlockPoolData(uint32_t id, native_handle_t *handle)
+            : mId(id), mHandle(handle) {}
+
+    ~_C2BlockPoolData() {
+        if (mHandle != NULL) {
+            native_handle_close(mHandle);
+            native_handle_delete(mHandle);
+        }
+    }
+};
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+
+typedef uint32_t BufferId;
+typedef uint64_t TransactionId;
+typedef int64_t ConnectionId;
+
+typedef android::hardware::MessageQueue<BufferStatusMessage, kSynchronizedReadWrite> BufferStatusQueue;
+typedef BufferStatusQueue::Descriptor QueueDescriptor;
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_BUFFERPOOLTYPES_H
diff --git a/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h b/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h
new file mode 100644
index 0000000..412fa59
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/bufferpool/include/ClientManager.h
@@ -0,0 +1,169 @@
+/*
+ * 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 ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
+#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
+
+#include <android/hardware/media/bufferpool/1.0/IClientManager.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <C2Buffer.h>
+#include <memory>
+#include <BufferPoolTypes.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace bufferpool {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::media::bufferpool::V1_0::IAccessor;
+using ::android::hardware::media::bufferpool::V1_0::ResultStatus;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ClientManager : public IClientManager {
+    // Methods from ::android::hardware::media::bufferpool::V1_0::IClientManager follow.
+    Return<void> registerSender(const sp<::android::hardware::media::bufferpool::V1_0::IAccessor>& bufferPool, registerSender_cb _hidl_cb) override;
+
+    /** Gets an instance. */
+    static sp<ClientManager> getInstance();
+
+    /**
+     * Creates a local connection with a newly created buffer pool.
+     *
+     * @param allocator     for new buffer allocation.
+     * @param linear        whether the allocator is linear or not.
+     * @param pConnectionId Id of the created connection. This is
+     *                      system-wide unique.
+     *
+     * @return OK when a buffer pool and a local connection is successfully
+     *         created.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus create(const std::shared_ptr<C2Allocator> &allocator,
+                        bool linear,
+                        ConnectionId *pConnectionId);
+
+    /**
+     * Closes the specified connection.
+     *
+     * @param connectionId  The id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus close(ConnectionId connectionId);
+
+    /**
+     * Allocates a buffer from the specified connection.
+     *
+     * @param connectionId  The id of the connection.
+     * @param params        The allocation parameters.
+     * @param buffer        The allocated buffer.
+     *
+     * @return OK when a buffer was allocated successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    /**
+     * Receives a buffer for the transaction.
+     *
+     * @param connectionId  The id of the receiving connection.
+     * @param transactionId The id for the transaction.
+     * @param bufferId      The id for the buffer.
+     * @param timestampUs   The timestamp of the buffer is being sent.
+     * @param buffer        The received buffer.
+     *
+     * @return OK when a buffer was received successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampUs,
+                         std::shared_ptr<_C2BlockPoolData> *buffer);
+
+    /**
+     * Posts a buffer transfer transaction to the buffer pool. Sends a buffer
+     * to other remote clients(connection) after this call has been succeeded.
+     *
+     * @param connectionId  The id of the sending connection.
+     * @param receiverId    The id of the receiving connection.
+     * @param buffer        to transfer
+     * @param transactionId Id of the transfer transaction.
+     * @param timestampUs   The timestamp of the buffer transaction is being
+     *                      posted.
+     *
+     * @return OK when a buffer transaction was posted successfully.
+     *         NOT_FOUND when the sending connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus postSend(ConnectionId connectionId,
+                          ConnectionId receiverId,
+                          const std::shared_ptr<_C2BlockPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampUs);
+
+    /** Gets a buffer pool for the specified connection.
+     *
+     * @param connectionId  The id of the connection.
+     * @param accessor      The buffer pool for the specified connection.
+     * @return OK when a buffer pool was found for the connection.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    ResultStatus getAccessor(ConnectionId connectionId,
+                             sp<IAccessor> *accessor);
+
+    /** Destructs the manager of buffer pool clients.  */
+    ~ClientManager();
+private:
+    static sp<ClientManager> sInstance;
+    static std::mutex sInstanceLock;
+
+    class Impl;
+    const std::unique_ptr<Impl> mImpl;
+
+    ClientManager();
+};
+
+// FIXME: most likely delete, this is only for passthrough implementations
+// extern "C" IClientManager* HIDL_FETCH_IClientManager(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace bufferpool
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V1_0_CLIENTMANAGER_H
diff --git a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
index 875a8c2..977cf7b 100644
--- a/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
+++ b/media/libstagefright/codec2/vndk/include/C2BufferPriv.h
@@ -21,8 +21,6 @@
 
 #include <C2Buffer.h>
 
-namespace android {
-
 class C2BasicLinearBlockPool : public C2BlockPool {
 public:
     explicit C2BasicLinearBlockPool(const std::shared_ptr<C2Allocator> &allocator);
@@ -73,6 +71,4 @@
     const std::shared_ptr<C2Allocator> mAllocator;
 };
 
-} // namespace android
-
 #endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
index cfea104..f6d8b98 100644
--- a/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
+++ b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
@@ -22,8 +22,6 @@
 #include <functional>
 #include <memory>
 
-namespace android {
-
 /**
  * Component factory object that enables to create a component and/or interface from a dynamically
  * linked library. This is needed because the component/interfaces are managed objects, but we
@@ -36,8 +34,8 @@
  */
 class C2ComponentFactory {
 public:
-    typedef std::function<void(::android::C2Component*)> ComponentDeleter;
-    typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;
+    typedef std::function<void(::C2Component*)> ComponentDeleter;
+    typedef std::function<void(::C2ComponentInterface*)> InterfaceDeleter;
 
     /**
      * Creates a component.
@@ -81,9 +79,9 @@
 
     virtual ~C2ComponentFactory() = default;
 
-    typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
-    typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
+    typedef ::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
+    typedef void (*DestroyCodec2FactoryFunc)(::C2ComponentFactory*);
 };
-} // namespace android
+
 
 #endif // STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
index 41132b9..5b995f6 100644
--- a/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
+++ b/media/libstagefright/codec2/vndk/include/C2ErrnoUtils.h
@@ -20,8 +20,6 @@
 #include <errno.h>
 #include <C2.h>
 
-namespace android {
-
 // standard ERRNO mappings
 template<int N> constexpr c2_status_t _c2_errno2status_impl();
 template<> constexpr c2_status_t _c2_errno2status_impl<0>()       { return C2_OK; }
@@ -52,7 +50,5 @@
     return _c2_map_errno_impl<N...>::map(result);
 }
 
-} // namespace android
-
 #endif // STAGEFRIGHT_CODEC2_ERRNO_UTILS_H_
 
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
index 76b02ed..afa51ee 100644
--- a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -86,6 +86,7 @@
  * \retval nullptr if the platform component store could not be obtained
  */
 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();
+
 } // namespace android
 
 #endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h b/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
index 3168248..710e74b 100644
--- a/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
+++ b/media/libstagefright/codec2/vndk/include/util/C2ParamUtils.h
@@ -21,13 +21,14 @@
 #include <util/_C2MacroUtils.h>
 
 #include <iostream>
+#include <list>
+#include <utility>
+#include <vector>
 
 /** \file
  * Utilities for parameter handling to be used by Codec2 implementations.
  */
 
-namespace android {
-
 /// \cond INTERNAL
 
 /* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
@@ -61,7 +62,7 @@
 
 #undef DEFINE_C2_ENUM_VALUE_AUTO_HELPER
 #define DEFINE_C2_ENUM_VALUE_AUTO_HELPER(name, type, prefix, ...) \
-template<> C2FieldDescriptor::named_values_type C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
+template<> C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
     return C2ParamUtils::sanitizeEnumValues( \
             std::vector<C2Value::Primitive> { _C2_MAP(_C2_GET_ENUM_VALUE, type, __VA_ARGS__) }, \
             { _C2_MAP(_C2_GET_ENUM_NAME, type, __VA_ARGS__) }, \
@@ -70,7 +71,7 @@
 
 #undef DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER
 #define DEFINE_C2_ENUM_VALUE_CUSTOM_HELPER(name, type, names, ...) \
-template<> C2FieldDescriptor::named_values_type C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
+template<> C2FieldDescriptor::NamedValuesType C2FieldDescriptor::namedValuesFor(const name &r __unused) { \
     return C2ParamUtils::customEnumValues( \
             std::vector<std::pair<C2StringLiteral, name>> names); \
 }
@@ -241,11 +242,11 @@
     }
 
     template<typename T>
-    static C2FieldDescriptor::named_values_type sanitizeEnumValues(
+    static C2FieldDescriptor::NamedValuesType sanitizeEnumValues(
             std::vector<T> values,
             std::vector<C2StringLiteral> names,
             C2StringLiteral prefix = NULL) {
-        C2FieldDescriptor::named_values_type namedValues;
+        C2FieldDescriptor::NamedValuesType namedValues;
         std::vector<C2String> sanitizedNames = sanitizeEnumValueNames(names, prefix);
         for (size_t i = 0; i < values.size() && i < sanitizedNames.size(); ++i) {
             namedValues.emplace_back(sanitizedNames[i], values[i]);
@@ -254,9 +255,9 @@
     }
 
     template<typename E>
-    static C2FieldDescriptor::named_values_type customEnumValues(
+    static C2FieldDescriptor::NamedValuesType customEnumValues(
             std::vector<std::pair<C2StringLiteral, E>> items) {
-        C2FieldDescriptor::named_values_type namedValues;
+        C2FieldDescriptor::NamedValuesType namedValues;
         for (auto &item : items) {
             namedValues.emplace_back(item.first, item.second);
         }
@@ -313,7 +314,5 @@
 
 /* ---------------------------- UTILITIES FOR ENUMERATION REFLECTION ---------------------------- */
 
-}  // namespace android
-
 #endif  // C2UTILS_PARAM_UTILS_H_
 
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
index 9c68369..25003cb 100644
--- a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
@@ -19,8 +19,6 @@
 
 #include <C2Buffer.h>
 
-namespace android {
-
 struct _C2BlockPoolData;
 
 /**
@@ -64,7 +62,5 @@
             const C2Rect &allottedCrop = C2Rect(~0u, ~0u));
 };
 
-}
-
 #endif // ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
 
diff --git a/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h b/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
index 5bf3009..34797a9 100644
--- a/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
+++ b/media/libstagefright/codec2/vndk/internal/C2ParamInternal.h
@@ -19,22 +19,20 @@
 
 #include <C2Param.h>
 
-namespace android {
-
 struct C2_HIDE _C2ParamInspector {
-    inline static uint32_t getIndex(const C2ParamField &pf) {
+    inline static uint32_t GetIndex(const C2ParamField &pf) {
         return pf._mIndex;
     }
 
-    inline static uint32_t getOffset(const C2ParamField &pf) {
+    inline static uint32_t GetOffset(const C2ParamField &pf) {
         return pf._mFieldId._mOffset;
     }
 
-    inline static uint32_t getSize(const C2ParamField &pf) {
+    inline static uint32_t GetSize(const C2ParamField &pf) {
         return pf._mFieldId._mSize;
     }
 
-    inline static uint32_t getAttrib(const C2ParamDescriptor &pd) {
+    inline static uint32_t GetAttrib(const C2ParamDescriptor &pd) {
         return pd._mAttrib;
     }
 
@@ -42,9 +40,15 @@
     C2ParamField CreateParamField(C2Param::Index index, uint32_t offset, uint32_t size) {
         return C2ParamField(index, offset, size);
     }
-};
 
-}
+    inline static
+    C2ParamField CreateParamField(C2Param::Index index, _C2FieldId field) {
+        return C2ParamField(index, field._mOffset, field._mSize);
+    }
+
+    // expose attributes
+    typedef C2ParamDescriptor::attrib_t attrib_t;
+};
 
 #endif // ANDROID_STAGEFRIGHT_C2PARAM_INTERNAL_H_
 
diff --git a/media/libstagefright/codecs/aacdec/C2SoftAac.cpp b/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
index b57c2aa..c82ea45 100644
--- a/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
+++ b/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
@@ -25,6 +25,7 @@
 
 #include <cutils/properties.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/misc.h>
@@ -50,12 +51,22 @@
 
 namespace android {
 
-C2SoftAac::C2SoftAac(const char *name, c2_node_id_t id)
-    : SimpleC2Component(
-            SimpleC2Interface::Builder(name, id)
+constexpr char kComponentName[] = "c2.google.aac.decoder";
+
+static std::shared_ptr<C2ComponentInterface> BuildIntf(
+        const char *name, c2_node_id_t id,
+        std::function<void(C2ComponentInterface*)> deleter =
+            std::default_delete<C2ComponentInterface>()) {
+    return SimpleC2Interface::Builder(name, id, deleter)
             .inputFormat(C2FormatCompressed)
             .outputFormat(C2FormatAudio)
-            .build()),
+            .inputMediaType(MEDIA_MIMETYPE_AUDIO_AAC)
+            .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
+            .build();
+}
+
+C2SoftAac::C2SoftAac(const char *name, c2_node_id_t id)
+    : SimpleC2Component(BuildIntf(name, id)),
       mAACDecoder(NULL),
       mStreamInfo(NULL),
       mIsADTS(false),
@@ -333,6 +344,7 @@
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
     work->workletsProcessed = 0u;
+    work->result = C2_OK;
     if (mSignalledError) {
         return;
     }
@@ -675,20 +687,18 @@
 class C2SoftAacDecFactory : public C2ComponentFactory {
 public:
     virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            std::function<void(::android::C2Component*)> deleter) override {
-        *component = std::shared_ptr<C2Component>(new C2SoftAac("aac", id), deleter);
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftAac(kComponentName, id), deleter);
         return C2_OK;
     }
 
     virtual c2_status_t createInterface(
-            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            std::function<void(::android::C2ComponentInterface*)> deleter) override {
-        *interface =
-                SimpleC2Interface::Builder("aac", id, deleter)
-                .inputFormat(C2FormatCompressed)
-                .outputFormat(C2FormatVideo)
-                .build();
+            c2_node_id_t id,
+            std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = BuildIntf(kComponentName, id, deleter);
         return C2_OK;
     }
 
@@ -697,12 +707,12 @@
 
 }  // namespace android
 
-extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
     ALOGV("in %s", __func__);
     return new ::android::C2SoftAacDecFactory();
 }
 
-extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
     ALOGV("in %s", __func__);
     delete factory;
 }
diff --git a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
index 6f1b325..70f6817 100644
--- a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
+++ b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
@@ -22,20 +22,31 @@
 
 #include <C2PlatformSupport.h>
 #include <SimpleC2Interface.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 #include <media/stagefright/foundation/hexdump.h>
 
 #include "C2SoftAacEnc.h"
 
 namespace android {
 
+constexpr char kComponentName[] = "c2.google.aac.encoder";
+
+static std::shared_ptr<C2ComponentInterface> BuildIntf(
+        const char *name, c2_node_id_t id,
+        std::function<void(C2ComponentInterface*)> deleter =
+            std::default_delete<C2ComponentInterface>()) {
+    return SimpleC2Interface::Builder(name, id, deleter)
+            .inputFormat(C2FormatAudio)
+            .outputFormat(C2FormatCompressed)
+            .inputMediaType(MEDIA_MIMETYPE_AUDIO_AAC)
+            .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
+            .build();
+}
+
 C2SoftAacEnc::C2SoftAacEnc(
         const char *name,
         c2_node_id_t id)
-    : SimpleC2Component(
-            SimpleC2Interface::Builder(name, id)
-            .inputFormat(C2FormatAudio)
-            .outputFormat(C2FormatCompressed)
-            .build()),
+    : SimpleC2Component(BuildIntf(name, id)),
       mAACEncoder(NULL),
       mNumChannels(1),
       mSampleRate(44100),
@@ -176,6 +187,7 @@
 void C2SoftAacEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
+    work->result = C2_OK;
     work->workletsProcessed = 0u;
 
     if (mSignalledError) {
@@ -208,7 +220,7 @@
         }
 
         std::unique_ptr<C2StreamCsdInfo::output> csd =
-            C2StreamCsdInfo::output::alloc_unique(encInfo.confSize, 0u);
+            C2StreamCsdInfo::output::AllocUnique(encInfo.confSize, 0u);
         // TODO: check NO_MEMORY
         memcpy(csd->m.value, encInfo.confBuf, encInfo.confSize);
         ALOGV("put csd");
@@ -381,20 +393,17 @@
 class C2SoftAacEncFactory : public C2ComponentFactory {
 public:
     virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            std::function<void(::android::C2Component*)> deleter) override {
-        *component = std::shared_ptr<C2Component>(new C2SoftAacEnc("aacenc", id), deleter);
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftAacEnc(kComponentName, id), deleter);
         return C2_OK;
     }
 
     virtual c2_status_t createInterface(
             c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            std::function<void(::android::C2ComponentInterface*)> deleter) override {
-        *interface =
-                SimpleC2Interface::Builder("aacenc", id, deleter)
-                .inputFormat(C2FormatAudio)
-                .outputFormat(C2FormatCompressed)
-                .build();
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = BuildIntf(kComponentName, id, deleter);
         return C2_OK;
     }
 
@@ -403,12 +412,12 @@
 
 }  // namespace android
 
-extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
     ALOGV("in %s", __func__);
     return new ::android::C2SoftAacEncFactory();
 }
 
-extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
     ALOGV("in %s", __func__);
     delete factory;
 }
diff --git a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
index 306d0a5..b9ba251 100644
--- a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
+++ b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
@@ -54,7 +54,7 @@
 
 #define PRINT_TIME  ALOGV
 
-#define componentName                   "video_decoder.avc"
+constexpr char kComponentName[] = "c2.google.avc.decoder";
 // #define codingType                      OMX_VIDEO_CodingAVC
 #define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_AVC
 
@@ -71,6 +71,18 @@
         (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES
 namespace {
 
+std::shared_ptr<C2ComponentInterface> BuildIntf(
+        const char *name, c2_node_id_t id,
+        std::function<void(C2ComponentInterface*)> deleter =
+            std::default_delete<C2ComponentInterface>()) {
+    return SimpleC2Interface::Builder(name, id, deleter)
+            .inputFormat(C2FormatCompressed)
+            .outputFormat(C2FormatVideo)
+            .inputMediaType(MEDIA_MIMETYPE_VIDEO_AVC)
+            .outputMediaType(MEDIA_MIMETYPE_VIDEO_RAW)
+            .build();
+}
+
 #if 0
 using SupportedValuesWithFields = C2SoftAvcDecIntf::SupportedValuesWithFields;
 
@@ -266,9 +278,9 @@
       mBlocksPerSecond(0u, 0),
       mParamReflector(new ParamReflector) {
     ALOGV("in %s", __func__);
-    mInputPortMime = C2PortMimeConfig::input::alloc_unique(strlen(CODEC_MIME_TYPE) + 1);
+    mInputPortMime = C2PortMimeConfig::input::AllocUnique(strlen(CODEC_MIME_TYPE) + 1);
     strcpy(mInputPortMime->m.value, CODEC_MIME_TYPE);
-    mOutputPortMime = C2PortMimeConfig::output::alloc_unique(strlen(MEDIA_MIMETYPE_VIDEO_RAW) + 1);
+    mOutputPortMime = C2PortMimeConfig::output::AllocUnique(strlen(MEDIA_MIMETYPE_VIDEO_RAW) + 1);
     strcpy(mOutputPortMime->m.value, MEDIA_MIMETYPE_VIDEO_RAW);
 
     mVideoSize.width = 320;
@@ -281,7 +293,7 @@
     mMaxVideoSizeHint.width = H264_MAX_FRAME_WIDTH;
     mMaxVideoSizeHint.height = H264_MAX_FRAME_HEIGHT;
 
-    mOutputBlockPools = C2PortBlockPoolsTuning::output::alloc_unique({});
+    mOutputBlockPools = C2PortBlockPoolsTuning::output::AllocUnique({});
 
     auto insertParam = [&params = mParams] (C2Param *param) {
         params[param->index()] = param;
@@ -614,11 +626,7 @@
 C2SoftAvcDec::C2SoftAvcDec(
         const char *name,
         c2_node_id_t id)
-    : SimpleC2Component(
-          SimpleC2Interface::Builder(name, id)
-          .inputFormat(C2FormatCompressed)
-          .outputFormat(C2FormatVideo)
-          .build()),
+    : SimpleC2Component(BuildIntf(name, id)),
       mCodecCtx(NULL),
       mFlushOutBuffer(NULL),
       mIvColorFormat(IV_YUV_420P),
@@ -1327,21 +1335,18 @@
 class C2SoftAvcDecFactory : public C2ComponentFactory {
 public:
     virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            std::function<void(::android::C2Component*)> deleter) override {
-        *component = std::shared_ptr<C2Component>(new C2SoftAvcDec("avc", id), deleter);
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftAvcDec(kComponentName, id), deleter);
         return C2_OK;
     }
 
     virtual c2_status_t createInterface(
-            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            std::function<void(::android::C2ComponentInterface*)> deleter) override {
-        *interface =
-              SimpleC2Interface::Builder("avc", id, deleter)
-              .inputFormat(C2FormatCompressed)
-              .outputFormat(C2FormatVideo)
-              .build();
-//            std::shared_ptr<C2ComponentInterface>(new C2SoftAvcDecIntf("avc", id), deleter);
+            c2_node_id_t id,
+            std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = BuildIntf(kComponentName, id, deleter);
         return C2_OK;
     }
 
@@ -1350,12 +1355,12 @@
 
 }  // namespace android
 
-extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
     ALOGV("in %s", __func__);
     return new ::android::C2SoftAvcDecFactory();
 }
 
-extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
     ALOGV("in %s", __func__);
     delete factory;
 }
diff --git a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
index 911f0f8..8fb8122 100644
--- a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
@@ -15,7 +15,7 @@
  */
 
 #define LOG_NDEBUG 0
-#define LOG_TAG "C2SoftAvcEncEnc"
+#define LOG_TAG "C2SoftAvcEnc"
 #include <utils/Log.h>
 #include <utils/misc.h>
 
@@ -35,7 +35,9 @@
 
 namespace android {
 
-#define ive_api_function ih264e_api_function
+#define ive_api_function  ih264e_api_function
+
+constexpr char kComponentName[] = "c2.google.avc.encoder";
 
 namespace {
 
@@ -55,6 +57,18 @@
     return (size_t)cpuCoreCount;
 }
 
+std::shared_ptr<C2ComponentInterface> BuildIntf(
+        const char *name, c2_node_id_t id,
+        std::function<void(C2ComponentInterface*)> deleter =
+            std::default_delete<C2ComponentInterface>()) {
+    return SimpleC2Interface::Builder(name, id, deleter)
+            .inputFormat(C2FormatVideo)
+            .outputFormat(C2FormatCompressed)
+            .inputMediaType(MEDIA_MIMETYPE_VIDEO_RAW)
+            .outputMediaType(MEDIA_MIMETYPE_VIDEO_AVC)
+            .build();
+}
+
 void ConvertRGBToPlanarYUV(
         uint8_t *dstY, size_t dstStride, size_t dstVStride,
         const C2GraphicView &src) {
@@ -115,11 +129,7 @@
 }  // namespace
 
 C2SoftAvcEnc::C2SoftAvcEnc(const char *name, c2_node_id_t id)
-    : SimpleC2Component(
-          SimpleC2Interface::Builder(name, id)
-          .inputFormat(C2FormatVideo)
-          .outputFormat(C2FormatCompressed)
-          .build()),
+    : SimpleC2Component(BuildIntf(name, id)),
       mUpdateFlag(0),
       mIvVideoColorFormat(IV_YUV_420P),
       mAVCEncProfile(IV_PROFILE_BASE),
@@ -1044,7 +1054,7 @@
         mSpsPpsHeaderReceived = true;
 
         std::unique_ptr<C2StreamCsdInfo::output> csd =
-            C2StreamCsdInfo::output::alloc_unique(s_encode_op.s_out_buf.u4_bytes, 0u);
+            C2StreamCsdInfo::output::AllocUnique(s_encode_op.s_out_buf.u4_bytes, 0u);
         memcpy(csd->m.value, header, s_encode_op.s_out_buf.u4_bytes);
         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
 
@@ -1209,20 +1219,18 @@
 class C2SoftAvcEncFactory : public C2ComponentFactory {
 public:
     virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            std::function<void(::android::C2Component*)> deleter) override {
-        *component = std::shared_ptr<C2Component>(new C2SoftAvcEnc("avcenc", id), deleter);
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftAvcEnc(kComponentName, id), deleter);
         return C2_OK;
     }
 
     virtual c2_status_t createInterface(
-            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            std::function<void(::android::C2ComponentInterface*)> deleter) override {
-        *interface =
-              SimpleC2Interface::Builder("avcenc", id, deleter)
-              .inputFormat(C2FormatVideo)
-              .outputFormat(C2FormatCompressed)
-              .build();
+            c2_node_id_t id,
+            std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = BuildIntf(kComponentName, id, deleter);
         return C2_OK;
     }
 
@@ -1231,12 +1239,12 @@
 
 }  // namespace android
 
-extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
     ALOGV("in %s", __func__);
     return new ::android::C2SoftAvcEncFactory();
 }
 
-extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
     ALOGV("in %s", __func__);
     delete factory;
 }
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index d95bb07..26f96c3 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -59,11 +59,6 @@
 #include <C2PlatformSupport.h>
 #include <C2Work.h>
 
-extern "C" ::android::C2ComponentFactory *CreateCodec2Factory();
-extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory *);
-
-#include "../avcdec/C2SoftAvcDec.h"
-
 using namespace android;
 using namespace std::chrono_literals;
 
@@ -72,7 +67,7 @@
 class LinearBuffer : public C2Buffer {
 public:
     explicit LinearBuffer(const std::shared_ptr<C2LinearBlock> &block)
-        : C2Buffer({ block->share(block->offset(), block->size(), ::android::C2Fence()) }) {}
+        : C2Buffer({ block->share(block->offset(), block->size(), ::C2Fence()) }) {}
 };
 
 class Listener;
@@ -220,7 +215,7 @@
 
     (void)component->setListener_vb(mListener, C2_DONT_BLOCK);
     std::unique_ptr<C2PortBlockPoolsTuning::output> pools =
-        C2PortBlockPoolsTuning::output::alloc_unique({ (uint64_t)C2BlockPool::BASIC_GRAPHIC });
+        C2PortBlockPoolsTuning::output::AllocUnique({ (uint64_t)C2BlockPool::BASIC_GRAPHIC });
     std::vector<std::unique_ptr<C2SettingResult>> result;
     (void)component->intf()->config_vb({pools.get()}, C2_DONT_BLOCK, &result);
     component->start();
@@ -295,7 +290,7 @@
         size_t size = 0u;
         void *data = nullptr;
         int64_t timestamp = 0u;
-        MediaBuffer *buffer = nullptr;
+        MediaBufferBase *buffer = nullptr;
         sp<ABuffer> csd;
         if (csd0 != nullptr) {
             csd = csd0;
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
index a26dbb9..d296a3d 100644
--- a/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
@@ -24,21 +24,37 @@
 #include <SimpleC2Interface.h>
 
 #include <media/stagefright/foundation/ADebug.h>
-
-#ifdef ALAW
-#define COMPONENT_NAME "g711a"
-#else
-#define COMPONENT_NAME "g711m"
-#endif
+#include <media/stagefright/foundation/MediaDefs.h>
 
 namespace android {
 
-C2SoftG711::C2SoftG711(const char *name, c2_node_id_t id)
-    : SimpleC2Component(
-            SimpleC2Interface::Builder(name, id)
+#ifdef ALAW
+constexpr char kComponentName[] = "c2.google.g711.alaw.decoder";
+#else
+constexpr char kComponentName[] = "c2.google.g711.mlaw.decoder";
+#endif
+
+static std::shared_ptr<C2ComponentInterface> BuildIntf(
+        const char *name, c2_node_id_t id,
+        std::function<void(C2ComponentInterface*)> deleter =
+            std::default_delete<C2ComponentInterface>()) {
+    return SimpleC2Interface::Builder(name, id, deleter)
             .inputFormat(C2FormatCompressed)
             .outputFormat(C2FormatAudio)
-            .build()) {
+            .inputMediaType(
+#ifdef ALAW
+                    MEDIA_MIMETYPE_AUDIO_G711_ALAW
+#else
+                    MEDIA_MIMETYPE_AUDIO_G711_MLAW
+#endif
+            )
+            .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
+            .build();
+}
+
+
+C2SoftG711::C2SoftG711(const char *name, c2_node_id_t id)
+    : SimpleC2Component(BuildIntf(name, id)) {
 }
 
 C2SoftG711::~C2SoftG711() {
@@ -206,20 +222,17 @@
 class C2SoftG711DecFactory : public C2ComponentFactory {
 public:
     virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            std::function<void(::android::C2Component*)> deleter) override {
-        *component = std::shared_ptr<C2Component>(new C2SoftG711(COMPONENT_NAME, id), deleter);
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftG711(kComponentName, id), deleter);
         return C2_OK;
     }
 
     virtual c2_status_t createInterface(
             c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            std::function<void(::android::C2ComponentInterface*)> deleter) override {
-        *interface =
-                SimpleC2Interface::Builder(COMPONENT_NAME, id, deleter)
-                .inputFormat(C2FormatCompressed)
-                .outputFormat(C2FormatAudio)
-                .build();
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = BuildIntf(kComponentName, id, deleter);
         return C2_OK;
     }
 
@@ -228,12 +241,12 @@
 
 }  // namespace android
 
-extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
     ALOGV("in %s", __func__);
     return new ::android::C2SoftG711DecFactory();
 }
 
-extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
     ALOGV("in %s", __func__);
     delete factory;
 }
diff --git a/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp
index c34a6f0..9cac87e 100644
--- a/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/C2SoftMP3.cpp
@@ -26,17 +26,28 @@
 #include <SimpleC2Interface.h>
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 
 #include <numeric>
 
 namespace android {
 
-C2SoftMP3::C2SoftMP3(const char *name, c2_node_id_t id)
-    : SimpleC2Component(
-            SimpleC2Interface::Builder(name, id)
+constexpr char kComponentName[] = "c2.google.aac.encoder";
+
+static std::shared_ptr<C2ComponentInterface> BuildIntf(
+        const char *name, c2_node_id_t id,
+        std::function<void(C2ComponentInterface*)> deleter =
+            std::default_delete<C2ComponentInterface>()) {
+    return SimpleC2Interface::Builder(name, id, deleter)
             .inputFormat(C2FormatCompressed)
             .outputFormat(C2FormatAudio)
-            .build()),
+            .inputMediaType(MEDIA_MIMETYPE_AUDIO_MPEG)
+            .outputMediaType(MEDIA_MIMETYPE_AUDIO_RAW)
+            .build();
+}
+
+C2SoftMP3::C2SoftMP3(const char *name, c2_node_id_t id)
+    : SimpleC2Component(BuildIntf(name, id)),
       mConfig(nullptr),
       mDecoderBuf(nullptr) {
 }
@@ -397,20 +408,18 @@
 class C2SoftMp3DecFactory : public C2ComponentFactory {
 public:
     virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            std::function<void(::android::C2Component*)> deleter) override {
-        *component = std::shared_ptr<C2Component>(new C2SoftMP3("mp3", id), deleter);
+            c2_node_id_t id,
+            std::shared_ptr<C2Component>* const component,
+            std::function<void(C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftMP3(kComponentName, id), deleter);
         return C2_OK;
     }
 
     virtual c2_status_t createInterface(
-            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            std::function<void(::android::C2ComponentInterface*)> deleter) override {
-        *interface =
-                SimpleC2Interface::Builder("mp3", id, deleter)
-                .inputFormat(C2FormatCompressed)
-                .outputFormat(C2FormatAudio)
-                .build();
+            c2_node_id_t id,
+            std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(C2ComponentInterface*)> deleter) override {
+        *interface = BuildIntf(kComponentName, id, deleter);
         return C2_OK;
     }
 
@@ -419,12 +428,12 @@
 
 }  // namespace android
 
-extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
     ALOGV("in %s", __func__);
     return new ::android::C2SoftMp3DecFactory();
 }
 
-extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
     ALOGV("in %s", __func__);
     delete factory;
 }
diff --git a/media/libstagefright/foundation/avc_utils.cpp b/media/libstagefright/foundation/avc_utils.cpp
index 8414af3..e8a6083 100644
--- a/media/libstagefright/foundation/avc_utils.cpp
+++ b/media/libstagefright/foundation/avc_utils.cpp
@@ -537,49 +537,6 @@
     return layerId;
 }
 
-sp<ABuffer> MakeAACCodecSpecificData(
-        unsigned profile, unsigned sampling_freq_index,
-        unsigned channel_configuration, int32_t *sampleRate,
-        int32_t *channelCount) {
-    CHECK_LE(sampling_freq_index, 11u);
-    static const int32_t kSamplingFreq[] = {
-        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-        16000, 12000, 11025, 8000
-    };
-    *sampleRate = kSamplingFreq[sampling_freq_index];
-    *channelCount = channel_configuration;
-
-    static const uint8_t kStaticESDS[] = {
-        0x03, 22,
-        0x00, 0x00,     // ES_ID
-        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
-
-        0x04, 17,
-        0x40,                       // Audio ISO/IEC 14496-3
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-
-        0x05, 2,
-        // AudioSpecificInfo follows
-
-        // oooo offf fccc c000
-        // o - audioObjectType
-        // f - samplingFreqIndex
-        // c - channelConfig
-    };
-    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
-    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
-
-    csd->data()[sizeof(kStaticESDS)] =
-        ((profile + 1) << 3) | (sampling_freq_index >> 1);
-
-    csd->data()[sizeof(kStaticESDS) + 1] =
-        ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
-
-    return csd;
-}
-
 bool ExtractDimensionsFromVOLHeader(
         const uint8_t *data, size_t size, int32_t *width, int32_t *height) {
     ABitReader br(&data[4], size - 4);
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
index 2ca66fb..c287559 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/avc_utils.h
@@ -90,11 +90,6 @@
 
 const char *AVCProfileToString(uint8_t profile);
 
-sp<ABuffer> MakeAACCodecSpecificData(
-        unsigned profile, unsigned sampling_freq_index,
-        unsigned channel_configuration, int32_t *sampleRate,
-        int32_t *channelCount);
-
 // Given an MPEG4 video VOL-header chunk (starting with 0x00 0x00 0x01 0x2?)
 // parse it and fill in dimensions, returns true iff successful.
 bool ExtractDimensionsFromVOLHeader(
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index f64e437..8a77401 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -40,6 +40,7 @@
         "libstagefright",
         "libstagefright_foundation",
         "libutils",
+        "libhidlallocatorutils",
         "libhidlbase",
         "android.hardware.cas@1.0",
         "android.hardware.cas.native@1.0",
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index f253a52..7c01e45 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -29,8 +29,10 @@
 #include <media/IOMX.h>
 
 namespace android {
-
-using hardware::hidl_memory;
+namespace hardware {
+class HidlMemory;
+};
+using hardware::HidlMemory;
 
 /**
  * BufferChannelBase implementation for ACodec.
@@ -119,7 +121,7 @@
     sp<MemoryDealer> mDealer;
     sp<IMemory> mDecryptDestination;
     int32_t mHeapSeqNum;
-    hidl_memory mHidlMemory;
+    sp<HidlMemory> mHidlMemory;
 
     // These should only be accessed via std::atomic_* functions.
     //
diff --git a/media/libstagefright/include/C2OMXNode.h b/media/libstagefright/include/C2OMXNode.h
new file mode 100644
index 0000000..3c007c4
--- /dev/null
+++ b/media/libstagefright/include/C2OMXNode.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef C2_OMX_NODE_H_
+#define C2_OMX_NODE_H_
+
+#include <atomic>
+
+#include <android/IOMXBufferSource.h>
+#include <media/IOMX.h>
+#include <media/OMXBuffer.h>
+
+namespace android {
+
+/**
+ * IOmxNode implementation around codec 2.0 component, only to be used in
+ * IGraphicBufferSource::configure. Only subset of IOmxNode API is implemented
+ * and others are left as stub. As a result, one cannot expect this IOmxNode
+ * to work in any other usage than IGraphicBufferSource.
+ */
+struct C2OMXNode : public BnOMXNode {
+    // TODO: this should take android::hardware::media::c2::V1_0::IComponent
+    explicit C2OMXNode(const std::shared_ptr<C2Component> &comp);
+    ~C2OMXNode() override = default;
+
+    // IOMXNode
+    status_t freeNode() override;
+    status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) override;
+    status_t getParameter(
+            OMX_INDEXTYPE index, void *params, size_t size) override;
+    status_t setParameter(
+            OMX_INDEXTYPE index, const void *params, size_t size) override;
+    status_t getConfig(
+            OMX_INDEXTYPE index, void *params, size_t size) override;
+    status_t setConfig(
+            OMX_INDEXTYPE index, const void *params, size_t size) override;
+    status_t setPortMode(OMX_U32 port_index, IOMX::PortMode mode) override;
+    status_t prepareForAdaptivePlayback(
+            OMX_U32 portIndex, OMX_BOOL enable,
+            OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) override;
+    status_t configureVideoTunnelMode(
+            OMX_U32 portIndex, OMX_BOOL tunneled,
+            OMX_U32 audioHwSync, native_handle_t **sidebandHandle) override;
+    status_t getGraphicBufferUsage(
+            OMX_U32 port_index, OMX_U32* usage) override;
+    status_t setInputSurface(
+            const sp<IOMXBufferSource> &bufferSource) override;
+    status_t allocateSecureBuffer(
+            OMX_U32 port_index, size_t size, buffer_id *buffer,
+            void **buffer_data, sp<NativeHandle> *native_handle) override;
+    status_t useBuffer(
+            OMX_U32 port_index, const OMXBuffer &omxBuf, buffer_id *buffer) override;
+    status_t freeBuffer(
+            OMX_U32 port_index, buffer_id buffer) override;
+    status_t fillBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf, int fenceFd) override;
+    status_t emptyBuffer(
+            buffer_id buffer, const OMXBuffer &omxBuf,
+            OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) override;
+    status_t getExtensionIndex(
+            const char *parameter_name,
+            OMX_INDEXTYPE *index) override;
+    status_t dispatchMessage(const omx_message &msg) override;
+
+    sp<IOMXBufferSource> getSource();
+
+private:
+    std::weak_ptr<C2Component> mComp;
+    sp<IOMXBufferSource> mBufferSource;
+    std::shared_ptr<C2Allocator> mAllocator;
+    std::atomic_uint64_t mFrameIndex;
+};
+
+}  // namespace android
+
+#endif  // C2_OMX_NODE_H_
diff --git a/media/libstagefright/include/CCodecBufferChannel.h b/media/libstagefright/include/CCodecBufferChannel.h
index e64f984..eb3255f 100644
--- a/media/libstagefright/include/CCodecBufferChannel.h
+++ b/media/libstagefright/include/CCodecBufferChannel.h
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef A_BUFFER_CHANNEL_H_
+#ifndef CCODEC_BUFFER_CHANNEL_H_
 
-#define A_BUFFER_CHANNEL_H_
+#define CCODEC_BUFFER_CHANNEL_H_
 
 #include <map>
 #include <memory>
@@ -26,13 +26,19 @@
 #include <C2Buffer.h>
 #include <C2Component.h>
 
-#include <media/stagefright/foundation/Mutexed.h>
 #include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <media/stagefright/codec2/1.0/InputSurface.h>
+#include <media/stagefright/foundation/Mutexed.h>
 #include <media/stagefright/CodecBase.h>
 #include <media/ICrypto.h>
 
+#include "InputSurfaceWrapper.h"
+
 namespace android {
 
+using ::android::hardware::media::c2::V1_0::implementation::InputSurface;
+using ::android::hardware::media::c2::V1_0::implementation::InputSurfaceConnection;
+
 /**
  * BufferChannelBase implementation for CCodec.
  */
@@ -76,7 +82,7 @@
      * Set GraphicBufferSource object from which the component extracts input
      * buffers.
      */
-    status_t setGraphicBufferSource(const sp<GraphicBufferSource> &source);
+    status_t setInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
 
     /**
      * Start queueing buffers to the component. This object should never queue
@@ -103,7 +109,6 @@
     class Buffers;
     class InputBuffers;
     class OutputBuffers;
-    class InputBufferClient;
 
 private:
     class QueueGuard;
@@ -156,8 +161,6 @@
         bool mRunning;
     };
 
-    class C2ComponentWrapper;
-
     void feedInputBufferIfAvailable();
 
     QueueSync mSync;
@@ -166,7 +169,6 @@
     int32_t mHeapSeqNum;
 
     std::shared_ptr<C2Component> mComponent;
-    std::shared_ptr<InputBufferClient> mInputClient;
     std::function<void(status_t, enum ActionCode)> mOnError;
     std::shared_ptr<C2BlockPool> mInputAllocator;
     QueueSync mQueueSync;
@@ -180,6 +182,8 @@
     sp<MemoryDealer> makeMemoryDealer(size_t heapSize);
     Mutexed<sp<Surface>> mSurface;
 
+    std::shared_ptr<InputSurfaceWrapper> mInputSurface;
+
     inline bool hasCryptoOrDescrambler() {
         return mCrypto != NULL || mDescrambler != NULL;
     }
@@ -187,4 +191,4 @@
 
 }  // namespace android
 
-#endif  // A_BUFFER_CHANNEL_H_
+#endif  // CCODEC_BUFFER_CHANNEL_H_
diff --git a/media/libstagefright/include/Codec2Buffer.h b/media/libstagefright/include/Codec2Buffer.h
index 6d85e83..9766b41 100644
--- a/media/libstagefright/include/Codec2Buffer.h
+++ b/media/libstagefright/include/Codec2Buffer.h
@@ -24,17 +24,100 @@
 
 namespace android {
 
+class Codec2Buffer : public MediaCodecBuffer {
+public:
+    using MediaCodecBuffer::MediaCodecBuffer;
+    ~Codec2Buffer() override = default;
+
+    /**
+     * \return  C2Buffer object represents this buffer.
+     */
+    virtual std::shared_ptr<C2Buffer> asC2Buffer() = 0;
+
+    /**
+     * Test if we can copy the content of |buffer| into this object.
+     *
+     * \param   buffer  C2Buffer object to copy.
+     * \return  true    if the content of buffer can be copied over to this buffer
+     *          false   otherwise.
+     */
+    virtual bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const {
+        (void)buffer;
+        return false;
+    }
+
+    /**
+     * Copy the content of |buffer| into this object. This method assumes that
+     * canCopy() check already passed.
+     *
+     * \param   buffer  C2Buffer object to copy.
+     * \return  true    if successful
+     *          false   otherwise.
+     */
+    virtual bool copy(const std::shared_ptr<C2Buffer> &buffer) {
+        (void)buffer;
+        return false;
+    }
+
+protected:
+    /**
+     * canCopy() implementation for linear buffers.
+     */
+    bool canCopyLinear(const std::shared_ptr<C2Buffer> &buffer) const;
+
+    /**
+     * copy() implementation for linear buffers.
+     */
+    bool copyLinear(const std::shared_ptr<C2Buffer> &buffer);
+};
+
+/**
+ * MediaCodecBuffer implementation on top of local linear buffer. This cannot
+ * cross process boundary so asC2Buffer() returns only nullptr.
+ */
+class LocalLinearBuffer : public Codec2Buffer {
+public:
+    using Codec2Buffer::Codec2Buffer;
+
+    std::shared_ptr<C2Buffer> asC2Buffer() override { return nullptr; }
+    bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
+    bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
+};
+
+/**
+ * MediaCodecBuffer implementation to be used only as a dummy wrapper around a
+ * C2Buffer object.
+ */
+class DummyContainerBuffer : public Codec2Buffer {
+public:
+    DummyContainerBuffer(
+            const sp<AMessage> &format,
+            const std::shared_ptr<C2Buffer> &buffer = nullptr);
+
+    std::shared_ptr<C2Buffer> asC2Buffer() override;
+    bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
+    bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
+
+private:
+    std::shared_ptr<C2Buffer> mBufferRef;
+};
+
 /**
  * MediaCodecBuffer implementation wraps around C2LinearBlock.
  */
-class LinearBlockBuffer : public MediaCodecBuffer {
+class LinearBlockBuffer : public Codec2Buffer {
 public:
-    static sp<LinearBlockBuffer> allocate(
+    /**
+     * Allocate a new LinearBufferBlock wrapping around C2LinearBlock object.
+     */
+    static sp<LinearBlockBuffer> Allocate(
             const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block);
 
     virtual ~LinearBlockBuffer() = default;
 
-    C2ConstLinearBlock share();
+    std::shared_ptr<C2Buffer> asC2Buffer() override;
+    bool canCopy(const std::shared_ptr<C2Buffer> &buffer) const override;
+    bool copy(const std::shared_ptr<C2Buffer> &buffer) override;
 
 private:
     LinearBlockBuffer(
@@ -50,20 +133,27 @@
 /**
  * MediaCodecBuffer implementation wraps around C2ConstLinearBlock.
  */
-class ConstLinearBlockBuffer : public MediaCodecBuffer {
+class ConstLinearBlockBuffer : public Codec2Buffer {
 public:
-    static sp<ConstLinearBlockBuffer> allocate(
-            const sp<AMessage> &format, const C2ConstLinearBlock &block);
+    /**
+     * Allocate a new ConstLinearBlockBuffer wrapping around C2Buffer object.
+     */
+    static sp<ConstLinearBlockBuffer> Allocate(
+            const sp<AMessage> &format, const std::shared_ptr<C2Buffer> &buffer);
 
     virtual ~ConstLinearBlockBuffer() = default;
 
+    std::shared_ptr<C2Buffer> asC2Buffer() override;
+
 private:
     ConstLinearBlockBuffer(
             const sp<AMessage> &format,
-            C2ReadView &&readView);
+            C2ReadView &&readView,
+            const std::shared_ptr<C2Buffer> &buffer);
     ConstLinearBlockBuffer() = delete;
 
     C2ReadView mReadView;
+    std::shared_ptr<C2Buffer> mBufferRef;
 };
 
 }  // namespace android
diff --git a/media/libstagefright/include/InputSurfaceWrapper.h b/media/libstagefright/include/InputSurfaceWrapper.h
new file mode 100644
index 0000000..a4d8f29
--- /dev/null
+++ b/media/libstagefright/include/InputSurfaceWrapper.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#ifndef INPUT_SURFACE_WRAPPER_H_
+
+#define INPUT_SURFACE_WRAPPER_H_
+
+namespace android {
+
+/**
+ * Wrapper interface around InputSurface.
+ */
+class InputSurfaceWrapper {
+public:
+    virtual ~InputSurfaceWrapper() = default;
+
+    /**
+     * Connect the surface with |comp| and start pushing buffers. A surface can
+     * connect to at most one component at a time.
+     *
+     * \return OK               successfully connected to |comp|
+     * \return ALREADY_EXISTS   already connected to another component.
+     */
+    virtual status_t connect(const std::shared_ptr<C2Component> &comp) = 0;
+
+    /**
+     * Disconnect the surface from the component if any.
+     */
+    virtual void disconnect() = 0;
+
+    // TODO: intf()
+};
+
+}  // namespace android
+
+#endif  // INPUT_SURFACE_WRAPPER_H_
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/media/libstagefright/include/media/stagefright/AudioPlayer.h
index e971762..7c2c36f 100644
--- a/media/libstagefright/include/media/stagefright/AudioPlayer.h
+++ b/media/libstagefright/include/media/stagefright/AudioPlayer.h
@@ -69,7 +69,7 @@
     sp<MediaSource> mSource;
     sp<AudioTrack> mAudioTrack;
 
-    MediaBuffer *mInputBuffer;
+    MediaBufferBase *mInputBuffer;
 
     int mSampleRate;
     int64_t mLatencyUs;
@@ -91,7 +91,7 @@
 
     bool mIsFirstBuffer;
     status_t mFirstBufferResult;
-    MediaBuffer *mFirstBuffer;
+    MediaBufferBase *mFirstBuffer;
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
 
diff --git a/media/libstagefright/include/media/stagefright/AudioSource.h b/media/libstagefright/include/media/stagefright/AudioSource.h
index f66b92d..206d322 100644
--- a/media/libstagefright/include/media/stagefright/AudioSource.h
+++ b/media/libstagefright/include/media/stagefright/AudioSource.h
@@ -56,11 +56,11 @@
     int16_t getMaxAmplitude();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
     virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
     status_t dataCallback(const AudioRecord::Buffer& buffer);
-    virtual void signalBufferReturned(MediaBuffer *buffer);
+    virtual void signalBufferReturned(MediaBufferBase *buffer);
 
     status_t setInputDevice(audio_port_handle_t deviceId);
     status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
diff --git a/media/libstagefright/include/media/stagefright/CCodec.h b/media/libstagefright/include/media/stagefright/CCodec.h
index 9307f3f..3a2670d 100644
--- a/media/libstagefright/include/media/stagefright/CCodec.h
+++ b/media/libstagefright/include/media/stagefright/CCodec.h
@@ -24,7 +24,6 @@
 #include <android/native_window.h>
 #include <media/hardware/MetadataBufferType.h>
 #include <media/stagefright/foundation/Mutexed.h>
-#include <media/stagefright/bqhelper/GraphicBufferSource.h>
 #include <media/stagefright/CodecBase.h>
 #include <media/stagefright/FrameRenderTracker.h>
 #include <media/stagefright/MediaDefs.h>
@@ -36,6 +35,7 @@
 namespace android {
 
 class CCodecBufferChannel;
+class InputSurfaceWrapper;
 
 class CCodec : public CodecBase {
 public:
@@ -81,9 +81,9 @@
 
     void createInputSurface();
     void setInputSurface(const sp<PersistentSurface> &surface);
-    status_t setupInputSurface(const sp<GraphicBufferSource> &source);
+    status_t setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface);
 
-    void setDeadline(const TimePoint &deadline);
+    void setDeadline(const TimePoint &deadline, const char *name);
 
     enum {
         kWhatAllocate,
@@ -126,10 +126,25 @@
         sp<AMessage> outputFormat;
     };
 
+    struct NamedTimePoint {
+        inline void set(
+                const TimePoint &timePoint,
+                const char *name) {
+            mTimePoint = timePoint;
+            mName = name;
+        }
+
+        inline TimePoint get() const { return mTimePoint; }
+        inline const char *getName() const { return mName; }
+    private:
+        TimePoint mTimePoint;
+        const char *mName;
+    };
+
     Mutexed<State> mState;
     std::shared_ptr<CCodecBufferChannel> mChannel;
     std::shared_ptr<C2Component::Listener> mListener;
-    Mutexed<TimePoint> mDeadline;
+    Mutexed<NamedTimePoint> mDeadline;
     Mutexed<Formats> mFormats;
     Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
 
diff --git a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
index 944d951..33453fa 100644
--- a/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/CallbackMediaSource.h
@@ -33,7 +33,7 @@
     virtual status_t stop();
     virtual sp<MetaData> getFormat();
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
     virtual status_t pause();
 
 private:
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 945e1be..475976b 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -97,7 +97,7 @@
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop() { return reset(); }
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
     virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
     /**
@@ -127,7 +127,7 @@
      */
     MetadataBufferType metaDataStoredInVideoBuffers() const;
 
-    virtual void signalBufferReturned(MediaBuffer* buffer);
+    virtual void signalBufferReturned(MediaBufferBase* buffer);
 
 protected:
 
diff --git a/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
index b066f9a..533e33b 100644
--- a/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/media/libstagefright/include/media/stagefright/CameraSourceTimeLapse.h
@@ -107,7 +107,7 @@
 
     // Stores a copy of the MediaBuffer read in the last read() call after
     // mQuickStop was true.
-    MediaBuffer* mLastReadBufferCopy;
+    MediaBufferBase* mLastReadBufferCopy;
 
     // Status code for last read.
     status_t mLastReadStatus;
@@ -128,10 +128,10 @@
     // Wrapper over CameraSource::signalBufferReturned() to implement quick stop.
     // It only handles the case when mLastReadBufferCopy is signalled. Otherwise
     // it calls the base class' function.
-    virtual void signalBufferReturned(MediaBuffer* buffer);
+    virtual void signalBufferReturned(MediaBufferBase* buffer);
 
     // Wrapper over CameraSource::read() to implement quick stop.
-    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options = NULL);
+    virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
     // mSkipCurrentFrame is set to true in dataCallbackTimestamp() if the current
     // frame needs to be skipped and this function just returns the value of mSkipCurrentFrame.
@@ -170,7 +170,7 @@
 
     // Convenience function to fill mLastReadBufferCopy from the just read
     // buffer.
-    void fillLastReadBufferCopy(MediaBuffer& sourceBuffer);
+    void fillLastReadBufferCopy(MediaBufferBase& sourceBuffer);
 
     // If the passed in size (width x height) is a supported video/preview size,
     // the function sets the camera's video/preview size to it and returns true.
diff --git a/media/libstagefright/include/media/stagefright/Codec2InfoBuilder.h b/media/libstagefright/include/media/stagefright/Codec2InfoBuilder.h
new file mode 100644
index 0000000..ea0b5c4
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/Codec2InfoBuilder.h
@@ -0,0 +1,33 @@
+/*
+ * 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 CODEC2_INFO_BUILDER_H_
+#define CODEC2_INFO_BUILDER_H_
+
+#include <media/stagefright/MediaCodecList.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class Codec2InfoBuilder : public MediaCodecListBuilderBase {
+public:
+    Codec2InfoBuilder() = default;
+    status_t buildMediaCodecList(MediaCodecListWriter* writer) override;
+};
+
+}  // namespace android
+
+#endif  // CODEC2_INFO_BUILDER_H_
diff --git a/media/libstagefright/include/media/stagefright/JPEGSource.h b/media/libstagefright/include/media/stagefright/JPEGSource.h
index 9fcbfc2..8ab3d11 100644
--- a/media/libstagefright/include/media/stagefright/JPEGSource.h
+++ b/media/libstagefright/include/media/stagefright/JPEGSource.h
@@ -33,7 +33,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
 protected:
     virtual ~JPEGSource();
diff --git a/media/libstagefright/include/media/stagefright/MediaAdapter.h b/media/libstagefright/include/media/stagefright/MediaAdapter.h
index 4b47160..589c827 100644
--- a/media/libstagefright/include/media/stagefright/MediaAdapter.h
+++ b/media/libstagefright/include/media/stagefright/MediaAdapter.h
@@ -40,13 +40,13 @@
     virtual status_t stop();
     virtual sp<MetaData> getFormat();
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
     /////////////////////////////////////////////////
     // Inherited functions from MediaBufferObserver
     /////////////////////////////////////////////////
 
-    virtual void signalBufferReturned(MediaBuffer *buffer);
+    virtual void signalBufferReturned(MediaBufferBase *buffer);
 
     /////////////////////////////////////////////////
     // Non-inherited functions:
diff --git a/media/libstagefright/include/media/stagefright/MediaBufferBase.h b/media/libstagefright/include/media/stagefright/MediaBufferBase.h
new file mode 120000
index 0000000..80e49b0
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaBufferBase.h
@@ -0,0 +1 @@
+../../../../libmediaextractor/include/media/stagefright/MediaBufferBase.h
\ No newline at end of file
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 0bc02af..e7faea5 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -334,8 +334,6 @@
 
     // initial create parameters
     AString mInitName;
-    bool mInitNameIsType;
-    bool mInitIsEncoder;
 
     // configure parameter
     sp<AMessage> mConfigureMsg;
@@ -370,14 +368,14 @@
 
     MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid);
 
-    static sp<CodecBase> GetCodecBase(const AString &name, bool nameIsType = false);
+    static sp<CodecBase> GetCodecBase(const AString &name);
 
     static status_t PostAndAwaitResponse(
             const sp<AMessage> &msg, sp<AMessage> *response);
 
     void PostReplyWithError(const sp<AReplyToken> &replyID, int32_t err);
 
-    status_t init(const AString &name, bool nameIsType, bool encoder);
+    status_t init(const AString &name);
 
     void setState(State newState);
     void returnBuffersToCodec(bool isReclaim = false);
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecList.h b/media/libstagefright/include/media/stagefright/MediaCodecList.h
index f2bd496..d46fe85 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecList.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecList.h
@@ -18,6 +18,8 @@
 
 #define MEDIA_CODEC_LIST_H_
 
+#include <initializer_list>
+
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AString.h>
 #include <media/IMediaCodecList.h>
@@ -94,9 +96,9 @@
 
     /**
      * This constructor will call `buildMediaCodecList()` from the given
-     * `MediaCodecListBuilderBase` object.
+     * `MediaCodecListBuilderBase` objects.
      */
-    MediaCodecList(MediaCodecListBuilderBase* builder);
+    MediaCodecList(std::initializer_list<MediaCodecListBuilderBase*> builders);
 
     ~MediaCodecList();
 
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecSource.h b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
index eec115e..a68cc19 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecSource.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecSource.h
@@ -57,13 +57,13 @@
     virtual status_t pause(MetaData *params);
     virtual sp<MetaData> getFormat();
     virtual status_t read(
-            MediaBuffer **buffer,
+            MediaBufferBase **buffer,
             const ReadOptions *options = NULL);
     virtual status_t setStopTimeUs(int64_t stopTimeUs);
 
 
     // MediaBufferObserver
-    virtual void signalBufferReturned(MediaBuffer *buffer);
+    virtual void signalBufferReturned(MediaBufferBase *buffer);
 
     // for AHandlerReflector
     void onMessageReceived(const sp<AMessage> &msg);
@@ -136,7 +136,7 @@
     sp<AMessage> mEncoderActivityNotify;
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
     sp<PersistentSurface> mPersistentSurface;
-    List<MediaBuffer *> mInputBufferQueue;
+    List<MediaBufferBase *> mInputBufferQueue;
     List<size_t> mAvailEncoderInputIndices;
     List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
     int64_t mInputBufferTimeOffsetUs;
@@ -149,7 +149,7 @@
 
     struct Output {
         Output();
-        List<MediaBuffer*> mBufferQueue;
+        List<MediaBufferBase*> mBufferQueue;
         bool mEncoderReachedEOS;
         status_t mErrorCode;
         Condition mCond;
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 4d2f4f0..90c66eb 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -57,7 +57,7 @@
             const sp<ExtractorPlugin> &plugin, List<sp<ExtractorPlugin>> &pluginList);
 
     static MediaExtractor::CreatorFunc sniff(DataSourceBase *source,
-            String8 *mimeType, float *confidence, sp<AMessage> *meta,
+            float *confidence, void **meta, MediaExtractor::FreeMetaFunc *freeMeta,
             sp<ExtractorPlugin> &plugin);
 
     static void UpdateExtractors(const char *newUpdateApkPath);
diff --git a/media/libstagefright/include/media/stagefright/NdkUtils.h b/media/libstagefright/include/media/stagefright/NdkUtils.h
new file mode 100644
index 0000000..a68884a
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/NdkUtils.h
@@ -0,0 +1,31 @@
+/*
+ * 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 NDK_UTILS_H_
+
+#define NDK_UTILS_H_
+
+#include <media/stagefright/MetaData.h>
+#include <media/NdkWrapper.h>
+
+namespace android {
+
+sp<MetaData> convertMediaFormatWrapperToMetaData(
+        const sp<AMediaFormatWrapper> &fmt);
+
+}  // namespace android
+
+#endif  // NDK_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 6a2e39b..5e5ef6e 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -107,8 +107,8 @@
 
     struct Sample {
         Sample();
-        Sample(MediaBuffer *buffer, int64_t timeUs);
-        MediaBuffer *mBuffer;
+        Sample(MediaBufferBase *buffer, int64_t timeUs);
+        MediaBufferBase *mBuffer;
         int64_t mSampleTimeUs;
     };
 
@@ -150,7 +150,7 @@
 
     bool getTotalBitrate(int64_t *bitRate) const;
     status_t updateDurationAndBitrate();
-    status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer);
+    status_t appendVorbisNumPageSamples(MediaBufferBase *mbuf, const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
 };
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 22a8210..509e669 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -40,8 +40,6 @@
     virtual sp<MetaData> getMetaData();
     virtual status_t getMetrics(Parcel *reply);
     virtual uint32_t flags() const;
-    virtual char* getDrmTrackInfo(size_t trackID, int * len);
-    virtual void setUID(uid_t uid);
     virtual status_t setMediaCas(const HInterfaceToken &casToken);
     virtual const char * name();
 
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index d1afa6a..a9bf820 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -35,7 +35,7 @@
     virtual status_t stop();
     virtual sp<MetaData> getFormat();
     virtual status_t read(
-            MediaBuffer **buffer,
+            MediaBufferBase **buffer,
             const MediaSource::ReadOptions *options = NULL);
     virtual status_t pause();
     virtual status_t setStopTimeUs(int64_t stopTimeUs);
diff --git a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
index 3006b45..23defb4 100644
--- a/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
+++ b/media/libstagefright/include/media/stagefright/SimpleDecodingSource.h
@@ -65,7 +65,7 @@
     virtual sp<MetaData> getFormat();
 
     // reads from the source. This call always blocks.
-    virtual status_t read(MediaBuffer **buffer, const ReadOptions *options);
+    virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options);
 
     // unsupported methods
     virtual status_t pause() { return INVALID_OPERATION; }
@@ -104,7 +104,8 @@
 
     // do the actual reading
     status_t doRead(
-            Mutexed<ProtectedState>::Locked &me, MediaBuffer **buffer, const ReadOptions *options);
+            Mutexed<ProtectedState>::Locked &me, MediaBufferBase **buffer,
+            const ReadOptions *options);
 };
 
 } // namespace android
diff --git a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h b/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
deleted file mode 100644
index 2e495f9..0000000
--- a/media/libstagefright/include/media/stagefright/SurfaceMediaSource.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2011 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_GUI_SURFACEMEDIASOURCE_H
-#define ANDROID_GUI_SURFACEMEDIASOURCE_H
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferQueue.h>
-
-#include <utils/threads.h>
-#include <utils/Vector.h>
-#include <media/MediaSource.h>
-#include <media/stagefright/MediaBuffer.h>
-
-#include <media/hardware/MetadataBufferType.h>
-
-#include "foundation/ABase.h"
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class String8;
-class GraphicBuffer;
-
-// ASSUMPTIONS
-// 1. SurfaceMediaSource is initialized with width*height which
-// can never change.  However, deqeueue buffer does not currently
-// enforce this as in BufferQueue, dequeue can be used by Surface
-// which can modify the default width and heght.  Also neither the width
-// nor height can be 0.
-// 2. setSynchronousMode is never used (basically no one should call
-// setSynchronousMode(false)
-// 3. setCrop, setTransform, setScalingMode should never be used
-// 4. queueBuffer returns a filled buffer to the SurfaceMediaSource. In addition, a
-// timestamp must be provided for the buffer. The timestamp is in
-// nanoseconds, and must be monotonically increasing. Its other semantics
-// (zero point, etc) are client-dependent and should be documented by the
-// client.
-// 5. Once disconnected, SurfaceMediaSource can be reused (can not
-// connect again)
-// 6. Stop is a hard stop, the last few frames held by the encoder
-// may be dropped.  It is possible to wait for the buffers to be
-// returned (but not implemented)
-
-#define DEBUG_PENDING_BUFFERS   0
-
-class SurfaceMediaSource : public MediaSource,
-                                public MediaBufferObserver,
-                                protected ConsumerListener {
-public:
-    enum { MIN_UNDEQUEUED_BUFFERS = 4};
-
-    struct FrameAvailableListener : public virtual RefBase {
-        // onFrameAvailable() is called from queueBuffer() is the FIFO is
-        // empty. You can use SurfaceMediaSource::getQueuedCount() to
-        // figure out if there are more frames waiting.
-        // This is called without any lock held can be called concurrently by
-        // multiple threads.
-        virtual void onFrameAvailable() = 0;
-    };
-
-    SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight);
-
-    virtual ~SurfaceMediaSource();
-
-    // For the MediaSource interface for use by StageFrightRecorder:
-    virtual status_t start(MetaData *params = NULL);
-    virtual status_t stop();
-    virtual status_t read(MediaBuffer **buffer,
-            const ReadOptions *options = NULL);
-    virtual sp<MetaData> getFormat();
-
-    // Get / Set the frame rate used for encoding. Default fps = 30
-    status_t setFrameRate(int32_t fps) ;
-    int32_t getFrameRate( ) const;
-
-    // The call for the StageFrightRecorder to tell us that
-    // it is done using the MediaBuffer data so that its state
-    // can be set to FREE for dequeuing
-    virtual void signalBufferReturned(MediaBuffer* buffer);
-    // end of MediaSource interface
-
-    // getTimestamp retrieves the timestamp associated with the image
-    // set by the most recent call to read()
-    //
-    // The timestamp is in nanoseconds, and is monotonically increasing. Its
-    // other semantics (zero point, etc) are source-dependent and should be
-    // documented by the source.
-    int64_t getTimestamp();
-
-    // setFrameAvailableListener sets the listener object that will be notified
-    // when a new frame becomes available.
-    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
-
-    // dump our state in a String
-    void dumpState(String8& result) const;
-    void dumpState(String8& result, const char* prefix, char* buffer,
-                                                    size_t SIZE) const;
-
-    // metaDataStoredInVideoBuffers tells the encoder what kind of metadata
-    // is passed through the buffers. Currently, it is set to ANWBuffer
-    MetadataBufferType metaDataStoredInVideoBuffers() const;
-
-    sp<IGraphicBufferProducer> getProducer() const { return mProducer; }
-
-    // To be called before start()
-    status_t setMaxAcquiredBufferCount(size_t count);
-
-    // To be called before start()
-    status_t setUseAbsoluteTimestamps();
-
-protected:
-
-    // Implementation of the BufferQueue::ConsumerListener interface.  These
-    // calls are used to notify the Surface of asynchronous events in the
-    // BufferQueue.
-    virtual void onFrameAvailable(const BufferItem& item);
-
-    // Used as a hook to BufferQueue::disconnect()
-    // This is called by the client side when it is done
-    // TODO: Currently, this also sets mStopped to true which
-    // is needed for unblocking the encoder which might be
-    // waiting to read more frames. So if on the client side,
-    // the same thread supplies the frames and also calls stop
-    // on the encoder, the client has to call disconnect before
-    // it calls stop.
-    // In the case of the camera,
-    // that need not be required since the thread supplying the
-    // frames is separate than the one calling stop.
-    virtual void onBuffersReleased();
-
-    // SurfaceMediaSource can't handle sideband streams, so this is not expected
-    // to ever be called. Does nothing.
-    virtual void onSidebandStreamChanged();
-
-    static bool isExternalFormat(uint32_t format);
-
-private:
-    // A BufferQueue, represented by these interfaces, is the exchange point
-    // between the producer and this consumer
-    sp<IGraphicBufferProducer> mProducer;
-    sp<IGraphicBufferConsumer> mConsumer;
-
-    struct SlotData {
-        sp<GraphicBuffer> mGraphicBuffer;
-        uint64_t mFrameNumber;
-    };
-
-    // mSlots caches GraphicBuffers and frameNumbers from the buffer queue
-    SlotData mSlots[BufferQueue::NUM_BUFFER_SLOTS];
-
-    // The permenent width and height of SMS buffers
-    int mWidth;
-    int mHeight;
-
-    // mCurrentSlot is the buffer slot index of the buffer that is currently
-    // being used by buffer consumer
-    // (e.g. StageFrightRecorder in the case of SurfaceMediaSource or GLTexture
-    // in the case of Surface).
-    // It is initialized to INVALID_BUFFER_SLOT,
-    // indicating that no buffer slot is currently bound to the texture. Note,
-    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
-    // that no buffer is bound to the texture. A call to setBufferCount will
-    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
-    int mCurrentSlot;
-
-    // mCurrentBuffers is a list of the graphic buffers that are being used by
-    // buffer consumer (i.e. the video encoder). It's possible that these
-    // buffers are not associated with any buffer slots, so we must track them
-    // separately.  Buffers are added to this list in read, and removed from
-    // this list in signalBufferReturned
-    Vector<sp<GraphicBuffer> > mCurrentBuffers;
-
-    size_t mNumPendingBuffers;
-
-#if DEBUG_PENDING_BUFFERS
-    Vector<MediaBuffer *> mPendingBuffers;
-#endif
-
-    // mCurrentTimestamp is the timestamp for the current texture. It
-    // gets set to mLastQueuedTimestamp each time updateTexImage is called.
-    int64_t mCurrentTimestamp;
-
-    // mFrameAvailableListener is the listener object that will be called when a
-    // new frame becomes available. If it is not NULL it will be called from
-    // queueBuffer.
-    sp<FrameAvailableListener> mFrameAvailableListener;
-
-    // mMutex is the mutex used to prevent concurrent access to the member
-    // variables of SurfaceMediaSource objects. It must be locked whenever the
-    // member variables are accessed.
-    mutable Mutex mMutex;
-
-    ////////////////////////// For MediaSource
-    // Set to a default of 30 fps if not specified by the client side
-    int32_t mFrameRate;
-
-    // mStarted is a flag to check if the recording is going on
-    bool mStarted;
-
-    // mNumFramesReceived indicates the number of frames recieved from
-    // the client side
-    int mNumFramesReceived;
-    // mNumFramesEncoded indicates the number of frames passed on to the
-    // encoder
-    int mNumFramesEncoded;
-
-    // mFirstFrameTimestamp is the timestamp of the first received frame.
-    // It is used to offset the output timestamps so recording starts at time 0.
-    int64_t mFirstFrameTimestamp;
-    // mStartTimeNs is the start time passed into the source at start, used to
-    // offset timestamps.
-    int64_t mStartTimeNs;
-
-    size_t mMaxAcquiredBufferCount;
-
-    bool mUseAbsoluteTimestamps;
-
-    // mFrameAvailableCondition condition used to indicate whether there
-    // is a frame available for dequeuing
-    Condition mFrameAvailableCondition;
-
-    Condition mMediaBuffersAvailableCondition;
-
-    // Allocate and return a new MediaBuffer and pass the ANW buffer as metadata into it.
-    void passMetadataBuffer_l(MediaBuffer **buffer, ANativeWindowBuffer *bufferHandle) const;
-
-    // Avoid copying and equating and default constructor
-    DISALLOW_EVIL_CONSTRUCTORS(SurfaceMediaSource);
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_SURFACEMEDIASOURCE_H
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 9b12b2d..bef2db4 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -26,6 +26,7 @@
 #include <binder/IMemory.h>
 #include <binder/MemoryDealer.h>
 #include <cutils/native_handle.h>
+#include <hidlmemory/FrameworkUtils.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -44,10 +45,10 @@
 #include <inttypes.h>
 
 namespace android {
-using hardware::hidl_handle;
-using hardware::hidl_memory;
+using hardware::fromHeap;
 using hardware::hidl_string;
 using hardware::hidl_vec;
+using hardware::HidlMemory;
 using namespace hardware::cas::V1_0;
 using namespace hardware::cas::native::V1_0;
 
@@ -210,6 +211,7 @@
     sp<AMessage> mSampleAesKeyItem;
     sp<IMemory> mMem;
     sp<MemoryDealer> mDealer;
+    sp<HidlMemory> mHidlMemory;
     hardware::cas::native::V1_0::SharedBuffer mDescramblerSrcBuffer;
     sp<ABuffer> mDescrambledBuffer;
     List<SubSampleInfo> mSubSamples;
@@ -852,14 +854,9 @@
         if (heap == NULL) {
             return false;
         }
-        native_handle_t* nativeHandle = native_handle_create(1, 0);
-        if (!nativeHandle) {
-            ALOGE("[stream %d] failed to create native handle", mElementaryPID);
-            return false;
-        }
-        nativeHandle->data[0] = heap->getHeapID();
-        mDescramblerSrcBuffer.heapBase = hidl_memory("ashmem",
-                hidl_handle(nativeHandle), heap->getSize());
+
+        mHidlMemory = fromHeap(heap);
+        mDescramblerSrcBuffer.heapBase = *mHidlMemory;
         mDescramblerSrcBuffer.offset = (uint64_t) offset;
         mDescramblerSrcBuffer.size = (uint64_t) size;
 
diff --git a/media/libstagefright/mpeg2ts/Android.bp b/media/libstagefright/mpeg2ts/Android.bp
index 0b2a48f..fbf1496 100644
--- a/media/libstagefright/mpeg2ts/Android.bp
+++ b/media/libstagefright/mpeg2ts/Android.bp
@@ -33,7 +33,7 @@
     shared_libs: [
         "libcrypto",
         "libmedia",
-        "libhidlmemory",
+        "libhidlallocatorutils",
         "android.hardware.cas.native@1.0",
         "android.hidl.memory@1.0",
     ],
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 1dac171..d0b17e0 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -163,7 +163,7 @@
 }
 
 status_t AnotherPacketSource::read(
-        MediaBuffer **out, const ReadOptions *) {
+        MediaBufferBase **out, const ReadOptions *) {
     *out = NULL;
 
     Mutex::Autolock autoLock(mLock);
@@ -202,7 +202,7 @@
             seg.mMaxDequeTimeUs = timeUs;
         }
 
-        MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+        MediaBufferBase *mediaBuffer = new MediaBuffer(buffer);
         sp<MetaData> bufmeta = mediaBuffer->meta_data();
 
         bufmeta->setInt64(kKeyTime, timeUs);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 3abd573..f4a6acb 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -39,7 +39,7 @@
     virtual sp<MetaData> getFormat();
 
     virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options = NULL);
+            MediaBufferBase **buffer, const ReadOptions *options = NULL);
 
     void clear();
 
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 86c7211..3d9c791 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -658,7 +658,7 @@
                      requestedSeekTimeUs, requestedSeekTimeUs / 1E6);
             }
 
-            MediaBuffer *buffer = NULL;
+            MediaBufferBase *buffer = NULL;
             options.setSeekTo(
                     requestedSeekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC);
 
@@ -679,7 +679,7 @@
         }
 
         status_t err;
-        MediaBuffer *buffer;
+        MediaBufferBase *buffer;
         for (;;) {
             err = codec->read(&buffer, &options);
             options.clearSeekTo();
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 68f8bdd..201a5df 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -219,7 +219,7 @@
     return csd;
 }
 
-sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
+static sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
     AString val;
     CHECK(GetAttribute(params, "config", &val));
 
@@ -257,7 +257,7 @@
 }
 
 // From mpeg4-generic configuration data.
-sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
+static sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
     AString val;
     unsigned long objectType;
     if (GetAttribute(params, "objectType", &val)) {
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 8604b69..4ce8a0c 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -173,7 +173,7 @@
     return OK;
 }
 
-static void StripStartcode(MediaBuffer *buffer) {
+static void StripStartcode(MediaBufferBase *buffer) {
     if (buffer->range_length() < 4) {
         return;
     }
@@ -195,7 +195,7 @@
 
 #if 0
             if (mMode == H264) {
-                MediaBuffer *buffer;
+                MediaBufferBase *buffer;
                 CHECK_EQ(mSource->read(&buffer), (status_t)OK);
 
                 StripStartcode(buffer);
@@ -265,7 +265,7 @@
 }
 
 void ARTPWriter::onRead(const sp<AMessage> &msg) {
-    MediaBuffer *mediaBuf;
+    MediaBufferBase *mediaBuf;
     status_t err = mSource->read(&mediaBuf);
 
     if (err != OK) {
@@ -523,7 +523,7 @@
     ALOGI("%s", sdp.c_str());
 }
 
-void ARTPWriter::makeH264SPropParamSets(MediaBuffer *buffer) {
+void ARTPWriter::makeH264SPropParamSets(MediaBufferBase *buffer) {
     static const char kStartCode[] = "\x00\x00\x00\x01";
 
     const uint8_t *data =
@@ -567,7 +567,7 @@
     send(buffer, true /* isRTCP */);
 }
 
-void ARTPWriter::sendAVCData(MediaBuffer *mediaBuf) {
+void ARTPWriter::sendAVCData(MediaBufferBase *mediaBuf) {
     // 12 bytes RTP header + 2 bytes for the FU-indicator and FU-header.
     CHECK_GE(kMaxPacketSize, 12u + 2u);
 
@@ -663,7 +663,7 @@
     mLastNTPTime = GetNowNTP();
 }
 
-void ARTPWriter::sendH263Data(MediaBuffer *mediaBuf) {
+void ARTPWriter::sendH263Data(MediaBufferBase *mediaBuf) {
     CHECK_GE(kMaxPacketSize, 12u + 2u);
 
     int64_t timeUs;
@@ -741,7 +741,7 @@
     return frameSize;
 }
 
-void ARTPWriter::sendAMRData(MediaBuffer *mediaBuf) {
+void ARTPWriter::sendAMRData(MediaBufferBase *mediaBuf) {
     const uint8_t *mediaData =
         (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
 
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index 92a64f2..2f13486 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -110,13 +110,13 @@
     void addSR(const sp<ABuffer> &buffer);
     void addSDES(const sp<ABuffer> &buffer);
 
-    void makeH264SPropParamSets(MediaBuffer *buffer);
+    void makeH264SPropParamSets(MediaBufferBase *buffer);
     void dumpSessionDesc();
 
     void sendBye();
-    void sendAVCData(MediaBuffer *mediaBuf);
-    void sendH263Data(MediaBuffer *mediaBuf);
-    void sendAMRData(MediaBuffer *mediaBuf);
+    void sendAVCData(MediaBufferBase *mediaBuf);
+    void sendH263Data(MediaBufferBase *mediaBuf);
+    void sendAMRData(MediaBufferBase *mediaBuf);
 
     void send(const sp<ABuffer> &buffer, bool isRTCP);
 
diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp
index e67a949..be10fdc 100644
--- a/media/libstagefright/tests/Android.bp
+++ b/media/libstagefright/tests/Android.bp
@@ -1,46 +1,6 @@
 // Build the unit tests.
 
 cc_test {
-    name: "SurfaceMediaSource_test",
-
-    srcs: [
-        "SurfaceMediaSource_test.cpp",
-        "DummyRecorder.cpp",
-    ],
-
-    shared_libs: [
-        "libEGL",
-        "libGLESv2",
-        "libbinder",
-        "libcutils",
-        "libgui",
-        "libmedia",
-        "libmediaextractor",
-        "libstagefright",
-        "libstagefright_foundation",
-        "libstagefright_omx",
-        "libsync",
-        "libui",
-        "libutils",
-        "liblog",
-    ],
-
-    include_dirs: [
-        "frameworks/av/media/libstagefright",
-        "frameworks/av/media/libstagefright/include",
-        "frameworks/native/include/media/openmax",
-        "frameworks/native/include/media/hardware",
-    ],
-
-    cflags: [
-        "-Werror",
-        "-Wall",
-    ],
-
-    compile_multilib: "32",
-}
-
-cc_test {
     name: "MediaCodecListOverrides_test",
 
     srcs: ["MediaCodecListOverrides_test.cpp"],
diff --git a/media/libstagefright/tests/DummyRecorder.cpp b/media/libstagefright/tests/DummyRecorder.cpp
deleted file mode 100644
index 4f560cb..0000000
--- a/media/libstagefright/tests/DummyRecorder.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2011 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 "DummyRecorder"
-// #define LOG_NDEBUG 0
-
-#include <media/MediaSource.h>
-#include <media/stagefright/MediaBuffer.h>
-#include "DummyRecorder.h"
-
-#include <utils/Log.h>
-
-namespace android {
-
-// static
-void *DummyRecorder::threadWrapper(void *pthis) {
-    ALOGV("ThreadWrapper: %p", pthis);
-    DummyRecorder *writer = static_cast<DummyRecorder *>(pthis);
-    writer->readFromSource();
-    return NULL;
-}
-
-
-status_t DummyRecorder::start() {
-    ALOGV("Start");
-    mStarted = true;
-
-    mSource->start();
-
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-    int err = pthread_create(&mThread, &attr, threadWrapper, this);
-    pthread_attr_destroy(&attr);
-
-    if (err) {
-        ALOGE("Error creating thread!");
-        return -ENODEV;
-    }
-    return OK;
-}
-
-
-status_t DummyRecorder::stop() {
-    ALOGV("Stop");
-    mStarted = false;
-
-    mSource->stop();
-    void *dummy;
-    pthread_join(mThread, &dummy);
-    status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
-
-    ALOGV("Ending the reading thread");
-    return err;
-}
-
-// pretend to read the source buffers
-void DummyRecorder::readFromSource() {
-    ALOGV("ReadFromSource");
-    if (!mStarted) {
-        return;
-    }
-
-    status_t err = OK;
-    MediaBuffer *buffer;
-    ALOGV("A fake writer accessing the frames");
-    while (mStarted && (err = mSource->read(&buffer)) == OK){
-        // if not getting a valid buffer from source, then exit
-        if (buffer == NULL) {
-            return;
-        }
-        buffer->release();
-        buffer = NULL;
-    }
-}
-
-
-} // end of namespace android
diff --git a/media/libstagefright/tests/DummyRecorder.h b/media/libstagefright/tests/DummyRecorder.h
deleted file mode 100644
index 0759777..0000000
--- a/media/libstagefright/tests/DummyRecorder.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011 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 DUMMY_RECORDER_H_
-#define DUMMY_RECORDER_H_
-
-#include <pthread.h>
-#include <utils/String8.h>
-#include <media/stagefright/foundation/ABase.h>
-
-
-namespace android {
-
-struct MediaSource;
-class MediaBuffer;
-
-class DummyRecorder {
-    public:
-    // The media source from which this will receive frames
-    sp<MediaSource> mSource;
-    bool mStarted;
-    pthread_t mThread;
-
-    status_t start();
-    status_t stop();
-
-    // actual entry point for the thread
-    void readFromSource();
-
-    // static function to wrap the actual thread entry point
-    static void *threadWrapper(void *pthis);
-
-    explicit DummyRecorder(const sp<MediaSource> &source) : mSource(source)
-                                                    , mStarted(false) {}
-    ~DummyRecorder( ) {}
-
-    private:
-
-    DISALLOW_EVIL_CONSTRUCTORS(DummyRecorder);
-};
-
-} // end of namespace android
-#endif
-
-
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
deleted file mode 100644
index 051108f..0000000
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ /dev/null
@@ -1,944 +0,0 @@
-/*
- * Copyright (C) 2011 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 "SurfaceMediaSource_test"
-
-#include <gtest/gtest.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-#include <utils/Errors.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <GLES2/gl2.h>
-
-#include <media/stagefright/SurfaceMediaSource.h>
-#include <media/mediarecorder.h>
-
-#include <ui/GraphicBuffer.h>
-#include <gui/Surface.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-
-#include <binder/ProcessState.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <OMX_Component.h>
-
-#include "DummyRecorder.h"
-
-
-namespace android {
-
-class GLTest : public ::testing::Test {
-protected:
-
-    GLTest():
-            mEglDisplay(EGL_NO_DISPLAY),
-            mEglSurface(EGL_NO_SURFACE),
-            mEglContext(EGL_NO_CONTEXT) {
-    }
-
-    virtual void SetUp() {
-        ALOGV("GLTest::SetUp()");
-        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
-
-        EGLint majorVersion;
-        EGLint minorVersion;
-        EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        RecordProperty("EglVersionMajor", majorVersion);
-        RecordProperty("EglVersionMajor", minorVersion);
-
-        EGLint numConfigs = 0;
-        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig,
-                1, &numConfigs));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
-        if (displaySecsEnv != NULL) {
-            mDisplaySecs = atoi(displaySecsEnv);
-            if (mDisplaySecs < 0) {
-                mDisplaySecs = 0;
-            }
-        } else {
-            mDisplaySecs = 0;
-        }
-
-        if (mDisplaySecs > 0) {
-            mComposerClient = new SurfaceComposerClient;
-            ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
-            mSurfaceControl = mComposerClient->createSurface(
-                    String8("Test Surface"),
-                    getSurfaceWidth(), getSurfaceHeight(),
-                    PIXEL_FORMAT_RGB_888, 0);
-
-            ASSERT_TRUE(mSurfaceControl != NULL);
-            ASSERT_TRUE(mSurfaceControl->isValid());
-
-            SurfaceComposerClient::Transaction{}
-                    .setLayer(mSurfaceControl, 0x7FFFFFFF)
-                    .show(mSurfaceControl)
-                    .apply();
-
-            sp<ANativeWindow> window = mSurfaceControl->getSurface();
-            mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-                    window.get(), NULL);
-        } else {
-            ALOGV("No actual display. Choosing EGLSurface based on SurfaceMediaSource");
-            sp<IGraphicBufferProducer> sms = (new SurfaceMediaSource(
-                    getSurfaceWidth(), getSurfaceHeight()))->getProducer();
-            sp<Surface> stc = new Surface(sms);
-            sp<ANativeWindow> window = stc;
-
-            mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-                    window.get(), NULL);
-        }
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
-
-        mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
-                getContextAttribs());
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
-
-        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-                mEglContext));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        EGLint w, h;
-        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &w));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        EXPECT_TRUE(eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &h));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        RecordProperty("EglSurfaceWidth", w);
-        RecordProperty("EglSurfaceHeight", h);
-
-        glViewport(0, 0, w, h);
-        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-    }
-
-    virtual void TearDown() {
-        // Display the result
-        if (mDisplaySecs > 0 && mEglSurface != EGL_NO_SURFACE) {
-            eglSwapBuffers(mEglDisplay, mEglSurface);
-            sleep(mDisplaySecs);
-        }
-
-        if (mComposerClient != NULL) {
-            mComposerClient->dispose();
-        }
-        if (mEglContext != EGL_NO_CONTEXT) {
-            eglDestroyContext(mEglDisplay, mEglContext);
-        }
-        if (mEglSurface != EGL_NO_SURFACE) {
-            eglDestroySurface(mEglDisplay, mEglSurface);
-        }
-        if (mEglDisplay != EGL_NO_DISPLAY) {
-            eglTerminate(mEglDisplay);
-        }
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    }
-
-    virtual EGLint const* getConfigAttribs() {
-        ALOGV("GLTest getConfigAttribs");
-        static EGLint sDefaultConfigAttribs[] = {
-            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-            EGL_RED_SIZE, 8,
-            EGL_GREEN_SIZE, 8,
-            EGL_BLUE_SIZE, 8,
-            EGL_ALPHA_SIZE, 8,
-            EGL_DEPTH_SIZE, 16,
-            EGL_STENCIL_SIZE, 8,
-            EGL_NONE };
-
-        return sDefaultConfigAttribs;
-    }
-
-    virtual EGLint const* getContextAttribs() {
-        static EGLint sDefaultContextAttribs[] = {
-            EGL_CONTEXT_CLIENT_VERSION, 2,
-            EGL_NONE };
-
-        return sDefaultContextAttribs;
-    }
-
-    virtual EGLint getSurfaceWidth() {
-        return 512;
-    }
-
-    virtual EGLint getSurfaceHeight() {
-        return 512;
-    }
-
-    void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
-        GLuint shader = glCreateShader(shaderType);
-        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-        if (shader) {
-            glShaderSource(shader, 1, &pSource, NULL);
-            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-            glCompileShader(shader);
-            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-            GLint compiled = 0;
-            glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
-            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-            if (!compiled) {
-                GLint infoLen = 0;
-                glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
-                ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-                if (infoLen) {
-                    char* buf = (char*) malloc(infoLen);
-                    if (buf) {
-                        glGetShaderInfoLog(shader, infoLen, NULL, buf);
-                        printf("Shader compile log:\n%s\n", buf);
-                        free(buf);
-                        FAIL();
-                    }
-                } else {
-                    char* buf = (char*) malloc(0x1000);
-                    if (buf) {
-                        glGetShaderInfoLog(shader, 0x1000, NULL, buf);
-                        printf("Shader compile log:\n%s\n", buf);
-                        free(buf);
-                        FAIL();
-                    }
-                }
-                glDeleteShader(shader);
-                shader = 0;
-            }
-        }
-        ASSERT_TRUE(shader != 0);
-        *outShader = shader;
-    }
-
-    void createProgram(const char* pVertexSource, const char* pFragmentSource,
-            GLuint* outPgm) {
-        GLuint vertexShader, fragmentShader;
-        {
-            SCOPED_TRACE("compiling vertex shader");
-            loadShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
-            if (HasFatalFailure()) {
-                return;
-            }
-        }
-        {
-            SCOPED_TRACE("compiling fragment shader");
-            loadShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
-            if (HasFatalFailure()) {
-                return;
-            }
-        }
-
-        GLuint program = glCreateProgram();
-        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-        if (program) {
-            glAttachShader(program, vertexShader);
-            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-            glAttachShader(program, fragmentShader);
-            ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-            glLinkProgram(program);
-            GLint linkStatus = GL_FALSE;
-            glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
-            if (linkStatus != GL_TRUE) {
-                GLint bufLength = 0;
-                glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
-                if (bufLength) {
-                    char* buf = (char*) malloc(bufLength);
-                    if (buf) {
-                        glGetProgramInfoLog(program, bufLength, NULL, buf);
-                        printf("Program link log:\n%s\n", buf);
-                        free(buf);
-                        FAIL();
-                    }
-                }
-                glDeleteProgram(program);
-                program = 0;
-            }
-        }
-        glDeleteShader(vertexShader);
-        glDeleteShader(fragmentShader);
-        ASSERT_TRUE(program != 0);
-        *outPgm = program;
-    }
-
-    static int abs(int value) {
-        return value > 0 ? value : -value;
-    }
-
-    ::testing::AssertionResult checkPixel(int x, int y, int r,
-            int g, int b, int a, int tolerance=2) {
-        GLubyte pixel[4];
-        String8 msg;
-        glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
-        GLenum err = glGetError();
-        if (err != GL_NO_ERROR) {
-            msg += String8::format("error reading pixel: %#x", err);
-            while ((err = glGetError()) != GL_NO_ERROR) {
-                msg += String8::format(", %#x", err);
-            }
-            fprintf(stderr, "pixel check failure: %s\n", msg.string());
-            return ::testing::AssertionFailure(
-                    ::testing::Message(msg.string()));
-        }
-        if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
-            msg += String8::format("r(%d isn't %d)", pixel[0], r);
-        }
-        if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
-            if (!msg.isEmpty()) {
-                msg += " ";
-            }
-            msg += String8::format("g(%d isn't %d)", pixel[1], g);
-        }
-        if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
-            if (!msg.isEmpty()) {
-                msg += " ";
-            }
-            msg += String8::format("b(%d isn't %d)", pixel[2], b);
-        }
-        if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
-            if (!msg.isEmpty()) {
-                msg += " ";
-            }
-            msg += String8::format("a(%d isn't %d)", pixel[3], a);
-        }
-        if (!msg.isEmpty()) {
-            fprintf(stderr, "pixel check failure: %s\n", msg.string());
-            return ::testing::AssertionFailure(
-                    ::testing::Message(msg.string()));
-        } else {
-            return ::testing::AssertionSuccess();
-        }
-    }
-
-    int mDisplaySecs;
-    sp<SurfaceComposerClient> mComposerClient;
-    sp<SurfaceControl> mSurfaceControl;
-
-    EGLDisplay mEglDisplay;
-    EGLSurface mEglSurface;
-    EGLContext mEglContext;
-    EGLConfig  mGlConfig;
-};
-
-///////////////////////////////////////////////////////////////////////
-//    Class for  the NON-GL tests
-///////////////////////////////////////////////////////////////////////
-class SurfaceMediaSourceTest : public ::testing::Test {
-public:
-
-    SurfaceMediaSourceTest( ): mYuvTexWidth(176), mYuvTexHeight(144) { }
-    void oneBufferPass(int width, int height );
-    void oneBufferPassNoFill(int width, int height );
-    static void fillYV12Buffer(uint8_t* buf, int w, int h, int stride) ;
-    static void fillYV12BufferRect(uint8_t* buf, int w, int h,
-                        int stride, const android_native_rect_t& rect) ;
-protected:
-
-    virtual void SetUp() {
-        android::ProcessState::self()->startThreadPool();
-        mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
-        mSTC = new Surface(mSMS->getProducer());
-        mANW = mSTC;
-    }
-
-    virtual void TearDown() {
-        mSMS.clear();
-        mSTC.clear();
-        mANW.clear();
-    }
-
-    const int mYuvTexWidth;
-    const int mYuvTexHeight;
-
-    sp<SurfaceMediaSource> mSMS;
-    sp<Surface> mSTC;
-    sp<ANativeWindow> mANW;
-};
-
-///////////////////////////////////////////////////////////////////////
-//    Class for  the GL tests
-///////////////////////////////////////////////////////////////////////
-class SurfaceMediaSourceGLTest : public GLTest {
-public:
-
-    SurfaceMediaSourceGLTest( ): mYuvTexWidth(176), mYuvTexHeight(144) { }
-    virtual EGLint const* getConfigAttribs();
-    void oneBufferPassGL(int num = 0);
-    static sp<MediaRecorder> setUpMediaRecorder(int fileDescriptor, int videoSource,
-        int outputFormat, int videoEncoder, int width, int height, int fps);
-protected:
-
-    virtual void SetUp() {
-        ALOGV("SMS-GLTest::SetUp()");
-        android::ProcessState::self()->startThreadPool();
-        mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
-        mSTC = new Surface(mSMS->getProducer());
-        mANW = mSTC;
-
-        // Doing the setup related to the GL Side
-        GLTest::SetUp();
-    }
-
-    virtual void TearDown() {
-        mSMS.clear();
-        mSTC.clear();
-        mANW.clear();
-        GLTest::TearDown();
-    }
-
-    void setUpEGLSurfaceFromMediaRecorder(sp<MediaRecorder>& mr);
-
-    const int mYuvTexWidth;
-    const int mYuvTexHeight;
-
-    sp<SurfaceMediaSource> mSMS;
-    sp<Surface> mSTC;
-    sp<ANativeWindow> mANW;
-};
-
-/////////////////////////////////////////////////////////////////////
-// Methods in SurfaceMediaSourceGLTest
-/////////////////////////////////////////////////////////////////////
-EGLint const* SurfaceMediaSourceGLTest::getConfigAttribs() {
-        ALOGV("SurfaceMediaSourceGLTest getConfigAttribs");
-    static EGLint sDefaultConfigAttribs[] = {
-        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-        EGL_RED_SIZE, 8,
-        EGL_GREEN_SIZE, 8,
-        EGL_BLUE_SIZE, 8,
-        EGL_RECORDABLE_ANDROID, EGL_TRUE,
-        EGL_NONE };
-
-    return sDefaultConfigAttribs;
-}
-
-// One pass of dequeuing and queuing a GLBuffer
-void SurfaceMediaSourceGLTest::oneBufferPassGL(int num) {
-    int d = num % 50;
-    float f = 0.2f; // 0.1f * d;
-
-    glClearColor(0, 0.3, 0, 0.6);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glEnable(GL_SCISSOR_TEST);
-    glScissor(4 + d, 4 + d, 4, 4);
-    glClearColor(1.0 - f, f, f, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glScissor(24 + d, 48 + d, 4, 4);
-    glClearColor(f, 1.0 - f, f, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glScissor(37 + d, 17 + d, 4, 4);
-    glClearColor(f, f, 1.0 - f, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    // The following call dequeues and queues the buffer
-    eglSwapBuffers(mEglDisplay, mEglSurface);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    glDisable(GL_SCISSOR_TEST);
-}
-
-// Set up the MediaRecorder which runs in the same process as mediaserver
-sp<MediaRecorder> SurfaceMediaSourceGLTest::setUpMediaRecorder(int fd, int videoSource,
-        int outputFormat, int videoEncoder, int width, int height, int fps) {
-    sp<MediaRecorder> mr = new MediaRecorder(String16());
-    mr->setVideoSource(videoSource);
-    mr->setOutputFormat(outputFormat);
-    mr->setVideoEncoder(videoEncoder);
-    mr->setOutputFile(fd);
-    mr->setVideoSize(width, height);
-    mr->setVideoFrameRate(fps);
-    mr->prepare();
-    ALOGV("Starting MediaRecorder...");
-    CHECK_EQ((status_t)OK, mr->start());
-    return mr;
-}
-
-// query the mediarecorder for a surfacemeidasource and create an egl surface with that
-void SurfaceMediaSourceGLTest::setUpEGLSurfaceFromMediaRecorder(sp<MediaRecorder>& mr) {
-    sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer();
-    mSTC = new Surface(iST);
-    mANW = mSTC;
-
-    if (mEglSurface != EGL_NO_SURFACE) {
-        EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
-        mEglSurface = EGL_NO_SURFACE;
-    }
-    mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-                                mANW.get(), NULL);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-            mEglContext));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-}
-
-
-/////////////////////////////////////////////////////////////////////
-// Methods in SurfaceMediaSourceTest
-/////////////////////////////////////////////////////////////////////
-
-// One pass of dequeuing and queuing the buffer. Fill it in with
-// cpu YV12 buffer
-void SurfaceMediaSourceTest::oneBufferPass(int width, int height ) {
-    ANativeWindowBuffer* anb;
-    ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
-    ASSERT_TRUE(anb != NULL);
-
-
-    // Fill the buffer with the a checkerboard pattern
-    uint8_t* img = NULL;
-    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
-    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
-    SurfaceMediaSourceTest::fillYV12Buffer(img, width, height, buf->getStride());
-    buf->unlock();
-
-    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
-            -1));
-}
-
-// Dequeuing and queuing the buffer without really filling it in.
-void SurfaceMediaSourceTest::oneBufferPassNoFill(
-        int /* width */, int /* height  */) {
-    ANativeWindowBuffer* anb;
-    ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
-    ASSERT_TRUE(anb != NULL);
-
-    // We do not fill the buffer in. Just queue it back.
-    sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
-    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
-            -1));
-}
-
-// Fill a YV12 buffer with a multi-colored checkerboard pattern
-void SurfaceMediaSourceTest::fillYV12Buffer(uint8_t* buf, int w, int h, int stride) {
-    const int blockWidth = w > 16 ? w / 16 : 1;
-    const int blockHeight = h > 16 ? h / 16 : 1;
-    const int yuvTexOffsetY = 0;
-    int yuvTexStrideY = stride;
-    int yuvTexOffsetV = yuvTexStrideY * h;
-    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
-    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
-    int yuvTexStrideU = yuvTexStrideV;
-    for (int x = 0; x < w; x++) {
-        for (int y = 0; y < h; y++) {
-            int parityX = (x / blockWidth) & 1;
-            int parityY = (y / blockHeight) & 1;
-            unsigned char intensity = (parityX ^ parityY) ? 63 : 191;
-            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
-            if (x < w / 2 && y < h / 2) {
-                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = intensity;
-                if (x * 2 < w / 2 && y * 2 < h / 2) {
-                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 0] =
-                    buf[yuvTexOffsetV + (y*2 * yuvTexStrideV) + x*2 + 1] =
-                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 0] =
-                    buf[yuvTexOffsetV + ((y*2+1) * yuvTexStrideV) + x*2 + 1] =
-                        intensity;
-                }
-            }
-        }
-    }
-}
-
-// Fill a YV12 buffer with red outside a given rectangle and green inside it.
-void SurfaceMediaSourceTest::fillYV12BufferRect(uint8_t* buf, int w,
-                  int h, int stride, const android_native_rect_t& rect) {
-    const int yuvTexOffsetY = 0;
-    int yuvTexStrideY = stride;
-    int yuvTexOffsetV = yuvTexStrideY * h;
-    int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
-    int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * h/2;
-    int yuvTexStrideU = yuvTexStrideV;
-    for (int x = 0; x < w; x++) {
-        for (int y = 0; y < h; y++) {
-            bool inside = rect.left <= x && x < rect.right &&
-                    rect.top <= y && y < rect.bottom;
-            buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = inside ? 240 : 64;
-            if (x < w / 2 && y < h / 2) {
-                bool inside = rect.left <= 2*x && 2*x < rect.right &&
-                        rect.top <= 2*y && 2*y < rect.bottom;
-                buf[yuvTexOffsetU + (y * yuvTexStrideU) + x] = 16;
-                buf[yuvTexOffsetV + (y * yuvTexStrideV) + x] =
-                                                inside ? 16 : 255;
-            }
-        }
-    }
-}  ///////// End of class SurfaceMediaSourceTest
-
-///////////////////////////////////////////////////////////////////
-// Class to imitate the recording     /////////////////////////////
-// ////////////////////////////////////////////////////////////////
-struct SimpleDummyRecorder {
-        sp<MediaSource> mSource;
-
-        explicit SimpleDummyRecorder
-                (const sp<MediaSource> &source): mSource(source) {}
-
-        status_t start() { return mSource->start();}
-        status_t stop()  { return mSource->stop();}
-
-        // fakes reading from a media source
-        status_t readFromSource() {
-            MediaBuffer *buffer;
-            status_t err = mSource->read(&buffer);
-            if (err != OK) {
-                return err;
-            }
-            buffer->release();
-            buffer = NULL;
-            return OK;
-        }
-};
-///////////////////////////////////////////////////////////////////
-//           TESTS
-// SurfaceMediaSourceTest class contains tests that fill the buffers
-// using the cpu calls
-// SurfaceMediaSourceGLTest class contains tests that fill the buffers
-// using the GL calls.
-// TODO: None of the tests actually verify the encoded images.. so at this point,
-// these are mostly functionality tests + visual inspection
-//////////////////////////////////////////////////////////////////////
-
-// Just pass one buffer from the native_window to the SurfaceMediaSource
-// Dummy Encoder
-static int testId = 1;
-TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotOneBufferPass) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("Testing OneBufferPass ******************************");
-
-    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
-            HAL_PIXEL_FORMAT_YV12));
-    oneBufferPass(mYuvTexWidth, mYuvTexHeight);
-}
-
-// Pass the buffer with the wrong height and weight and should not be accepted
-// Dummy Encoder
-TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotWrongSizeBufferPass) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("Testing Wrong size BufferPass ******************************");
-
-    // setting the client side buffer size different than the server size
-    ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
-             10, 10));
-    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
-            HAL_PIXEL_FORMAT_YV12));
-
-    ANativeWindowBuffer* anb;
-
-    // Note: make sure we get an ERROR back when dequeuing!
-    ASSERT_NE(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
-}
-
-// pass multiple buffers from the native_window the SurfaceMediaSource
-// Dummy Encoder
-TEST_F(SurfaceMediaSourceTest,  DISABLED_DummyEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("Testing MultiBufferPass, Dummy Recorder *********************");
-    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
-            HAL_PIXEL_FORMAT_YV12));
-
-    SimpleDummyRecorder writer(mSMS);
-    writer.start();
-
-    int32_t nFramesCount = 0;
-    while (nFramesCount < 300) {
-        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
-
-        ASSERT_EQ(NO_ERROR, writer.readFromSource());
-
-        nFramesCount++;
-    }
-    writer.stop();
-}
-
-// Delayed pass of multiple buffers from the native_window the SurfaceMediaSource
-// Dummy Encoder
-TEST_F(SurfaceMediaSourceTest,  DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************");
-
-    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
-            HAL_PIXEL_FORMAT_YV12));
-
-    SimpleDummyRecorder writer(mSMS);
-    writer.start();
-
-    int32_t nFramesCount = 1;
-    const int FRAMES_LAG = SurfaceMediaSource::MIN_UNDEQUEUED_BUFFERS;
-
-    while (nFramesCount <= 300) {
-        ALOGV("Frame: %d", nFramesCount);
-        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
-        // Forcing the writer to lag behind a few frames
-        if (nFramesCount > FRAMES_LAG) {
-            ASSERT_EQ(NO_ERROR, writer.readFromSource());
-        }
-        nFramesCount++;
-    }
-    writer.stop();
-}
-
-// pass multiple buffers from the native_window the SurfaceMediaSource
-// A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer
-TEST_F(SurfaceMediaSourceTest, DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********");
-    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
-            HAL_PIXEL_FORMAT_YV12));
-
-    DummyRecorder writer(mSMS);
-    writer.start();
-
-    int32_t nFramesCount = 0;
-    while (nFramesCount <= 300) {
-        ALOGV("Frame: %d", nFramesCount);
-        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
-
-        nFramesCount++;
-    }
-    writer.stop();
-}
-
-// Test to examine actual encoding using mediarecorder
-// We use the mediaserver to create a mediarecorder and send
-// it back to us. So SurfaceMediaSource lives in the same process
-// as the mediaserver.
-// Very close to the actual camera, except that the
-// buffers are filled and queueud by the CPU instead of GL.
-TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaServer) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("************** Testing the whole pipeline with actual MediaRecorder ***********");
-    ALOGV("************** SurfaceMediaSource is same process as mediaserver    ***********");
-
-    const char *fileName = "/sdcard/outputSurfEncMSource.mp4";
-    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
-    if (fd < 0) {
-        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
-    }
-    CHECK(fd >= 0);
-
-    sp<MediaRecorder> mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd,
-            VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264,
-            mYuvTexWidth, mYuvTexHeight, 30);
-    // get the reference to the surfacemediasource living in
-    // mediaserver that is created by stagefrightrecorder
-    sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer();
-    mSTC = new Surface(iST);
-    mANW = mSTC;
-    ASSERT_EQ(NO_ERROR, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU));
-    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
-                                                HAL_PIXEL_FORMAT_YV12));
-
-    int32_t nFramesCount = 0;
-    while (nFramesCount <= 300) {
-        oneBufferPassNoFill(mYuvTexWidth, mYuvTexHeight);
-        nFramesCount++;
-        ALOGV("framesCount = %d", nFramesCount);
-    }
-
-    ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU));
-    ALOGV("Stopping MediaRecorder...");
-    CHECK_EQ((status_t)OK, mr->stop());
-    mr.clear();
-    close(fd);
-}
-
-//////////////////////////////////////////////////////////////////////
-// GL tests
-/////////////////////////////////////////////////////////////////////
-
-// Test to examine whether we can choose the Recordable Android GLConfig
-// DummyRecorder used- no real encoding here
-TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("Verify creating a surface w/ right config + dummy writer*********");
-
-    mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
-    mSTC = new Surface(mSMS->getProducer());
-    mANW = mSTC;
-
-    DummyRecorder writer(mSMS);
-    writer.start();
-
-    if (mEglSurface != EGL_NO_SURFACE) {
-        EXPECT_TRUE(eglDestroySurface(mEglDisplay, mEglSurface));
-        mEglSurface = EGL_NO_SURFACE;
-    }
-
-    mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-                                mANW.get(), NULL);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, mEglSurface) ;
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-            mEglContext));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    int32_t nFramesCount = 0;
-    while (nFramesCount <= 300) {
-        oneBufferPassGL();
-        nFramesCount++;
-        ALOGV("framesCount = %d", nFramesCount);
-    }
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-            EGL_NO_CONTEXT));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    eglDestroySurface(mEglDisplay, mEglSurface);
-    mEglSurface = EGL_NO_SURFACE;
-
-    writer.stop();
-}
-// Test to examine whether we can render GL buffers in to the surface
-// created with the native window handle
-TEST_F(SurfaceMediaSourceGLTest, RenderingToRecordableEGLSurfaceWorks) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("RenderingToRecordableEGLSurfaceWorks *********************");
-    // Do the producer side of things
-    glClearColor(0.6, 0.6, 0.6, 0.6);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glEnable(GL_SCISSOR_TEST);
-    glScissor(4, 4, 4, 4);
-    glClearColor(1.0, 0.0, 0.0, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glScissor(24, 48, 4, 4);
-    glClearColor(0.0, 1.0, 0.0, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glScissor(37, 17, 4, 4);
-    glClearColor(0.0, 0.0, 1.0, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    EXPECT_TRUE(checkPixel( 0,  0, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(63,  0, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
-
-    EXPECT_TRUE(checkPixel( 4,  7, 255,   0,   0, 255));
-    EXPECT_TRUE(checkPixel(25, 51,   0, 255,   0, 255));
-    EXPECT_TRUE(checkPixel(40, 19,   0,   0, 255, 255));
-    EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(13,  8, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(46,  3, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
-}
-
-// Test to examine the actual encoding with GL buffers
-// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource
-// The same pattern is rendered every frame
-TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaSameImageEachBufNpotWrite) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("************** Testing the whole pipeline with actual Recorder ***********");
-    ALOGV("************** GL Filling the buffers ***********");
-    // Note: No need to set the colorformat for the buffers. The colorformat is
-    // in the GRAlloc buffers itself.
-
-    const char *fileName = "/sdcard/outputSurfEncMSourceGL.mp4";
-    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
-    if (fd < 0) {
-        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
-    }
-    CHECK(fd >= 0);
-
-    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE,
-            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
-
-    // get the reference to the surfacemediasource living in
-    // mediaserver that is created by stagefrightrecorder
-    setUpEGLSurfaceFromMediaRecorder(mr);
-
-    int32_t nFramesCount = 0;
-    while (nFramesCount <= 300) {
-        oneBufferPassGL();
-        nFramesCount++;
-        ALOGV("framesCount = %d", nFramesCount);
-    }
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-            EGL_NO_CONTEXT));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    eglDestroySurface(mEglDisplay, mEglSurface);
-    mEglSurface = EGL_NO_SURFACE;
-
-    ALOGV("Stopping MediaRecorder...");
-    CHECK_EQ((status_t)OK, mr->stop());
-    mr.clear();
-    close(fd);
-}
-
-// Test to examine the actual encoding from the GL Buffers
-// Actual encoder, Actual GL Buffers Filled SurfaceMediaSource
-// A different pattern is rendered every frame
-TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaDiffImageEachBufNpotWrite) {
-    ALOGV("Test # %d", testId++);
-    ALOGV("************** Testing the whole pipeline with actual Recorder ***********");
-    ALOGV("************** Diff GL Filling the buffers ***********");
-    // Note: No need to set the colorformat for the buffers. The colorformat is
-    // in the GRAlloc buffers itself.
-
-    const char *fileName = "/sdcard/outputSurfEncMSourceGLDiff.mp4";
-    int fd = open(fileName, O_RDWR | O_CREAT, 0744);
-    if (fd < 0) {
-        ALOGE("ERROR: Could not open the the file %s, fd = %d !!", fileName, fd);
-    }
-    CHECK(fd >= 0);
-
-    sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE,
-            OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30);
-
-    // get the reference to the surfacemediasource living in
-    // mediaserver that is created by stagefrightrecorder
-    setUpEGLSurfaceFromMediaRecorder(mr);
-
-    int32_t nFramesCount = 0;
-    while (nFramesCount <= 300) {
-        oneBufferPassGL(nFramesCount);
-        nFramesCount++;
-        ALOGV("framesCount = %d", nFramesCount);
-    }
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-            EGL_NO_CONTEXT));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    eglDestroySurface(mEglDisplay, mEglSurface);
-    mEglSurface = EGL_NO_SURFACE;
-
-    ALOGV("Stopping MediaRecorder...");
-    CHECK_EQ((status_t)OK, mr->stop());
-    mr.clear();
-    close(fd);
-}
-} // namespace android
diff --git a/media/libstagefright/webm/WebmFrame.cpp b/media/libstagefright/webm/WebmFrame.cpp
index e5134ed..4b0d47c 100644
--- a/media/libstagefright/webm/WebmFrame.cpp
+++ b/media/libstagefright/webm/WebmFrame.cpp
@@ -27,7 +27,7 @@
 using namespace webm;
 
 namespace {
-sp<ABuffer> toABuffer(MediaBuffer *mbuf) {
+sp<ABuffer> toABuffer(MediaBufferBase *mbuf) {
     sp<ABuffer> abuf = new ABuffer(mbuf->range_length());
     memcpy(abuf->data(), (uint8_t*) mbuf->data() + mbuf->range_offset(), mbuf->range_length());
     return abuf;
@@ -46,7 +46,7 @@
       mEos(true) {
 }
 
-WebmFrame::WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *mbuf)
+WebmFrame::WebmFrame(int type, bool key, uint64_t absTimecode, MediaBufferBase *mbuf)
     : mType(type),
       mKey(key),
       mAbsTimecode(absTimecode),
diff --git a/media/libstagefright/webm/WebmFrame.h b/media/libstagefright/webm/WebmFrame.h
index 4f0b055..a410a87 100644
--- a/media/libstagefright/webm/WebmFrame.h
+++ b/media/libstagefright/webm/WebmFrame.h
@@ -30,7 +30,7 @@
     const bool mEos;
 
     WebmFrame();
-    WebmFrame(int type, bool key, uint64_t absTimecode, MediaBuffer *buf);
+    WebmFrame(int type, bool key, uint64_t absTimecode, MediaBufferBase *buf);
     ~WebmFrame() {}
 
     sp<WebmElement> SimpleBlock(uint64_t baseTimecode) const;
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 420890b..0d4c699 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -337,7 +337,7 @@
     mStartTimeUs = kUninitialized;
 
     status_t err = OK;
-    MediaBuffer *buffer;
+    MediaBufferBase *buffer;
     while (!mDone && (err = mSource->read(&buffer, NULL)) == OK) {
         if (buffer->range_length() == 0) {
             buffer->release();
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index f190f80..9d00e5e 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -44,7 +44,15 @@
 };
 
 NdkDataSource::NdkDataSource(AMediaDataSource *dataSource)
-    : mDataSource(dataSource) {
+    : mDataSource(AMediaDataSource_new()) {
+      AMediaDataSource_setReadAt(mDataSource, dataSource->readAt);
+      AMediaDataSource_setGetSize(mDataSource, dataSource->getSize);
+      AMediaDataSource_setClose(mDataSource, dataSource->close);
+      AMediaDataSource_setUserdata(mDataSource, dataSource->userdata);
+}
+
+NdkDataSource::~NdkDataSource() {
+    AMediaDataSource_delete(mDataSource);
 }
 
 status_t NdkDataSource::initCheck() const {
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index 65ddd2a..ea9c865 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -49,6 +49,9 @@
     virtual String8 getMIMEType() const;
     virtual void close();
 
+protected:
+    virtual ~NdkDataSource();
+
 private:
 
     Mutex mLock;
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
index 7c7718e..22eea25 100644
--- a/packages/MediaComponents/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -16,6 +16,12 @@
 
 LOCAL_PATH := $(call my-dir)
 
+ifneq ($(TARGET_BUILD_PDK),true)
+# Build MediaComponents only if this is not a PDK build.  MediaComponents won't
+# build in PDK builds because frameworks/base/core/java is not available but
+# IMediaSession2.aidl and IMediaSession2Callback.aidl are using classes from
+# frameworks/base/core/java.
+
 include $(CLEAR_VARS)
 
 LOCAL_PACKAGE_NAME := MediaComponents
@@ -60,4 +66,6 @@
 
 include $(BUILD_PACKAGE)
 
+endif  # ifneq ($(TARGET_BUILD_PDK),true)
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index f9ebd44..73c1b38 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -71,7 +71,7 @@
             android:orientation="horizontal">
 
             <LinearLayout
-                android:id="@+id/ad"
+                android:id="@+id/ad_external_link"
                 android:clickable="true"
                 android:gravity="center"
                 android:layout_width="wrap_content"
@@ -80,7 +80,8 @@
                 android:layout_centerVertical="true"
                 android:paddingLeft="5dip"
                 android:paddingRight="10dip"
-                android:orientation="horizontal">
+                android:orientation="horizontal"
+                android:visibility="gone">
 
                 <TextView
                     android:id="@+id/ad_text"
@@ -88,7 +89,7 @@
                     android:layout_height="wrap_content"
                     android:layout_centerVertical="true"
                     android:paddingRight="5dip"
-                    android:text="Visit Advertiser"
+                    android:text="@string/MediaControlView2_ad_text"
                     android:textSize="10sp"
                     android:textColor="#FFFFFFFF" />
 
@@ -163,14 +164,35 @@
             android:textStyle="bold"
             android:textColor="#BBBBBB" />
 
+        <TextView
+            android:id="@+id/ad_skip_time"
+            android:gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:textSize="12sp"
+            android:textColor="#FFFFFF"
+            android:visibility="gone" />
+
         <LinearLayout
             android:id="@+id/basic_controls"
+            android:gravity="center"
             android:layout_alignParentRight="true"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerVertical="true"
             android:orientation="horizontal" >
 
+            <TextView
+                android:id="@+id/ad_remaining"
+                android:gravity="center"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:textSize="12sp"
+                android:textColor="#FFFFFF"
+                android:visibility="gone" />
+
             <ImageButton
                 android:id="@+id/subtitle"
                 android:scaleType="fitCenter"
diff --git a/packages/MediaComponents/res/values/strings.xml b/packages/MediaComponents/res/values/strings.xml
index 35db0e5..333d400 100644
--- a/packages/MediaComponents/res/values/strings.xml
+++ b/packages/MediaComponents/res/values/strings.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 
-<resources>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
     <!-- Name for the default system route prior to Jellybean. [CHAR LIMIT=30] -->
     <string name="mr_system_route_name">System</string>
 
@@ -92,4 +94,15 @@
     <string name="VideoView2_error_text_unknown">Can\'t play this video.</string>
     <!-- Button to close error alert when a video cannot be played. -->
     <string name="VideoView2_error_button">OK</string>
+
+    <!-- Text for displaying ad skip wait time. -->
+    <string name="MediaControlView2_ad_skip_wait_time">
+        You can skip Ad in <xliff:g id="wait_time" example="5">%1$d</xliff:g>s
+    </string>
+    <!-- Text for displaying ad total remaining time. -->
+    <string name="MediaControlView2_ad_remaining_time">
+        Ad · <xliff:g id="remaining_time" example="1:15">%1$s</xliff:g> remaining
+    </string>
+    <!-- Placeholder text indicating that the user can press the button to go to an external website. -->
+    <string name="MediaControlView2_ad_text">Visit Advertiser</string>
 </resources>
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
index 7702bda..63c0697 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2.aidl
@@ -37,7 +37,7 @@
     //               not to expose other methods to the controller whose connection wasn't accepted.
     //               But this would be enough for now because it's the same as existing
     //               MediaBrowser and MediaBrowserService.
-    void connect(String callingPackage, IMediaSession2Callback callback);
+    void connect(IMediaSession2Callback caller, String callingPackage);
     void release(IMediaSession2Callback caller);
 
     void setVolumeTo(IMediaSession2Callback caller, int value, int flags);
@@ -52,15 +52,24 @@
     void sendCustomCommand(IMediaSession2Callback caller, in Bundle command, in Bundle args,
             in ResultReceiver receiver);
 
-    void prepareFromUri(IMediaSession2Callback caller, in Uri uri, in Bundle extra);
-    void prepareFromSearch(IMediaSession2Callback caller, String query, in Bundle extra);
-    void prepareFromMediaId(IMediaSession2Callback caller, String mediaId, in Bundle extra);
-    void playFromUri(IMediaSession2Callback caller, in Uri uri, in Bundle extra);
-    void playFromSearch(IMediaSession2Callback caller, String query, in Bundle extra);
-    void playFromMediaId(IMediaSession2Callback caller, String mediaId, in Bundle extra);
+    void prepareFromUri(IMediaSession2Callback caller, in Uri uri, in Bundle extras);
+    void prepareFromSearch(IMediaSession2Callback caller, String query, in Bundle extras);
+    void prepareFromMediaId(IMediaSession2Callback caller, String mediaId, in Bundle extras);
+    void playFromUri(IMediaSession2Callback caller, in Uri uri, in Bundle extras);
+    void playFromSearch(IMediaSession2Callback caller, String query, in Bundle extras);
+    void playFromMediaId(IMediaSession2Callback caller, String mediaId, in Bundle extras);
+    void setRating(IMediaSession2Callback caller, String mediaId, in Bundle rating);
 
-   //////////////////////////////////////////////////////////////////////////////////////////////
-    // Get library service specific
     //////////////////////////////////////////////////////////////////////////////////////////////
-    void getBrowserRoot(IMediaSession2Callback callback, in Bundle rootHints);
+    // library service specific
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    void getBrowserRoot(IMediaSession2Callback caller, in Bundle rootHints);
+    void getItem(IMediaSession2Callback caller, String mediaId);
+    void getChildren(IMediaSession2Callback caller, String parentId, int page, int pageSize,
+            in Bundle extras);
+    void search(IMediaSession2Callback caller, String query, in Bundle extras);
+    void getSearchResult(IMediaSession2Callback caller, String query, int page, int pageSize,
+            in Bundle extras);
+    void subscribe(IMediaSession2Callback caller, String parentId, in Bundle extras);
+    void unsubscribe(IMediaSession2Callback caller, String parentId);
 }
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
index a443bf8..9a0be7a 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
@@ -36,7 +36,7 @@
 
     // TODO(jaewan): Handle when the playlist becomes too huge.
     void onConnected(IMediaSession2 sessionBinder, in Bundle commandGroup, in Bundle playbackState,
-            in Bundle playbackInfo, in Bundle params, in List<Bundle> playlist, int ratingType,
+            in Bundle playbackInfo, in Bundle params, in List<Bundle> playlist,
             in PendingIntent sessionActivity);
     void onDisconnected();
 
@@ -48,4 +48,11 @@
     // Browser sepcific
     //////////////////////////////////////////////////////////////////////////////////////////////
     void onGetRootResult(in Bundle rootHints, String rootMediaId, in Bundle rootExtra);
+    void onItemLoaded(String mediaId, in Bundle result);
+    void onChildrenChanged(String rootMediaId, int childCount, in Bundle extras);
+    void onChildrenLoaded(String parentId, int page, int pageSize, in List<Bundle> result,
+            in Bundle extras);
+    void onSearchResultChanged(String query, int itemCount, in Bundle extras);
+    void onSearchResultLoaded(String query, int page, int pageSize, in List<Bundle> result,
+            in Bundle extras);
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index 7e928d7..c095187 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -19,11 +19,12 @@
 import android.content.Context;
 import android.media.MediaBrowser2;
 import android.media.MediaBrowser2.BrowserCallback;
-import android.media.MediaSession2.CommandButton;
+import android.media.MediaItem2;
 import android.media.SessionToken2;
 import android.media.update.MediaBrowser2Provider;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.util.List;
@@ -61,28 +62,122 @@
     }
 
     @Override
-    public void subscribe_impl(String parentId, Bundle options) {
-        // TODO(jaewan): Implement
+    public void subscribe_impl(String parentId, Bundle extras) {
+        final IMediaSession2 binder = getSessionBinder();
+        if (binder != null) {
+            try {
+                binder.subscribe(getControllerStub(), parentId, extras);
+            } catch (RemoteException e) {
+                // TODO(jaewan): Handle disconnect.
+                if (DEBUG) {
+                    Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+                }
+            }
+        } else {
+            Log.w(TAG, "Session isn't active", new IllegalStateException());
+        }
     }
 
     @Override
-    public void unsubscribe_impl(String parentId, Bundle options) {
-        // TODO(jaewan): Implement
+    public void unsubscribe_impl(String parentId) {
+        final IMediaSession2 binder = getSessionBinder();
+        if (binder != null) {
+            try {
+                binder.unsubscribe(getControllerStub(), parentId);
+            } catch (RemoteException e) {
+                // TODO(jaewan): Handle disconnect.
+                if (DEBUG) {
+                    Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+                }
+            }
+        } else {
+            Log.w(TAG, "Session isn't active", new IllegalStateException());
+        }
     }
 
     @Override
     public void getItem_impl(String mediaId) {
-        // TODO(jaewan): Implement
+        if (mediaId == null) {
+            throw new IllegalArgumentException("mediaId shouldn't be null");
+        }
+
+        final IMediaSession2 binder = getSessionBinder();
+        if (binder != null) {
+            try {
+                binder.getItem(getControllerStub(), mediaId);
+            } catch (RemoteException e) {
+                // TODO(jaewan): Handle disconnect.
+                if (DEBUG) {
+                    Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+                }
+            }
+        } else {
+            Log.w(TAG, "Session isn't active", new IllegalStateException());
+        }
     }
 
     @Override
-    public void getChildren_impl(String parentId, int page, int pageSize, Bundle options) {
-        // TODO(jaewan): Implement
+    public void getChildren_impl(String parentId, int page, int pageSize, Bundle extras) {
+        if (parentId == null) {
+            throw new IllegalArgumentException("parentId shouldn't be null");
+        }
+        if (page < 1 || pageSize < 1) {
+            throw new IllegalArgumentException("Neither page nor pageSize should be less than 1");
+        }
+
+        final IMediaSession2 binder = getSessionBinder();
+        if (binder != null) {
+            try {
+                binder.getChildren(getControllerStub(), parentId, page, pageSize, extras);
+            } catch (RemoteException e) {
+                // TODO(jaewan): Handle disconnect.
+                if (DEBUG) {
+                    Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+                }
+            }
+        } else {
+            Log.w(TAG, "Session isn't active", new IllegalStateException());
+        }
     }
 
     @Override
-    public void search_impl(String query, int page, int pageSize, Bundle extras) {
-        // TODO(jaewan): Implement
+    public void search_impl(String query, Bundle extras) {
+        if (TextUtils.isEmpty(query)) {
+            throw new IllegalArgumentException("query shouldn't be empty");
+        }
+        final IMediaSession2 binder = getSessionBinder();
+        if (binder != null) {
+            try {
+                binder.search(getControllerStub(), query, extras);
+            } catch (RemoteException e) {
+                // TODO(jaewan): Handle disconnect.
+                if (DEBUG) {
+                    Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+                }
+            }
+        } else {
+            Log.w(TAG, "Session isn't active", new IllegalStateException());
+        }
+    }
+
+    @Override
+    public void getSearchResult_impl(String query, int page, int pageSize, Bundle extras) {
+        if (TextUtils.isEmpty(query)) {
+            throw new IllegalArgumentException("query shouldn't be empty");
+        }
+        final IMediaSession2 binder = getSessionBinder();
+        if (binder != null) {
+            try {
+                binder.getSearchResult(getControllerStub(), query, page, pageSize, extras);
+            } catch (RemoteException e) {
+                // TODO(jaewan): Handle disconnect.
+                if (DEBUG) {
+                    Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+                }
+            }
+        } else {
+            Log.w(TAG, "Session isn't active", new IllegalStateException());
+        }
     }
 
     public void onGetRootResult(
@@ -91,4 +186,36 @@
             mCallback.onGetRootResult(rootHints, rootMediaId, rootExtra);
         });
     }
+
+    public void onItemLoaded(String mediaId, MediaItem2 item) {
+        getCallbackExecutor().execute(() -> {
+            mCallback.onItemLoaded(mediaId, item);
+        });
+    }
+
+    public void onChildrenLoaded(String parentId, int page, int pageSize, List<MediaItem2> result,
+            Bundle extras) {
+        getCallbackExecutor().execute(() -> {
+            mCallback.onChildrenLoaded(parentId, page, pageSize, result, extras);
+        });
+    }
+
+    public void onSearchResultChanged(String query, int itemCount, Bundle extras) {
+        getCallbackExecutor().execute(() -> {
+            mCallback.onSearchResultChanged(query, itemCount, extras);
+        });
+    }
+
+    public void onSearchResultLoaded(String query, int page, int pageSize, List<MediaItem2> result,
+            Bundle extras) {
+        getCallbackExecutor().execute(() -> {
+            mCallback.onSearchResultLoaded(query, page, pageSize, result, extras);
+        });
+    }
+
+    public void onChildrenChanged(final String parentId, int childCount, final Bundle extras) {
+        getCallbackExecutor().execute(() -> {
+            mCallback.onChildrenChanged(parentId, childCount, extras);
+        });
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 5ae37ee..77db355 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -22,14 +22,14 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.media.AudioAttributes;
+import android.media.MediaController2;
+import android.media.MediaController2.ControllerCallback;
 import android.media.MediaController2.PlaybackInfo;
 import android.media.MediaItem2;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
-import android.media.MediaController2;
-import android.media.MediaController2.ControllerCallback;
 import android.media.MediaSession2.PlaylistParams;
 import android.media.MediaSessionService2;
 import android.media.PlaybackState2;
@@ -75,8 +75,6 @@
     @GuardedBy("mLock")
     private PlaybackInfo mPlaybackInfo;
     @GuardedBy("mLock")
-    private int mRatingType;
-    @GuardedBy("mLock")
     private PendingIntent mSessionActivity;
     @GuardedBy("mLock")
     private CommandGroup mCommandGroup;
@@ -164,7 +162,7 @@
 
     private void connectToSession(IMediaSession2 sessionBinder) {
         try {
-            sessionBinder.connect(mContext.getPackageName(), mSessionCallbackStub);
+            sessionBinder.connect(mSessionCallbackStub, mContext.getPackageName());
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to call connection request. Framework will retry"
                     + " automatically");
@@ -286,11 +284,6 @@
     }
 
     @Override
-    public int getRatingType_impl() {
-        return mRatingType;
-    }
-
-    @Override
     public void setVolumeTo_impl(int value, int flags) {
         // TODO(hdmoon): sanity check
         final IMediaSession2 binder = mSessionBinder;
@@ -403,9 +396,26 @@
             // TODO(jaewan): Handle.
         }
     }
+
     @Override
-    public void setRating_impl(Rating2 rating) {
-        // TODO(jaewan): Implement
+    public void setRating_impl(String mediaId, Rating2 rating) {
+        if (mediaId == null) {
+            throw new IllegalArgumentException("mediaId shouldn't be null");
+        }
+        if (rating == null) {
+            throw new IllegalArgumentException("rating shouldn't be null");
+        }
+
+        final IMediaSession2 binder = mSessionBinder;
+        if (binder != null) {
+            try {
+                binder.setRating(mSessionCallbackStub, mediaId, rating.toBundle());
+            } catch (RemoteException e) {
+                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
+            }
+        } else {
+            // TODO(jaewan): Handle.
+        }
     }
 
     @Override
@@ -563,7 +573,7 @@
     // Should be used without a lock to prevent potential deadlock.
     void onConnectedNotLocked(IMediaSession2 sessionBinder,
             final CommandGroup commandGroup, final PlaybackState2 state, final PlaybackInfo info,
-            final PlaylistParams params, final List<MediaItem2> playlist, final int ratingType,
+            final PlaylistParams params, final List<MediaItem2> playlist,
             final PendingIntent sessionActivity) {
         if (DEBUG) {
             Log.d(TAG, "onConnectedNotLocked sessionBinder=" + sessionBinder
@@ -591,7 +601,6 @@
                 mPlaybackInfo = info;
                 mPlaylistParams = params;
                 mPlaylist = playlist;
-                mRatingType = ratingType;
                 mSessionActivity = sessionActivity;
                 mSessionBinder = sessionBinder;
                 try {
diff --git a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
index f51e246..4c4ef24 100644
--- a/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaItem2Impl.java
@@ -52,7 +52,7 @@
             throw new IllegalArgumentException("dsd shouldn't be null");
         }
         if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) {
-            throw new IllegalArgumentException("metadata's id should be match with the mediaid");
+            throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
         }
 
         mContext = context;
@@ -71,9 +71,9 @@
             throw new IllegalArgumentException("mediaId shouldn't be null");
         }
         if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) {
-            throw new IllegalArgumentException("metadata's id should be match with the mediaid");
+            throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
         }
-        mContext =context;
+        mContext = context;
         mId = mediaId;
         mMetadata = metadata;
         mFlags = flags;
@@ -136,24 +136,21 @@
     }
 
     @Override
-    public void setMetadata_impl(@NonNull MediaMetadata2 metadata) {
-        if (metadata == null) {
-            throw new IllegalArgumentException("metadata shouldn't be null");
-        }
-        if (TextUtils.isEmpty(metadata.getMediaId())) {
-            throw new IllegalArgumentException("metadata must have a non-empty media id");
+    public void setMetadata_impl(@Nullable MediaMetadata2 metadata) {
+        if (metadata != null && !TextUtils.equals(mId, metadata.getMediaId())) {
+            throw new IllegalArgumentException("metadata's id should be matched with the mediaId");
         }
         mMetadata = metadata;
     }
 
     @Override
-    public MediaMetadata2 getMetadata_impl() {
+    public @Nullable MediaMetadata2 getMetadata_impl() {
         return mMetadata;
     }
 
     @Override
-    public @Nullable String getMediaId_impl() {
-        return mMetadata.getMediaId();
+    public @NonNull String getMediaId_impl() {
+        return mId;
     }
 
     @Override
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index b9dffcf..b9d2fa4 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -26,12 +26,12 @@
 import android.media.MediaPlayerInterface;
 import android.media.MediaSession2;
 import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
 import android.media.update.MediaLibraryService2Provider;
 import android.os.Bundle;
+import android.text.TextUtils;
 
 import com.android.media.MediaSession2Impl.BuilderBaseImpl;
 
@@ -66,15 +66,16 @@
 
     public static class MediaLibrarySessionImpl extends MediaSession2Impl
             implements MediaLibrarySessionProvider {
-        private final MediaLibrarySessionCallback mCallback;
-
         public MediaLibrarySessionImpl(Context context,
                 MediaPlayerInterface player, String id, VolumeProvider2 volumeProvider,
-                int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
+                PendingIntent sessionActivity, Executor callbackExecutor,
                 MediaLibrarySessionCallback callback) {
-            super(context, player, id, volumeProvider, ratingType, sessionActivity,
-                    callbackExecutor, callback);
-            mCallback = callback;
+            super(context, player, id, volumeProvider, sessionActivity, callbackExecutor, callback);
+            // Don't put any extra initialization here. Here's the reason.
+            // System service will recognize this session inside of the super constructor and would
+            // connect to this session assuming that initialization is finished. However, if any
+            // initialization logic is here, calls from the server would fail.
+            // see: MediaSession2Stub#connect()
         }
 
         @Override
@@ -89,19 +90,41 @@
 
         @Override
         MediaLibrarySessionCallback getCallback() {
-            // Equivalent to the (MediaLibrarySessionCallback) super.getCallback().
-            return mCallback;
+            return (MediaLibrarySessionCallback) super.getCallback();
         }
 
         @Override
         public void notifyChildrenChanged_impl(ControllerInfo controller, String parentId,
-                Bundle options) {
-            // TODO(jaewan): Implements
+                int childCount, Bundle extras) {
+            if (controller == null) {
+                throw new IllegalArgumentException("controller shouldn't be null");
+            }
+            if (parentId == null) {
+                throw new IllegalArgumentException("parentId shouldn't be null");
+            }
+            getSessionStub().notifyChildrenChangedNotLocked(controller, parentId, childCount,
+                    extras);
         }
 
         @Override
-        public void notifyChildrenChanged_impl(String parentId, Bundle options) {
-            // TODO(jaewan): Implements
+        public void notifyChildrenChanged_impl(String parentId, int childCount, Bundle extras) {
+            if (parentId == null) {
+                throw new IllegalArgumentException("parentId shouldn't be null");
+            }
+            getSessionStub().notifyChildrenChangedNotLocked(parentId, childCount, extras);
+        }
+
+        @Override
+        public void notifySearchResultChanged_impl(ControllerInfo controller, String query,
+                int itemCount, Bundle extras) {
+            ensureCallingThread();
+            if (controller == null) {
+                throw new IllegalArgumentException("controller shouldn't be null");
+            }
+            if (TextUtils.isEmpty(query)) {
+                throw new IllegalArgumentException("query shouldn't be empty");
+            }
+            getSessionStub().notifySearchResultChanged(controller, query, itemCount, extras);
         }
     }
 
@@ -116,7 +139,7 @@
 
         @Override
         public MediaLibrarySession build_impl() {
-            return new MediaLibrarySessionImpl(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+            return new MediaLibrarySessionImpl(mContext, mPlayer, mId, mVolumeProvider,
                     mSessionActivity, mCallbackExecutor, mCallback).getInstance();
         }
     }
@@ -147,4 +170,4 @@
             return mExtras;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
index 07edf7e..e174d91 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2CallbackStub.java
@@ -125,7 +125,7 @@
     @Override
     public void onConnected(IMediaSession2 sessionBinder, Bundle commandGroup,
             Bundle playbackState, Bundle playbackInfo, Bundle playlistParams, List<Bundle>
-            playlist, int ratingType, PendingIntent sessionActivity) {
+            playlist, PendingIntent sessionActivity) {
         final MediaController2Impl controller = mController.get();
         if (controller == null) {
             if (DEBUG) {
@@ -146,7 +146,7 @@
                 PlaybackState2.fromBundle(context, playbackState),
                 PlaybackInfoImpl.fromBundle(context, playbackInfo),
                 PlaylistParams.fromBundle(context, playlistParams),
-                list, ratingType, sessionActivity);
+                list, sessionActivity);
     }
 
     @Override
@@ -224,4 +224,105 @@
         }
         browser.onGetRootResult(rootHints, rootMediaId, rootExtra);
     }
+
+
+    @Override
+    public void onItemLoaded(String mediaId, Bundle itemBundle) throws RuntimeException {
+        final MediaBrowser2Impl browser;
+        try {
+            browser = getBrowser();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (browser == null) {
+            // TODO(jaewan): Revisit here. Could be a bug
+            return;
+        }
+        browser.onItemLoaded(mediaId,
+                MediaItem2Impl.fromBundle(browser.getContext(), itemBundle));
+    }
+
+    @Override
+    public void onChildrenLoaded(String parentId, int page, int pageSize,
+            List<Bundle> itemBundleList, Bundle extras) throws RuntimeException {
+        final MediaBrowser2Impl browser;
+        try {
+            browser = getBrowser();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (browser == null) {
+            // TODO(jaewan): Revisit here. Could be a bug
+            return;
+        }
+
+        List<MediaItem2> result = null;
+        if (itemBundleList != null) {
+            result = new ArrayList<>();
+            for (Bundle bundle : itemBundleList) {
+                result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+            }
+        }
+        browser.onChildrenLoaded(parentId, page, pageSize, result, extras);
+    }
+
+    @Override
+    public void onSearchResultChanged(String query, int itemCount, Bundle extras)
+            throws RuntimeException {
+        final MediaBrowser2Impl browser;
+        try {
+            browser = getBrowser();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (browser == null) {
+            // TODO(jaewan): Revisit here. Could be a bug
+            return;
+        }
+        browser.onSearchResultChanged(query, itemCount, extras);
+    }
+
+    @Override
+    public void onSearchResultLoaded(String query, int page, int pageSize,
+            List<Bundle> itemBundleList, Bundle extras) throws RuntimeException {
+        final MediaBrowser2Impl browser;
+        try {
+            browser = getBrowser();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (browser == null) {
+            // TODO(jaewan): Revisit here. Could be a bug
+            return;
+        }
+
+        List<MediaItem2> result = null;
+        if (itemBundleList != null) {
+            result = new ArrayList<>();
+            for (Bundle bundle : itemBundleList) {
+                result.add(MediaItem2.fromBundle(browser.getContext(), bundle));
+            }
+        }
+        browser.onSearchResultLoaded(query, page, pageSize, result, extras);
+    }
+
+    @Override
+    public void onChildrenChanged(String parentId, int childCount, Bundle extras) {
+        final MediaBrowser2Impl browser;
+        try {
+            browser = getBrowser();
+        } catch (IllegalStateException e) {
+            Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+            return;
+        }
+        if (browser == null) {
+            // TODO(jaewan): Revisit here. Could be a bug
+            return;
+        }
+        browser.onChildrenChanged(parentId, childCount, extras);
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 74ac5b3..a32ea0a 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -38,7 +38,7 @@
 import android.media.MediaLibraryService2;
 import android.media.MediaMetadata2;
 import android.media.MediaPlayerInterface;
-import android.media.MediaPlayerInterface.PlaybackListener;
+import android.media.MediaPlayerInterface.EventCallback;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Builder;
 import android.media.MediaSession2.Command;
@@ -62,6 +62,7 @@
 import android.os.ResultReceiver;
 import android.support.annotation.GuardedBy;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -84,10 +85,25 @@
     private final MediaSession2Stub mSessionStub;
     private final SessionToken2 mSessionToken;
     private final AudioManager mAudioManager;
-    private final List<PlaybackListenerHolder> mListeners = new ArrayList<>();
-    private final int mRatingType;
+    private final ArrayMap<EventCallback, Executor> mCallbacks = new ArrayMap<>();
     private final PendingIntent mSessionActivity;
 
+    // mPlayer is set to null when the session is closed, and we shouldn't throw an exception
+    // nor leave log always for using mPlayer when it's null. Here's the reason.
+    // When a MediaSession2 is closed, there could be a pended operation in the session callback
+    // executor that may want to access the player. Here's the sample code snippet for that.
+    //
+    //   public void onFoo() {
+    //     if (mPlayer == null) return; // first check
+    //     mSessionCallbackExecutor.executor(() -> {
+    //       // Error. Session may be closed and mPlayer can be null here.
+    //       mPlayer.foo();
+    //     });
+    //   }
+    //
+    // By adding protective code, we can also protect APIs from being called after the close()
+    //
+    // TODO(jaewan): Should we put volatile here?
     @GuardedBy("mLock")
     private MediaPlayerInterface mPlayer;
     @GuardedBy("mLock")
@@ -95,11 +111,7 @@
     @GuardedBy("mLock")
     private PlaybackInfo mPlaybackInfo;
     @GuardedBy("mLock")
-    private MyPlaybackListener mListener;
-    @GuardedBy("mLock")
-    private PlaylistParams mPlaylistParams;
-    @GuardedBy("mLock")
-    private List<MediaItem2> mPlaylist;
+    private MyEventCallback mEventCallback;
 
     /**
      * Can be only called by the {@link Builder#build()}.
@@ -107,13 +119,13 @@
      * @param context
      * @param player
      * @param id
-     * @param callback
      * @param volumeProvider
-     * @param ratingType
      * @param sessionActivity
+     * @param callbackExecutor
+     * @param callback
      */
     public MediaSession2Impl(Context context, MediaPlayerInterface player, String id,
-            VolumeProvider2 volumeProvider, int ratingType, PendingIntent sessionActivity,
+            VolumeProvider2 volumeProvider, PendingIntent sessionActivity,
             Executor callbackExecutor, SessionCallback callback) {
         // TODO(jaewan): Keep other params.
         mInstance = createInstance();
@@ -124,7 +136,6 @@
         mId = id;
         mCallback = callback;
         mCallbackExecutor = callbackExecutor;
-        mRatingType = ratingType;
         mSessionActivity = sessionActivity;
         mSessionStub = new MediaSession2Stub(this);
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -146,9 +157,7 @@
                     mContext.getPackageName(), null, id, mSessionStub).getInstance();
         }
 
-        setPlayerLocked(player);
-        mVolumeProvider = volumeProvider;
-        mPlaybackInfo = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
+        setPlayer(player, volumeProvider);
 
         // Ask server for the sanity check, and starts
         // Sanity check for making session ID unique 'per package' cannot be done in here.
@@ -198,14 +207,7 @@
         if (player == null) {
             throw new IllegalArgumentException("player shouldn't be null");
         }
-        PlaybackInfo info =
-                createPlaybackInfo(null /* VolumeProvider */, player.getAudioAttributes());
-        synchronized (mLock) {
-            setPlayerLocked(player);
-            mVolumeProvider = null;
-            mPlaybackInfo = info;
-        }
-        mSessionStub.notifyPlaybackInfoChanged(info);
+        setPlayer(player, null);
     }
 
     @Override
@@ -218,23 +220,24 @@
         if (volumeProvider == null) {
             throw new IllegalArgumentException("volumeProvider shouldn't be null");
         }
-        PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
+        setPlayer(player, volumeProvider);
+    }
+
+    private void setPlayer(MediaPlayerInterface player, VolumeProvider2 volumeProvider) {
+        final PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
         synchronized (mLock) {
-            setPlayerLocked(player);
+            if (mPlayer != null && mEventCallback != null) {
+                // This might not work for a poorly implemented player.
+                mPlayer.unregisterEventCallback(mEventCallback);
+            }
+            mPlayer = player;
+            mEventCallback = new MyEventCallback(this, player);
+            player.registerEventCallback(mCallbackExecutor, mEventCallback);
             mVolumeProvider = volumeProvider;
             mPlaybackInfo = info;
         }
         mSessionStub.notifyPlaybackInfoChanged(info);
-    }
-
-    private void setPlayerLocked(MediaPlayerInterface player) {
-        if (mPlayer != null && mListener != null) {
-            // This might not work for a poorly implemented player.
-            mPlayer.removePlaybackListener(mListener);
-        }
-        mPlayer = player;
-        mListener = new MyPlaybackListener(this, player);
-        player.addPlaybackListener(mCallbackExecutor, mListener);
+        notifyPlaybackStateChangedNotLocked(mInstance.getPlaybackState());
     }
 
     private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
@@ -290,7 +293,7 @@
         synchronized (mLock) {
             if (mPlayer != null) {
                 // close can be called multiple times
-                mPlayer.removePlaybackListener(mListener);
+                mPlayer.unregisterEventCallback(mEventCallback);
                 mPlayer = null;
             }
         }
@@ -320,36 +323,56 @@
     @Override
     public void play_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.play();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.play();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void pause_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.pause();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.pause();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void stop_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.stop();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.stop();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void skipToPrevious_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.skipToPrevious();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.skipToPrevious();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void skipToNext_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.skipToNext();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.skipToNext();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
@@ -367,21 +390,27 @@
     @Override
     public void setPlaylistParams_impl(PlaylistParams params) {
         if (params == null) {
-            throw new IllegalArgumentException("PlaylistParams should not be null!");
+            throw new IllegalArgumentException("params shouldn't be null");
         }
         ensureCallingThread();
-        ensurePlayer();
-        synchronized (mLock) {
-            mPlaylistParams = params;
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.setPlaylistParams(params);
+            mSessionStub.notifyPlaylistParamsChanged(params);
         }
-        mPlayer.setPlaylistParams(params);
-        mSessionStub.notifyPlaylistParamsChanged(params);
     }
 
     @Override
     public PlaylistParams getPlaylistParams_impl() {
-        // TODO: Do we need to synchronize here for preparing Controller2.setPlaybackParams?
-        return mPlaylistParams;
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            // TODO(jaewan): Is it safe to be called on any thread?
+            //               Otherwise MediaSession2 should cache parameter of setPlaylistParams.
+            return player.getPlaylistParams();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
+        return null;
     }
 
     //////////////////////////////////////////////////////////////////////////////////////
@@ -412,95 +441,126 @@
     @Override
     public void setPlaylist_impl(List<MediaItem2> playlist) {
         if (playlist == null) {
-            throw new IllegalArgumentException("Playlist should not be null!");
+            throw new IllegalArgumentException("playlist shouldn't be null");
         }
         ensureCallingThread();
-        ensurePlayer();
-        synchronized (mLock) {
-            mPlaylist = playlist;
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.setPlaylist(playlist);
+            mSessionStub.notifyPlaylistChanged(playlist);
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
         }
-        mPlayer.setPlaylist(playlist);
-        mSessionStub.notifyPlaylistChanged(playlist);
     }
 
     @Override
     public List<MediaItem2> getPlaylist_impl() {
-        synchronized (mLock) {
-            return mPlaylist;
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            // TODO(jaewan): Is it safe to be called on any thread?
+            //               Otherwise MediaSession2 should cache parameter of setPlaylist.
+            return player.getPlaylist();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
         }
+        return null;
     }
 
     @Override
     public void prepare_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.prepare();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.prepare();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void fastForward_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.fastForward();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.fastForward();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void rewind_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.rewind();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.rewind();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void seekTo_impl(long pos) {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.seekTo(pos);
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.seekTo(pos);
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
     public void setCurrentPlaylistItem_impl(int index) {
         ensureCallingThread();
-        ensurePlayer();
-        mPlayer.setCurrentPlaylistItem(index);
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            player.setCurrentPlaylistItem(index);
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
     }
 
     @Override
-    public void addPlaybackListener_impl(Executor executor, PlaybackListener listener) {
+    public void registerPlayerEventCallback_impl(Executor executor, EventCallback callback) {
         if (executor == null) {
             throw new IllegalArgumentException("executor shouldn't be null");
         }
-        if (listener == null) {
-            throw new IllegalArgumentException("listener shouldn't be null");
+        if (callback == null) {
+            throw new IllegalArgumentException("callback shouldn't be null");
         }
         ensureCallingThread();
-        if (PlaybackListenerHolder.contains(mListeners, listener)) {
-            Log.w(TAG, "listener is already added. Ignoring.");
+        if (mCallbacks.get(callback) != null) {
+            Log.w(TAG, "callback is already added. Ignoring.");
             return;
         }
-        mListeners.add(new PlaybackListenerHolder(executor, listener));
-        executor.execute(() -> listener.onPlaybackChanged(getInstance().getPlaybackState()));
+        mCallbacks.put(callback, executor);
+        // TODO(jaewan): Double check if we need this.
+        final PlaybackState2 state = getInstance().getPlaybackState();
+        executor.execute(() -> callback.onPlaybackStateChanged(state));
     }
 
     @Override
-    public void removePlaybackListener_impl(PlaybackListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener shouldn't be null");
+    public void unregisterPlayerEventCallback_impl(EventCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback shouldn't be null");
         }
         ensureCallingThread();
-        int idx = PlaybackListenerHolder.indexOf(mListeners, listener);
-        if (idx >= 0) {
-            mListeners.remove(idx);
-        }
+        mCallbacks.remove(callback);
     }
 
     @Override
     public PlaybackState2 getPlaybackState_impl() {
         ensureCallingThread();
-        ensurePlayer();
-        // TODO(jaewan): Is it safe to be called on any thread?
-        //               Otherwise we should cache the result from listener.
-        return mPlayer.getPlaybackState();
+        final MediaPlayerInterface player = mPlayer;
+        if (player != null) {
+            // TODO(jaewan): Is it safe to be called on any thread?
+            //               Otherwise MediaSession2 should cache the result from listener.
+            return player.getPlaybackState();
+        } else if (DEBUG) {
+            Log.d(TAG, "API calls after the close()", new IllegalStateException());
+        }
+        return null;
     }
 
     ///////////////////////////////////////////////////
@@ -519,7 +579,7 @@
     //               1. Allow calls from random threads for all methods.
     //               2. Allow calls from random threads for all methods, except for the
     //                  {@link #setPlayer()}.
-    private void ensureCallingThread() {
+    void ensureCallingThread() {
         // TODO(jaewan): Uncomment or remove
         /*
         if (mHandler.getLooper() != Looper.myLooper()) {
@@ -527,27 +587,35 @@
         }*/
     }
 
-    private void ensurePlayer() {
-        // TODO(jaewan): Should we pend command instead? Follow the decision from MP2.
-        //               Alternatively we can add a API like setAcceptsPendingCommands(boolean).
-        if (mPlayer == null) {
-            throw new IllegalStateException("Player isn't set");
-        }
-    }
-
-    private void notifyPlaybackStateChangedNotLocked(PlaybackState2 state) {
-        List<PlaybackListenerHolder> listeners = new ArrayList<>();
+    private void notifyPlaybackStateChangedNotLocked(final PlaybackState2 state) {
+        ArrayMap<EventCallback, Executor> callbacks = new ArrayMap<>();
         synchronized (mLock) {
-            listeners.addAll(mListeners);
+            callbacks.putAll(mCallbacks);
         }
-        // Notify to listeners added directly to this session
-        for (int i = 0; i < listeners.size(); i++) {
-            listeners.get(i).postPlaybackChange(state);
+        // Notify to callbacks added directly to this session
+        for (int i = 0; i < callbacks.size(); i++) {
+            final EventCallback callback = callbacks.keyAt(i);
+            final Executor executor = callbacks.valueAt(i);
+            executor.execute(() -> callback.onPlaybackStateChanged(state));
         }
         // Notify to controllers as well.
         mSessionStub.notifyPlaybackStateChangedNotLocked(state);
     }
 
+    private void notifyErrorNotLocked(String mediaId, int what, int extra) {
+        ArrayMap<EventCallback, Executor> callbacks = new ArrayMap<>();
+        synchronized (mLock) {
+            callbacks.putAll(mCallbacks);
+        }
+        // Notify to callbacks added directly to this session
+        for (int i = 0; i < callbacks.size(); i++) {
+            final EventCallback callback = callbacks.keyAt(i);
+            final Executor executor = callbacks.valueAt(i);
+            executor.execute(() -> callback.onError(mediaId, what, extra));
+        }
+        // TODO(jaewan): Notify to controllers as well.
+    }
+
     Context getContext() {
         return mContext;
     }
@@ -568,6 +636,10 @@
         return mCallback;
     }
 
+    MediaSession2Stub getSessionStub() {
+        return mSessionStub;
+    }
+
     VolumeProvider2 getVolumeProvider() {
         return mVolumeProvider;
     }
@@ -578,33 +650,47 @@
         }
     }
 
-    int getRatingType() {
-        return mRatingType;
-    }
-
     PendingIntent getSessionActivity() {
         return mSessionActivity;
     }
 
-    private static class MyPlaybackListener implements MediaPlayerInterface.PlaybackListener {
+    private static class MyEventCallback implements EventCallback {
         private final WeakReference<MediaSession2Impl> mSession;
         private final MediaPlayerInterface mPlayer;
 
-        private MyPlaybackListener(MediaSession2Impl session, MediaPlayerInterface player) {
+        private MyEventCallback(MediaSession2Impl session, MediaPlayerInterface player) {
             mSession = new WeakReference<>(session);
             mPlayer = player;
         }
 
         @Override
-        public void onPlaybackChanged(PlaybackState2 state) {
+        public void onPlaybackStateChanged(PlaybackState2 state) {
             MediaSession2Impl session = mSession.get();
             if (mPlayer != session.mInstance.getPlayer()) {
                 Log.w(TAG, "Unexpected playback state change notifications. Ignoring.",
                         new IllegalStateException());
                 return;
             }
+            if (DEBUG) {
+                Log.d(TAG, "onPlaybackStateChanged from player, state=" + state);
+            }
             session.notifyPlaybackStateChangedNotLocked(state);
         }
+
+        @Override
+        public void onError(String mediaId, int what, int extra) {
+            MediaSession2Impl session = mSession.get();
+            if (mPlayer != session.mInstance.getPlayer()) {
+                Log.w(TAG, "Unexpected playback state change notifications. Ignoring.",
+                        new IllegalStateException());
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "onError from player, mediaId=" + mediaId + ", what=" + what
+                        + ", extra=" + extra);
+            }
+            session.notifyErrorNotLocked(mediaId, what, extra);
+        }
     }
 
     public static final class CommandImpl implements CommandProvider {
@@ -1114,7 +1200,6 @@
         Executor mCallbackExecutor;
         C mCallback;
         VolumeProvider2 mVolumeProvider;
-        int mRatingType;
         PendingIntent mSessionActivity;
 
         /**
@@ -1143,10 +1228,6 @@
             mVolumeProvider = volumeProvider;
         }
 
-        public void setRatingType_impl(int type) {
-            mRatingType = type;
-        }
-
         public void setSessionActivity_impl(PendingIntent pi) {
             mSessionActivity = pi;
         }
@@ -1186,7 +1267,7 @@
                 mCallback = new SessionCallback(mContext);
             }
 
-            return new MediaSession2Impl(mContext, mPlayer, mId, mVolumeProvider, mRatingType,
+            return new MediaSession2Impl(mContext, mPlayer, mId, mVolumeProvider,
                     mSessionActivity, mCallbackExecutor, mCallback).getInstance();
         }
     }
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 43ad49d..914f85e 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -28,6 +28,7 @@
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.PlaylistParams;
 import android.media.PlaybackState2;
+import android.media.Rating2;
 import android.media.VolumeProvider2;
 import android.net.Uri;
 import android.os.Binder;
@@ -36,6 +37,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.support.annotation.GuardedBy;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -46,6 +48,8 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
 
 public class MediaSession2Stub extends IMediaSession2.Stub {
 
@@ -62,6 +66,8 @@
 
     @GuardedBy("mLock")
     private final ArrayMap<IBinder, ControllerInfo> mControllers = new ArrayMap<>();
+    @GuardedBy("mLock")
+    private final ArrayMap<ControllerInfo, Set<String>> mSubscriptions = new ArrayMap<>();
 
     public MediaSession2Stub(MediaSession2Impl session) {
         mSession = new WeakReference<>(session);
@@ -75,11 +81,11 @@
             mControllers.clear();
         }
         for (int i = 0; i < list.size(); i++) {
-            IMediaSession2Callback callbackBinder =
+            IMediaSession2Callback controllerBinder =
                     ((ControllerInfoImpl) list.get(i).getProvider()).getControllerBinder();
             try {
                 // Should be used without a lock hold to prevent potential deadlock.
-                callbackBinder.onDisconnected();
+                controllerBinder.onDisconnected();
             } catch (RemoteException e) {
                 // Controller is gone. Should be fine because we're destroying.
             }
@@ -116,12 +122,12 @@
     //////////////////////////////////////////////////////////////////////////////////////////////
 
     @Override
-    public void connect(String callingPackage, final IMediaSession2Callback callback)
+    public void connect(final IMediaSession2Callback caller, String callingPackage)
             throws RuntimeException {
         final MediaSession2Impl sessionImpl = getSession();
         final Context context = sessionImpl.getContext();
         final ControllerInfo request = new ControllerInfo(context,
-                Binder.getCallingUid(), Binder.getCallingPid(), callingPackage, callback);
+                Binder.getCallingUid(), Binder.getCallingPid(), callingPackage, caller);
         sessionImpl.getCallbackExecutor().execute(() -> {
             final MediaSession2Impl session = mSession.get();
             if (session == null) {
@@ -133,7 +139,7 @@
             // media keys to.
             boolean accept = allowedCommands != null || request.isTrusted();
             ControllerInfoImpl impl = ControllerInfoImpl.from(request);
-            if (accept && allowedCommands != null) {
+            if (accept) {
                 if (DEBUG) {
                     Log.d(TAG, "Accepting connection, request=" + request
                             + " allowedCommands=" + allowedCommands);
@@ -154,11 +160,10 @@
                 // TODO(jaewan): Should we protect getting playback state?
                 final PlaybackState2 state = session.getInstance().getPlaybackState();
                 final Bundle playbackStateBundle = (state != null) ? state.toBundle() : null;
-                final Bundle playbackInfoBundle =
-                        ((MediaController2Impl.PlaybackInfoImpl) session.getPlaybackInfo().getProvider()).toBundle();
+                final Bundle playbackInfoBundle = ((MediaController2Impl.PlaybackInfoImpl)
+                        session.getPlaybackInfo().getProvider()).toBundle();
                 final PlaylistParams params = session.getInstance().getPlaylistParams();
                 final Bundle paramsBundle = (params != null) ? params.toBundle() : null;
-                final int ratingType = session.getRatingType();
                 final PendingIntent sessionActivity = session.getSessionActivity();
                 final List<MediaItem2> playlist = session.getInstance().getPlaylist();
                 final List<Bundle> playlistBundle = new ArrayList<>();
@@ -181,9 +186,9 @@
                     return;
                 }
                 try {
-                    callback.onConnected(MediaSession2Stub.this,
+                    caller.onConnected(MediaSession2Stub.this,
                             allowedCommands.toBundle(), playbackStateBundle, playbackInfoBundle,
-                            paramsBundle, playlistBundle, ratingType, sessionActivity);
+                            paramsBundle, playlistBundle, sessionActivity);
                 } catch (RemoteException e) {
                     // Controller may be died prematurely.
                     // TODO(jaewan): Handle here.
@@ -193,7 +198,7 @@
                     Log.d(TAG, "Rejecting connection, request=" + request);
                 }
                 try {
-                    callback.onDisconnected();
+                    caller.onDisconnected();
                 } catch (RemoteException e) {
                     // Controller may be died prematurely.
                     // Not an issue because we'll ignore it anyway.
@@ -209,6 +214,7 @@
             if (DEBUG) {
                 Log.d(TAG, "releasing " + controllerInfo);
             }
+            mSubscriptions.remove(controllerInfo);
         }
     }
 
@@ -388,7 +394,7 @@
 
     @Override
     public void prepareFromUri(final IMediaSession2Callback caller, final Uri uri,
-            final Bundle extra) {
+            final Bundle extras) {
         final MediaSession2Impl sessionImpl = getSession();
         final ControllerInfo controller = getController(caller);
         if (controller == null) {
@@ -402,13 +408,13 @@
             if (session == null) {
                 return;
             }
-            session.getCallback().onPrepareFromUri(controller, uri, extra);
+            session.getCallback().onPrepareFromUri(controller, uri, extras);
         });
     }
 
     @Override
     public void prepareFromSearch(final IMediaSession2Callback caller, final String query,
-            final Bundle extra) {
+            final Bundle extras) {
         final MediaSession2Impl sessionImpl = getSession();
         final ControllerInfo controller = getController(caller);
         if (controller == null) {
@@ -422,13 +428,13 @@
             if (session == null) {
                 return;
             }
-            session.getCallback().onPrepareFromSearch(controller, query, extra);
+            session.getCallback().onPrepareFromSearch(controller, query, extras);
         });
     }
 
     @Override
     public void prepareFromMediaId(final IMediaSession2Callback caller, final String mediaId,
-            final Bundle extra) {
+            final Bundle extras) {
         final MediaSession2Impl sessionImpl = getSession();
         final ControllerInfo controller = getController(caller);
         if (controller == null) {
@@ -442,13 +448,13 @@
             if (session == null) {
                 return;
             }
-            session.getCallback().onPrepareFromMediaId(controller, mediaId, extra);
+            session.getCallback().onPrepareFromMediaId(controller, mediaId, extras);
         });
     }
 
     @Override
     public void playFromUri(final IMediaSession2Callback caller, final Uri uri,
-            final Bundle extra) {
+            final Bundle extras) {
         final MediaSession2Impl sessionImpl = getSession();
         final ControllerInfo controller = getController(caller);
         if (controller == null) {
@@ -462,13 +468,13 @@
             if (session == null) {
                 return;
             }
-            session.getCallback().onPlayFromUri(controller, uri, extra);
+            session.getCallback().onPlayFromUri(controller, uri, extras);
         });
     }
 
     @Override
     public void playFromSearch(final IMediaSession2Callback caller, final String query,
-            final Bundle extra) {
+            final Bundle extras) {
         final MediaSession2Impl sessionImpl = getSession();
         final ControllerInfo controller = getController(caller);
         if (controller == null) {
@@ -482,13 +488,13 @@
             if (session == null) {
                 return;
             }
-            session.getCallback().onPlayFromSearch(controller, query, extra);
+            session.getCallback().onPlayFromSearch(controller, query, extras);
         });
     }
 
     @Override
     public void playFromMediaId(final IMediaSession2Callback caller, final String mediaId,
-            final Bundle extra) {
+            final Bundle extras) {
         final MediaSession2Impl sessionImpl = getSession();
         final ControllerInfo controller = getController(caller);
         if (controller == null) {
@@ -502,7 +508,28 @@
             if (session == null) {
                 return;
             }
-            session.getCallback().onPlayFromMediaId(controller, mediaId, extra);
+            session.getCallback().onPlayFromMediaId(controller, mediaId, extras);
+        });
+    }
+
+    @Override
+    public void setRating(final IMediaSession2Callback caller, final String mediaId,
+            final Bundle ratingBundle) {
+        final MediaSession2Impl sessionImpl = getSession();
+        final ControllerInfo controller = getController(caller);
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "Command from a controller that hasn't connected. Ignore");
+            }
+            return;
+        }
+        sessionImpl.getCallbackExecutor().execute(() -> {
+            final MediaSession2Impl session = mSession.get();
+            if (session == null) {
+                return;
+            }
+            Rating2 rating = Rating2Impl.fromBundle(session.getContext(), ratingBundle);
+            session.getCallback().onSetRating(controller, mediaId, rating);
         });
     }
 
@@ -539,9 +566,232 @@
         });
     }
 
+    @Override
+    public void getItem(IMediaSession2Callback caller, String mediaId) throws RuntimeException {
+        final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+        final ControllerInfo controller = getController(caller);
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "getItem() from a controller that hasn't connected. Ignore");
+            }
+            return;
+        }
+        if (mediaId == null) {
+            if (DEBUG) {
+                Log.d(TAG, "mediaId shouldn't be null");
+            }
+            return;
+        }
+        sessionImpl.getCallbackExecutor().execute(() -> {
+            final MediaLibrarySessionImpl session = getLibrarySession();
+            if (session == null) {
+                return;
+            }
+            final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+            MediaItem2 result = session.getCallback().onLoadItem(controller, mediaId);
+            try {
+                controllerImpl.getControllerBinder().onItemLoaded(
+                        mediaId, result == null ? null : result.toBundle());
+            } catch (RemoteException e) {
+                // Controller may be died prematurely.
+                // TODO(jaewan): Handle this.
+            }
+        });
+    }
+
+    @Override
+    public void getChildren(IMediaSession2Callback caller, String parentId, int page,
+            int pageSize, Bundle extras) throws RuntimeException {
+        final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+        final ControllerInfo controller = getController(caller);
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "getChildren() from a controller that hasn't connected. Ignore");
+            }
+            return;
+        }
+        if (parentId == null) {
+            if (DEBUG) {
+                Log.d(TAG, "parentId shouldn't be null");
+            }
+            return;
+        }
+        if (page < 1 || pageSize < 1) {
+            if (DEBUG) {
+                Log.d(TAG, "Neither page nor pageSize should be less than 1");
+            }
+            return;
+        }
+
+        sessionImpl.getCallbackExecutor().execute(() -> {
+            final MediaLibrarySessionImpl session = getLibrarySession();
+            if (session == null) {
+                return;
+            }
+            final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+            List<MediaItem2> result = session.getCallback().onLoadChildren(
+                    controller, parentId, page, pageSize, extras);
+            if (result != null && result.size() > pageSize) {
+                throw new IllegalArgumentException("onLoadChildren() shouldn't return media items "
+                        + "more than pageSize. result.size()=" + result.size() + " pageSize="
+                        + pageSize);
+            }
+
+            List<Bundle> bundleList = null;
+            if (result != null) {
+                bundleList = new ArrayList<>();
+                for (MediaItem2 item : result) {
+                    bundleList.add(item == null ? null : item.toBundle());
+                }
+            }
+
+            try {
+                controllerImpl.getControllerBinder().onChildrenLoaded(
+                        parentId, page, pageSize, bundleList, extras);
+            } catch (RemoteException e) {
+                // Controller may be died prematurely.
+                // TODO(jaewan): Handle this.
+            }
+        });
+    }
+
+    @Override
+    public void search(IMediaSession2Callback caller, String query, Bundle extras) {
+        final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+        final ControllerInfo controller = getController(caller);
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "search() from a controller that hasn't connected. Ignore");
+            }
+            return;
+        }
+        if (TextUtils.isEmpty(query)) {
+            if (DEBUG) {
+                Log.d(TAG, "query shouldn't be empty");
+            }
+            return;
+        }
+
+        sessionImpl.getCallbackExecutor().execute(() -> {
+            final MediaLibrarySessionImpl session = getLibrarySession();
+            if (session == null) {
+                return;
+            }
+            final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+            session.getCallback().onSearch(controller, query, extras);
+        });
+    }
+
+    @Override
+    public void getSearchResult(IMediaSession2Callback caller, String query, int page,
+            int pageSize, Bundle extras) {
+        final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+        final ControllerInfo controller = getController(caller);
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "getSearchResult() from a controller that hasn't connected. Ignore");
+            }
+            return;
+        }
+        if (TextUtils.isEmpty(query)) {
+            if (DEBUG) {
+                Log.d(TAG, "query shouldn't be empty");
+            }
+            return;
+        }
+        if (page < 1 || pageSize < 1) {
+            if (DEBUG) {
+                Log.d(TAG, "Neither page nor pageSize should be less than 1");
+            }
+            return;
+        }
+
+        sessionImpl.getCallbackExecutor().execute(() -> {
+            final MediaLibrarySessionImpl session = getLibrarySession();
+            if (session == null) {
+                return;
+            }
+            final ControllerInfoImpl controllerImpl = ControllerInfoImpl.from(controller);
+            List<MediaItem2> result = session.getCallback().onLoadSearchResult(
+                    controller, query, page, pageSize, extras);
+            if (result != null && result.size() > pageSize) {
+                throw new IllegalArgumentException("onLoadSearchResult() shouldn't return media "
+                        + "items more than pageSize. result.size()=" + result.size() + " pageSize="
+                        + pageSize);
+            }
+
+            List<Bundle> bundleList = null;
+            if (result != null) {
+                bundleList = new ArrayList<>();
+                for (MediaItem2 item : result) {
+                    bundleList.add(item == null ? null : item.toBundle());
+                }
+            }
+
+            try {
+                controllerImpl.getControllerBinder().onSearchResultLoaded(
+                        query, page, pageSize, bundleList, extras);
+            } catch (RemoteException e) {
+                // Controller may be died prematurely.
+                // TODO(jaewan): Handle this.
+            }
+        });
+    }
+
+    @Override
+    public void subscribe(final IMediaSession2Callback caller, final String parentId,
+            final Bundle option) {
+        final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+        final ControllerInfo controller = getController(caller);
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "subscribe() from a browser that hasn't connected. Ignore");
+            }
+            return;
+        }
+        sessionImpl.getCallbackExecutor().execute(() -> {
+            final MediaLibrarySessionImpl session = getLibrarySession();
+            if (session == null) {
+                return;
+            }
+            session.getCallback().onSubscribed(controller, parentId, option);
+            synchronized (mLock) {
+                Set<String> subscription = mSubscriptions.get(controller);
+                if (subscription == null) {
+                    subscription = new HashSet<>();
+                    mSubscriptions.put(controller, subscription);
+                }
+                subscription.add(parentId);
+            }
+        });
+    }
+
+    @Override
+    public void unsubscribe(final IMediaSession2Callback caller, final String parentId) {
+        final MediaLibrarySessionImpl sessionImpl = getLibrarySession();
+        final ControllerInfo controller = getController(caller);
+        if (controller == null) {
+            if (DEBUG) {
+                Log.d(TAG, "unsubscribe() from a browser that hasn't connected. Ignore");
+            }
+            return;
+        }
+        sessionImpl.getCallbackExecutor().execute(() -> {
+            final MediaLibrarySessionImpl session = getLibrarySession();
+            if (session == null) {
+                return;
+            }
+            session.getCallback().onUnsubscribed(controller, parentId);
+            synchronized (mLock) {
+                mSubscriptions.remove(controller);
+            }
+        });
+    }
+
     //////////////////////////////////////////////////////////////////////////////////////////////
     // APIs for MediaSession2Impl
     //////////////////////////////////////////////////////////////////////////////////////////////
+
     // TODO(jaewan): Need a way to get controller with permissions
     public List<ControllerInfo> getControllers() {
         ArrayList<ControllerInfo> controllers = new ArrayList<>();
@@ -557,11 +807,11 @@
     public void notifyPlaybackStateChangedNotLocked(PlaybackState2 state) {
         final List<ControllerInfo> list = getControllers();
         for (int i = 0; i < list.size(); i++) {
-            IMediaSession2Callback callbackBinder =
+            IMediaSession2Callback controllerBinder =
                     ControllerInfoImpl.from(list.get(i)).getControllerBinder();
             try {
                 final Bundle bundle = state != null ? state.toBundle() : null;
-                callbackBinder.onPlaybackStateChanged(bundle);
+                controllerBinder.onPlaybackStateChanged(bundle);
             } catch (RemoteException e) {
                 Log.w(TAG, "Controller is gone", e);
                 // TODO(jaewan): What to do when the controller is gone?
@@ -572,7 +822,7 @@
     public void notifyCustomLayoutNotLocked(ControllerInfo controller, List<CommandButton> layout) {
         // TODO(jaewan): It's OK to be called while it's connecting, but not OK if the connection
         //               is rejected. Handle the case.
-        IMediaSession2Callback callbackBinder =
+        IMediaSession2Callback controllerBinder =
                 ControllerInfoImpl.from(controller).getControllerBinder();
         try {
             List<Bundle> layoutBundles = new ArrayList<>();
@@ -582,7 +832,7 @@
                     layoutBundles.add(bundle);
                 }
             }
-            callbackBinder.onCustomLayoutChanged(layoutBundles);
+            controllerBinder.onCustomLayoutChanged(layoutBundles);
         } catch (RemoteException e) {
             Log.w(TAG, "Controller is gone", e);
             // TODO(jaewan): What to do when the controller is gone?
@@ -604,10 +854,10 @@
         }
         final List<ControllerInfo> list = getControllers();
         for (int i = 0; i < list.size(); i++) {
-            IMediaSession2Callback callbackBinder =
+            IMediaSession2Callback controllerBinder =
                     ControllerInfoImpl.from(list.get(i)).getControllerBinder();
             try {
-                callbackBinder.onPlaylistChanged(bundleList);
+                controllerBinder.onPlaylistChanged(bundleList);
             } catch (RemoteException e) {
                 Log.w(TAG, "Controller is gone", e);
                 // TODO(jaewan): What to do when the controller is gone?
@@ -618,10 +868,10 @@
     public void notifyPlaylistParamsChanged(MediaSession2.PlaylistParams params) {
         final List<ControllerInfo> list = getControllers();
         for (int i = 0; i < list.size(); i++) {
-            IMediaSession2Callback callbackBinder =
+            IMediaSession2Callback controllerBinder =
                     ControllerInfoImpl.from(list.get(i)).getControllerBinder();
             try {
-                callbackBinder.onPlaylistParamsChanged(params.toBundle());
+                controllerBinder.onPlaylistParamsChanged(params.toBundle());
             } catch (RemoteException e) {
                 Log.w(TAG, "Controller is gone", e);
                 // TODO(jaewan): What to do when the controller is gone?
@@ -632,11 +882,11 @@
     public void notifyPlaybackInfoChanged(MediaController2.PlaybackInfo playbackInfo) {
         final List<ControllerInfo> list = getControllers();
         for (int i = 0; i < list.size(); i++) {
-            IMediaSession2Callback callbackBinder =
+            IMediaSession2Callback controllerBinder =
                     ControllerInfoImpl.from(list.get(i)).getControllerBinder();
             try {
-                callbackBinder.onPlaybackInfoChanged(
-                        ((MediaController2Impl.PlaybackInfoImpl) playbackInfo.getProvider()).toBundle());
+                controllerBinder.onPlaybackInfoChanged(((MediaController2Impl.PlaybackInfoImpl)
+                        playbackInfo.getProvider()).toBundle());
             } catch (RemoteException e) {
                 Log.w(TAG, "Controller is gone", e);
                 // TODO(jaewan): What to do when the controller is gone?
@@ -653,9 +903,9 @@
         if (command == null) {
             throw new IllegalArgumentException("command shouldn't be null");
         }
-        final IMediaSession2Callback callbackBinder =
+        final IMediaSession2Callback controllerBinder =
                 ControllerInfoImpl.from(controller).getControllerBinder();
-        if (getController(callbackBinder) == null) {
+        if (getController(controllerBinder) == null) {
             throw new IllegalArgumentException("Controller is gone");
         }
         sendCustomCommandInternal(controller, command, args, receiver);
@@ -673,14 +923,64 @@
 
     private void sendCustomCommandInternal(ControllerInfo controller, Command command, Bundle args,
             ResultReceiver receiver) {
-        final IMediaSession2Callback callbackBinder =
+        final IMediaSession2Callback controllerBinder =
                 ControllerInfoImpl.from(controller).getControllerBinder();
         try {
             Bundle commandBundle = command.toBundle();
-            callbackBinder.sendCustomCommand(commandBundle, args, receiver);
+            controllerBinder.sendCustomCommand(commandBundle, args, receiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Controller is gone", e);
             // TODO(jaewan): What to do when the controller is gone?
         }
     }
+
+    //////////////////////////////////////////////////////////////////////////////////////////////
+    // APIs for MediaLibrarySessionImpl
+    //////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void notifySearchResultChanged(ControllerInfo controller, String query, int itemCount,
+            Bundle extras) {
+        final IMediaSession2Callback callbackBinder =
+                ControllerInfoImpl.from(controller).getControllerBinder();
+        try {
+            callbackBinder.onSearchResultChanged(query, itemCount, extras);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Controller is gone", e);
+            // TODO(jaewan): What to do when the controller is gone?
+        }
+    }
+
+    public void notifyChildrenChangedNotLocked(ControllerInfo controller, String parentId,
+            int childCount, Bundle extras) {
+        // TODO(jaewan): Handle when controller is disconnected and no longer valid.
+        //               Note: Commands may be sent while onConnected() is running. Should we also
+        //                     consider it as error?
+        notifyChildrenChangedInternalNotLocked(controller, parentId, childCount, extras);
+    }
+
+    public void notifyChildrenChangedNotLocked(String parentId, int childCount, Bundle extras) {
+        final List<ControllerInfo> controllers = getControllers();
+        for (int i = 0; i < controllers.size(); i++) {
+            notifyChildrenChangedInternalNotLocked(controllers.get(i), parentId, childCount,
+                    extras);
+        }
+    }
+
+    public void notifyChildrenChangedInternalNotLocked(final ControllerInfo controller,
+            String parentId, int childCount, Bundle extras) {
+        // Ensure subscription
+        synchronized (mLock) {
+            Set<String> subscriptions = mSubscriptions.get(controller);
+            if (subscriptions == null || !subscriptions.contains(parentId)) {
+                return;
+            }
+        }
+        final IMediaSession2Callback callbackBinder =
+                ControllerInfoImpl.from(controller).getControllerBinder();
+        try {
+            callbackBinder.onChildrenChanged(parentId, childCount, extras);
+        } catch (RemoteException e) {
+            // TODO(jaewan): Handle controller removed?
+        }
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
index 8773df4..aa5ac84 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSessionService2Impl.java
@@ -22,7 +22,7 @@
 import android.app.NotificationManager;
 import android.content.Context;
 import android.content.Intent;
-import android.media.MediaPlayerInterface.PlaybackListener;
+import android.media.MediaPlayerInterface.EventCallback;
 import android.media.MediaSession2;
 import android.media.MediaSessionService2;
 import android.media.MediaSessionService2.MediaNotification;
@@ -42,7 +42,7 @@
     private static final boolean DEBUG = true; // TODO(jaewan): Change this.
 
     private final MediaSessionService2 mInstance;
-    private final PlaybackListener mListener = new SessionServicePlaybackListener();
+    private final EventCallback mCallback = new SessionServiceEventCallback();
 
     private final Object mLock = new Object();
     @GuardedBy("mLock")
@@ -94,7 +94,7 @@
                     + ", but got " + mSession);
         }
         // TODO(jaewan): Uncomment here.
-        // mSession.addPlaybackListener(mListener, mSession.getExecutor());
+        // mSession.registerPlayerEventCallback(mCallback, mSession.getExecutor());
     }
 
     @TokenType int getSessionType() {
@@ -135,9 +135,9 @@
                 mediaNotification.getNotification());
     }
 
-    private class SessionServicePlaybackListener implements PlaybackListener {
+    private class SessionServiceEventCallback implements EventCallback {
         @Override
-        public void onPlaybackChanged(PlaybackState2 state) {
+        public void onPlaybackStateChanged(PlaybackState2 state) {
             if (state == null) {
                 Log.w(TAG, "Ignoring null playback state");
                 return;
diff --git a/packages/MediaComponents/src/com/android/media/PlaybackListenerHolder.java b/packages/MediaComponents/src/com/android/media/PlaybackListenerHolder.java
deleted file mode 100644
index 4241f85..0000000
--- a/packages/MediaComponents/src/com/android/media/PlaybackListenerHolder.java
+++ /dev/null
@@ -1,72 +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.
- */
-
-package com.android.media;
-
-import android.media.MediaPlayerInterface.PlaybackListener;
-import android.media.PlaybackState2;
-import android.os.Handler;
-import android.support.annotation.NonNull;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Holds {@link PlaybackListener} with the {@link Handler}.
- */
-public class PlaybackListenerHolder {
-    public final Executor executor;
-    public final PlaybackListener listener;
-
-    public PlaybackListenerHolder(Executor executor, @NonNull PlaybackListener listener) {
-        this.executor = executor;
-        this.listener = listener;
-    }
-
-    public void postPlaybackChange(final PlaybackState2 state) {
-        executor.execute(() -> listener.onPlaybackChanged(state));
-    }
-
-    /**
-     * Returns {@code true} if the given list contains a {@link PlaybackListenerHolder} that holds
-     * the given listener.
-     *
-     * @param list list to check
-     * @param listener listener to check
-     * @return {@code true} if the given list contains listener. {@code false} otherwise.
-     */
-    public static <Holder extends PlaybackListenerHolder> boolean contains(
-            @NonNull List<Holder> list, PlaybackListener listener) {
-        return indexOf(list, listener) >= 0;
-    }
-
-    /**
-     * Returns the index of the {@link PlaybackListenerHolder} that contains the given listener.
-     *
-     * @param list list to check
-     * @param listener listener to check
-     * @return {@code index} of item if the given list contains listener. {@code -1} otherwise.
-     */
-    public static <Holder extends PlaybackListenerHolder> int indexOf(
-            @NonNull List<Holder> list, PlaybackListener listener) {
-        for (int i = 0; i < list.size(); i++) {
-            if (list.get(i).listener == listener) {
-                return i;
-            }
-        }
-        return -1;
-    }
-}
diff --git a/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java b/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java
index 5eb1129..ee8d6d7 100644
--- a/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/PlaybackState2Impl.java
@@ -30,7 +30,6 @@
     private static final String KEY_BUFFERED_POSITION =
             "android.media.playbackstate2.buffered_position";
     private static final String KEY_SPEED = "android.media.playbackstate2.speed";
-    private static final String KEY_ERROR_MESSAGE = "android.media.playbackstate2.error_message";
     private static final String KEY_UPDATE_TIME = "android.media.playbackstate2.update_time";
     private static final String KEY_ACTIVE_ITEM_ID = "android.media.playbackstate2.active_item_id";
 
@@ -42,11 +41,9 @@
     private final float mSpeed;
     private final long mBufferedPosition;
     private final long mActiveItemId;
-    private final CharSequence mErrorMessage;
 
     public PlaybackState2Impl(Context context, PlaybackState2 instance, int state, long position,
-            long updateTime, float speed, long bufferedPosition, long activeItemId,
-            CharSequence error) {
+            long updateTime, float speed, long bufferedPosition, long activeItemId) {
         mContext = context;
         mInstance = instance;
         mState = state;
@@ -55,7 +52,6 @@
         mUpdateTime = updateTime;
         mBufferedPosition = bufferedPosition;
         mActiveItemId = activeItemId;
-        mErrorMessage = error;
     }
 
     @Override
@@ -67,7 +63,6 @@
         bob.append(", speed=").append(mSpeed);
         bob.append(", updated=").append(mUpdateTime);
         bob.append(", active item id=").append(mActiveItemId);
-        bob.append(", error=").append(mErrorMessage);
         bob.append("}");
         return bob.toString();
     }
@@ -93,11 +88,6 @@
     }
 
     @Override
-    public CharSequence getErrorMessage_impl() {
-        return mErrorMessage;
-    }
-
-    @Override
     public long getLastPositionUpdateTime_impl() {
         return mUpdateTime;
     }
@@ -116,7 +106,6 @@
         bundle.putFloat(KEY_SPEED, mSpeed);
         bundle.putLong(KEY_BUFFERED_POSITION, mBufferedPosition);
         bundle.putLong(KEY_ACTIVE_ITEM_ID, mActiveItemId);
-        bundle.putCharSequence(KEY_ERROR_MESSAGE, mErrorMessage);
         return bundle;
     }
 
@@ -129,18 +118,15 @@
                 || !bundle.containsKey(KEY_UPDATE_TIME)
                 || !bundle.containsKey(KEY_SPEED)
                 || !bundle.containsKey(KEY_BUFFERED_POSITION)
-                || !bundle.containsKey(KEY_ACTIVE_ITEM_ID)
-                || !bundle.containsKey(KEY_ERROR_MESSAGE)) {
+                || !bundle.containsKey(KEY_ACTIVE_ITEM_ID)) {
             return null;
         }
-
         return new PlaybackState2(context,
                 bundle.getInt(KEY_STATE),
                 bundle.getLong(KEY_POSITION),
                 bundle.getLong(KEY_UPDATE_TIME),
                 bundle.getFloat(KEY_SPEED),
                 bundle.getLong(KEY_BUFFERED_POSITION),
-                bundle.getLong(KEY_ACTIVE_ITEM_ID),
-                bundle.getCharSequence(KEY_ERROR_MESSAGE));
+                bundle.getLong(KEY_ACTIVE_ITEM_ID));
     }
 }
\ No newline at end of file
diff --git a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
index b2b7959..f36aa43 100644
--- a/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/SessionToken2Impl.java
@@ -34,6 +34,8 @@
 import android.os.IBinder;
 import android.text.TextUtils;
 
+import java.util.List;
+
 public class SessionToken2Impl implements SessionToken2Provider {
     private static final String KEY_UID = "android.media.token.uid";
     private static final String KEY_TYPE = "android.media.token.type";
@@ -73,25 +75,24 @@
             }
         }
         mUid = uid;
-        // calculate id and type
-        Intent serviceIntent = new Intent(MediaLibraryService2.SERVICE_INTERFACE);
-        serviceIntent.setClassName(packageName, serviceName);
-        String id = getSessionId(manager.resolveService(serviceIntent,
-                PackageManager.GET_META_DATA));
-        int type = TYPE_LIBRARY_SERVICE;
-        if (id == null) {
+
+        // Infer id and type from package name and service name
+        // TODO(jaewan): Handle multi-user.
+        String id = getSessionIdFromService(manager, MediaLibraryService2.SERVICE_INTERFACE,
+                packageName, serviceName);
+        if (id != null) {
+            mId = id;
+            mType = TYPE_LIBRARY_SERVICE;
+        } else {
             // retry with session service
-            serviceIntent.setClassName(packageName, serviceName);
-            id = getSessionId(manager.resolveService(serviceIntent,
-                    PackageManager.GET_META_DATA));
-            type = TYPE_SESSION_SERVICE;
+            mId = getSessionIdFromService(manager, MediaSessionService2.SERVICE_INTERFACE,
+                    packageName, serviceName);
+            mType = TYPE_SESSION_SERVICE;
         }
-        if (id == null) {
+        if (mId == null) {
             throw new IllegalArgumentException("service " + serviceName + " doesn't implement"
-                    + " session service nor library service");
+                    + " session service nor library service. Use service's full name.");
         }
-        mId = id;
-        mType = type;
         mPackageName = packageName;
         mServiceName = serviceName;
         mSessionBinder = null;
@@ -109,6 +110,29 @@
         mInstance = new SessionToken2(this);
     }
 
+    private static String getSessionIdFromService(PackageManager manager, String serviceInterface,
+            String packageName, String serviceName) {
+        Intent serviceIntent = new Intent(serviceInterface);
+        serviceIntent.setPackage(packageName);
+        // Use queryIntentServices to find services with MediaLibraryService2.SERVICE_INTERFACE.
+        // We cannot use resolveService with intent specified class name, because resolveService
+        // ignores actions if Intent.setClassName() is specified.
+        List<ResolveInfo> list = manager.queryIntentServices(
+                serviceIntent, PackageManager.GET_META_DATA);
+        if (list != null) {
+            for (int i = 0; i < list.size(); i++) {
+                ResolveInfo resolveInfo = list.get(i);
+                if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+                    continue;
+                }
+                if (TextUtils.equals(resolveInfo.serviceInfo.name, serviceName)) {
+                    return getSessionId(resolveInfo);
+                }
+            }
+        }
+        return null;
+    }
+
     public static String getSessionId(ResolveInfo resolveInfo) {
         if (resolveInfo == null || resolveInfo.serviceInfo == null) {
             return null;
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 46812e7..994824d 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -44,7 +44,6 @@
 import android.media.MediaSessionService2.MediaNotification;
 import android.media.PlaybackState2;
 import android.media.Rating2;
-import android.media.SessionPlayer2;
 import android.media.SessionToken2;
 import android.media.VolumeProvider2;
 import android.media.update.MediaBrowser2Provider;
@@ -60,7 +59,6 @@
 import android.media.update.MediaSessionService2Provider;
 import android.media.update.MediaSessionService2Provider.MediaNotificationProvider;
 import android.media.update.PlaybackState2Provider;
-import android.media.update.SessionPlayer2Provider;
 import android.media.update.SessionToken2Provider;
 import android.media.update.StaticProvider;
 import android.media.update.VideoView2Provider;
@@ -230,12 +228,6 @@
     }
 
     @Override
-    public SessionPlayer2Provider createSessionPlayer2(Context context, SessionPlayer2 instance) {
-        // TODO(jaewan): Implement this
-        return null;
-    }
-
-    @Override
     public MediaItem2Provider createMediaItem2(Context context, MediaItem2 instance,
             String mediaId, DataSourceDesc dsd, MediaMetadata2 metadata, int flags) {
         return new MediaItem2Impl(context, instance, mediaId, dsd, metadata, flags);
@@ -302,9 +294,9 @@
     @Override
     public PlaybackState2Provider createPlaybackState2(Context context, PlaybackState2 instance,
             int state, long position, long updateTime, float speed, long bufferedPosition,
-            long activeItemId, CharSequence error) {
+            long activeItemId) {
         return new PlaybackState2Impl(context, instance, state, position, updateTime, speed,
-                bufferedPosition, activeItemId, error);
+                bufferedPosition, activeItemId);
     }
 
     @Override
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 318cbf9..e937659 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -33,6 +33,7 @@
 import android.widget.ImageButton;
 import android.widget.MediaControlView2;
 import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
@@ -58,11 +59,15 @@
     static final String KEY_STATE_CONTAINS_SUBTITLE = "StateContainsSubtitle";
     static final String EVENT_UPDATE_SUBTITLE_STATUS = "UpdateSubtitleStatus";
 
+    // TODO: Remove this once integrating with MediaSession2 & MediaMetadata2
+    static final String KEY_STATE_IS_ADVERTISEMENT = "MediaTypeAdvertisement";
+    static final String EVENT_UPDATE_MEDIA_TYPE_STATUS = "UpdateMediaTypeStatus";
+
     private static final int MAX_PROGRESS = 1000;
     private static final int DEFAULT_PROGRESS_UPDATE_TIME_MS = 1000;
-
     private static final int REWIND_TIME_MS = 10000;
     private static final int FORWARD_TIME_MS = 30000;
+    private static final int AD_SKIP_WAIT_TIME_MS = 5000;
 
     private MediaController mController;
     private MediaController.TransportControls mControls;
@@ -71,8 +76,12 @@
     private ProgressBar mProgress;
     private TextView mEndTime, mCurrentTime;
     private TextView mTitleView;
+    private TextView mAdSkipView, mAdRemainingView;
+    private View mAdExternalLink;
+    private View mRoot;
     private int mDuration;
     private int mPrevState;
+    private int mPrevLeftBarWidth;
     private long mPlaybackActions;
     private boolean mDragging;
     private boolean mIsFullScreen;
@@ -81,6 +90,7 @@
     private boolean mSubtitleIsEnabled;
     private boolean mContainsSubtitle;
     private boolean mSeekAvailable;
+    private boolean mIsAdvertisement;
     private ImageButton mPlayPauseButton;
     private ImageButton mFfwdButton;
     private ImageButton mRewButton;
@@ -118,8 +128,9 @@
     @Override
     public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         // Inflate MediaControlView2 from XML
-        View root = makeControllerView();
-        mInstance.addView(root);
+        mRoot = makeControllerView();
+        mRoot.addOnLayoutChangeListener(mTitleBarLayoutChangeListener);
+        mInstance.addView(mRoot);
     }
 
     @Override
@@ -140,6 +151,8 @@
 
     @Override
     public void setButtonVisibility_impl(int button, int visibility) {
+        // TODO: add member variables for Fast-Forward/Prvious/Rewind buttons to save visibility in
+        // order to prevent being overriden inside updateLayout().
         switch (button) {
             case MediaControlView2.BUTTON_PLAY_PAUSE:
                 if (mPlayPauseButton != null && canPause()) {
@@ -421,6 +434,10 @@
         mCurrentTime = v.findViewById(R.id.time_current);
         mFormatBuilder = new StringBuilder();
         mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
+
+        mAdSkipView = v.findViewById(R.id.ad_skip_time);
+        mAdRemainingView = v.findViewById(R.id.ad_remaining);
+        mAdExternalLink = v.findViewById(R.id.ad_external_link);
     }
 
     /**
@@ -505,6 +522,36 @@
             mCurrentTime.setText(stringForTime(currentPosition));
         }
 
+        if (mIsAdvertisement) {
+            // Update the remaining number of seconds until the first 5 seconds of the
+            // advertisement.
+            if (mAdSkipView != null) {
+                if (currentPosition <= AD_SKIP_WAIT_TIME_MS) {
+                    if (mAdSkipView.getVisibility() == View.GONE) {
+                        mAdSkipView.setVisibility(View.VISIBLE);
+                    }
+                    String skipTimeText = ApiHelper.getLibResources().getString(
+                            R.string.MediaControlView2_ad_skip_wait_time,
+                            ((AD_SKIP_WAIT_TIME_MS - currentPosition) / 1000 + 1));
+                    mAdSkipView.setText(skipTimeText);
+                } else {
+                    if (mAdSkipView.getVisibility() == View.VISIBLE) {
+                        mAdSkipView.setVisibility(View.GONE);
+                        mNextButton.setEnabled(true);
+                        mNextButton.clearColorFilter();
+                    }
+                }
+            }
+            // Update the remaining number of seconds of the advertisement.
+            if (mAdRemainingView != null) {
+                int remainingTime =
+                        (mDuration - currentPosition < 0) ? 0 : (mDuration - currentPosition);
+                String remainingTimeText = ApiHelper.getLibResources().getString(
+                        R.string.MediaControlView2_ad_remaining_time,
+                        stringForTime(remainingTime));
+                mAdRemainingView.setText(remainingTimeText);
+            }
+        }
         return currentPosition;
     }
 
@@ -693,6 +740,36 @@
         }
     };
 
+    // The title bar is made up of two separate LinearLayouts. If the sum of the two bars are
+    // greater than the length of the title bar, reduce the size of the left bar (which makes the
+    // TextView that contains the title of the media file shrink).
+    private final View.OnLayoutChangeListener mTitleBarLayoutChangeListener
+            = new View.OnLayoutChangeListener() {
+        @Override
+        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+                int oldTop, int oldRight, int oldBottom) {
+            if (mRoot != null) {
+                int titleBarWidth = mRoot.findViewById(R.id.title_bar).getWidth();
+
+                View leftBar = mRoot.findViewById(R.id.title_bar_left);
+                View rightBar = mRoot.findViewById(R.id.title_bar_right);
+                int leftBarWidth = leftBar.getWidth();
+                int rightBarWidth = rightBar.getWidth();
+
+                RelativeLayout.LayoutParams params =
+                        (RelativeLayout.LayoutParams) leftBar.getLayoutParams();
+                if (leftBarWidth + rightBarWidth > titleBarWidth) {
+                    params.width = titleBarWidth - rightBarWidth;
+                    mPrevLeftBarWidth = leftBarWidth;
+                } else if (leftBarWidth + rightBarWidth < titleBarWidth && mPrevLeftBarWidth != 0) {
+                    params.width = mPrevLeftBarWidth;
+                    mPrevLeftBarWidth = 0;
+                }
+                leftBar.setLayoutParams(params);
+            }
+        }
+    };
+
     private void updateDuration() {
         if (mMetadata != null) {
             if (mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
@@ -711,6 +788,39 @@
         }
     }
 
+    private void updateLayout() {
+        if (mIsAdvertisement) {
+            mRewButton.setVisibility(View.GONE);
+            mFfwdButton.setVisibility(View.GONE);
+            mPrevButton.setVisibility(View.GONE);
+            mCurrentTime.setVisibility(View.GONE);
+            mEndTime.setVisibility(View.GONE);
+
+            mAdSkipView.setVisibility(View.VISIBLE);
+            mAdRemainingView.setVisibility(View.VISIBLE);
+            mAdExternalLink.setVisibility(View.VISIBLE);
+
+            mProgress.setEnabled(false);
+            mNextButton.setEnabled(false);
+            mNextButton.setColorFilter(R.integer.gray);
+        } else {
+            mRewButton.setVisibility(View.VISIBLE);
+            mFfwdButton.setVisibility(View.VISIBLE);
+            mPrevButton.setVisibility(View.VISIBLE);
+            mCurrentTime.setVisibility(View.VISIBLE);
+            mEndTime.setVisibility(View.VISIBLE);
+
+            mAdSkipView.setVisibility(View.GONE);
+            mAdRemainingView.setVisibility(View.GONE);
+            mAdExternalLink.setVisibility(View.GONE);
+
+            mProgress.setEnabled(true);
+            mNextButton.setEnabled(true);
+            mNextButton.clearColorFilter();
+            disableUnsupportedButtons();
+        }
+    }
+
     private class MediaControllerCallback extends MediaController.Callback {
         @Override
         public void onPlaybackStateChanged(PlaybackState state) {
@@ -818,6 +928,12 @@
                     }
                     mContainsSubtitle = newSubtitleStatus;
                 }
+            } else if (event.equals(EVENT_UPDATE_MEDIA_TYPE_STATUS)) {
+                boolean newStatus = extras.getBoolean(KEY_STATE_IS_ADVERTISEMENT);
+                if (newStatus != mIsAdvertisement) {
+                    mIsAdvertisement = newStatus;
+                    updateLayout();
+                }
             }
         }
     }
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index ea7e714..805c262 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -17,9 +17,7 @@
 package com.android.widget;
 
 import android.annotation.NonNull;
-import android.app.AlertDialog;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.res.Resources;
 import android.media.AudioAttributes;
 import android.media.AudioFocusRequest;
@@ -29,6 +27,7 @@
 import android.media.MediaPlayerInterface;
 import android.media.Cea708CaptionRenderer;
 import android.media.ClosedCaptionRenderer;
+import android.media.MediaMetadata2;
 import android.media.Metadata;
 import android.media.PlaybackParams;
 import android.media.SRTRenderer;
@@ -48,6 +47,7 @@
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
@@ -92,13 +92,9 @@
     private AudioAttributes mAudioAttributes;
     private int mAudioFocusType = AudioManager.AUDIOFOCUS_GAIN; // legacy focus gain
 
-    private VideoView2.OnCustomActionListener mOnCustomActionListener;
-    private VideoView2.OnPreparedListener mOnPreparedListener;
-    private VideoView2.OnCompletionListener mOnCompletionListener;
-    private VideoView2.OnErrorListener mOnErrorListener;
-    private VideoView2.OnInfoListener mOnInfoListener;
-    private VideoView2.OnViewTypeChangedListener mOnViewTypeChangedListener;
-    private VideoView2.OnFullScreenRequestListener mOnFullScreenRequestListener;
+    private Pair<Executor, VideoView2.OnCustomActionListener> mCustomActionListenerRecord;
+    private VideoView2.OnViewTypeChangedListener mViewTypeChangedListener;
+    private VideoView2.OnFullScreenRequestListener mFullScreenRequestListener;
 
     private VideoViewInterface mCurrentView;
     private VideoTextureView mTextureView;
@@ -112,6 +108,9 @@
     private MediaRouter mMediaRouter;
     private MediaRouteSelector mRouteSelector;
     private Metadata mMetadata;
+    private MediaMetadata2 mMediaMetadata;
+    private boolean mNeedUpdateMediaType;
+    private Bundle mMediaTypeData;
     private String mTitle;
 
     private PlaybackState.Builder mStateBuilder;
@@ -240,6 +239,32 @@
     }
 
     @Override
+    public MediaMetadata2 getMediaMetadata_impl() {
+        return mMediaMetadata;
+    }
+
+    @Override
+    public void setMediaMetadata_impl(MediaMetadata2 metadata) {
+        // TODO: integrate this with MediaSession2#MediaItem2
+        mMediaMetadata = metadata;
+
+        // TODO: add support for handling website link
+        mMediaTypeData = new Bundle();
+        boolean isAd = metadata == null ?
+                false : metadata.getLong(MediaMetadata2.METADATA_KEY_ADVERTISEMENT) != 0;
+        mMediaTypeData.putBoolean(
+                MediaControlView2Impl.KEY_STATE_IS_ADVERTISEMENT, isAd);
+
+        if (mMediaSession != null) {
+            mMediaSession.sendSessionEvent(
+                    MediaControlView2Impl.EVENT_UPDATE_MEDIA_TYPE_STATUS, mMediaTypeData);
+        } else {
+            // Update later inside OnPreparedListener after MediaSession is initialized.
+            mNeedUpdateMediaType = true;
+        }
+    }
+
+    @Override
     public void setSubtitleEnabled_impl(boolean enable) {
         if (enable != mSubtitleEnabled) {
             selectOrDeselectSubtitle(enable);
@@ -351,13 +376,12 @@
         return mCurrentView.getViewType();
     }
 
-    // TODO: Handle executor properly for all the set listener methods.
     @Override
     public void setCustomActions_impl(
             List<PlaybackState.CustomAction> actionList,
             Executor executor, VideoView2.OnCustomActionListener listener) {
         mCustomActionList = actionList;
-        mOnCustomActionListener = listener;
+        mCustomActionListenerRecord = new Pair<>(executor, listener);
 
         // Create a new playback builder in order to clear existing the custom actions.
         mStateBuilder = null;
@@ -365,35 +389,13 @@
     }
 
     @Override
-    public void setOnPreparedListener_impl(Executor executor, VideoView2.OnPreparedListener l) {
-        mOnPreparedListener = l;
+    public void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l) {
+        mViewTypeChangedListener = l;
     }
 
     @Override
-    public void setOnCompletionListener_impl(Executor executor, VideoView2.OnCompletionListener l) {
-        mOnCompletionListener = l;
-    }
-
-    @Override
-    public void setOnErrorListener_impl(Executor executor, VideoView2.OnErrorListener l) {
-        mOnErrorListener = l;
-    }
-
-    @Override
-    public void setOnInfoListener_impl(Executor executor, VideoView2.OnInfoListener l) {
-        mOnInfoListener = l;
-    }
-
-    @Override
-    public void setOnViewTypeChangedListener_impl(Executor executor,
-            VideoView2.OnViewTypeChangedListener l) {
-        mOnViewTypeChangedListener = l;
-    }
-
-    @Override
-    public void setFullScreenRequestListener_impl(Executor executor,
-            VideoView2.OnFullScreenRequestListener l) {
-        mOnFullScreenRequestListener = l;
+    public void setFullScreenRequestListener_impl(VideoView2.OnFullScreenRequestListener l) {
+        mFullScreenRequestListener = l;
     }
 
     @Override
@@ -492,8 +494,8 @@
             Log.d(TAG, "onSurfaceTakeOverDone(). Now current view is: " + view);
         }
         mCurrentView = view;
-        if (mOnViewTypeChangedListener != null) {
-            mOnViewTypeChangedListener.onViewTypeChanged(mInstance, view.getViewType());
+        if (mViewTypeChangedListener != null) {
+            mViewTypeChangedListener.onViewTypeChanged(mInstance, view.getViewType());
         }
         if (needToStart()) {
             mMediaController.getTransportControls().play();
@@ -845,9 +847,6 @@
             updatePlaybackState();
             extractSubtitleTracks();
 
-            if (mOnPreparedListener != null) {
-                mOnPreparedListener.onPrepared(mInstance);
-            }
             if (mMediaControlView != null) {
                 mMediaControlView.setEnabled(true);
             }
@@ -897,6 +896,13 @@
 
             if (mMediaSession != null) {
                 mMediaSession.setMetadata(builder.build());
+
+                // TODO: merge this code with the above code when integrating with MediaSession2.
+                if (mNeedUpdateMediaType) {
+                    mMediaSession.sendSessionEvent(
+                            MediaControlView2Impl.EVENT_UPDATE_MEDIA_TYPE_STATUS, mMediaTypeData);
+                    mNeedUpdateMediaType = false;
+                }
             }
         }
     };
@@ -908,9 +914,6 @@
                     mTargetState = STATE_PLAYBACK_COMPLETED;
                     updatePlaybackState();
 
-                    if (mOnCompletionListener != null) {
-                        mOnCompletionListener.onCompletion(mInstance);
-                    }
                     if (mAudioFocusType != AudioManager.AUDIOFOCUS_NONE) {
                         mAudioManager.abandonAudioFocus(null);
                     }
@@ -920,10 +923,6 @@
     private MediaPlayer.OnInfoListener mInfoListener =
             new MediaPlayer.OnInfoListener() {
                 public boolean onInfo(MediaPlayer mp, int what, int extra) {
-                    if (mOnInfoListener != null) {
-                        mOnInfoListener.onInfo(mInstance, what, extra);
-                    }
-
                     if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
                         extractSubtitleTracks();
                     }
@@ -944,47 +943,6 @@
                     if (mMediaControlView != null) {
                         mMediaControlView.setVisibility(View.GONE);
                     }
-
-                    /* If an error handler has been supplied, use it and finish. */
-                    if (mOnErrorListener != null) {
-                        if (mOnErrorListener.onError(mInstance, frameworkErr, implErr)) {
-                            return true;
-                        }
-                    }
-
-                    /* Otherwise, pop up an error dialog so the user knows that
-                     * something bad has happened. Only try and pop up the dialog
-                     * if we're attached to a window. When we're going away and no
-                     * longer have a window, don't bother showing the user an error.
-                    */
-                    if (mInstance.getWindowToken() != null) {
-                        int messageId;
-
-                        if (frameworkErr
-                                == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
-                            messageId = R.string.VideoView2_error_text_invalid_progressive_playback;
-                        } else {
-                            messageId = R.string.VideoView2_error_text_unknown;
-                        }
-
-                        Resources res = ApiHelper.getLibResources();
-                        new AlertDialog.Builder(mInstance.getContext())
-                                .setMessage(res.getString(messageId))
-                                .setPositiveButton(res.getString(R.string.VideoView2_error_button),
-                                        new DialogInterface.OnClickListener() {
-                                            public void onClick(DialogInterface dialog,
-                                                    int whichButton) {
-                                                /* If we get here, there is no onError listener, so
-                                                * at least inform them that the video is over.
-                                                */
-                                                if (mOnCompletionListener != null) {
-                                                    mOnCompletionListener.onCompletion(mInstance);
-                                                }
-                                            }
-                                        })
-                                .setCancelable(false)
-                                .show();
-                    }
                     return true;
                 }
             };
@@ -1020,8 +978,8 @@
                         mInstance.setSubtitleEnabled(false);
                         break;
                     case MediaControlView2.COMMAND_SET_FULLSCREEN:
-                        if (mOnFullScreenRequestListener != null) {
-                            mOnFullScreenRequestListener.onFullScreenRequest(
+                        if (mFullScreenRequestListener != null) {
+                            mFullScreenRequestListener.onFullScreenRequest(
                                     mInstance,
                                     args.getBoolean(MediaControlView2Impl.ARGUMENT_KEY_FULLSCREEN));
                         }
@@ -1033,7 +991,8 @@
 
         @Override
         public void onCustomAction(String action, Bundle extras) {
-            mOnCustomActionListener.onCustomAction(action, extras);
+            mCustomActionListenerRecord.first.execute(() ->
+                    mCustomActionListenerRecord.second.onCustomAction(action, extras));
             showController();
         }
 
diff --git a/packages/MediaComponents/test/AndroidManifest.xml b/packages/MediaComponents/test/AndroidManifest.xml
index 48e4292..5ebe31a 100644
--- a/packages/MediaComponents/test/AndroidManifest.xml
+++ b/packages/MediaComponents/test/AndroidManifest.xml
@@ -34,7 +34,7 @@
             <intent-filter>
                 <action android:name="android.media.MediaLibraryService2" />
             </intent-filter>
-            <meta-data android:name="android.media.session" android:value="TestBrowser" />
+            <meta-data android:name="android.media.session" android:value="TestLibrary" />
         </service>
     </application>
 
diff --git a/packages/MediaComponents/test/runtest.sh b/packages/MediaComponents/test/runtest.sh
index 920fa96..edce230 100644
--- a/packages/MediaComponents/test/runtest.sh
+++ b/packages/MediaComponents/test/runtest.sh
@@ -146,9 +146,10 @@
         fi
         target_dir=$(dirname ${target_dir})
         local package=$(sed -n 's/^.*\bpackage\b="\([a-z0-9\._]*\)".*$/\1/p' ${target_dir}/AndroidManifest.xml)
-        local apk_path=$(find ${OUT} -name ${target}.apk)
-        if [[ -z "${apk_path}" ]]; then
-          echo "Cannot locate ${target}.apk" && break
+        local apk_path=$(find ${OUT}/system ${OUT}/data -name ${target}.apk)
+        local apk_num=$(find ${OUT}/system ${OUT}/data -name ${target}.apk | wc -l)
+        if [[ "${apk_num}" != "1" ]]; then
+          echo "Cannot locate a ${target}.apk. Found ${apk_num} apks" && break
         fi
         echo "Installing ${target}.apk. path=${apk_path}"
         ${adb} install -r ${apk_path}
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index eff4c3b..7e93232 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -18,17 +18,24 @@
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.fail;
 
 import android.annotation.Nullable;
 import android.content.Context;
 import android.media.MediaBrowser2.BrowserCallback;
+import android.media.MediaLibraryService2.MediaLibrarySession;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
+import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.PlaylistParams;
+import android.media.TestServiceRegistry.SessionCallbackProxy;
 import android.os.Bundle;
 import android.os.ResultReceiver;
+import android.os.Process;
 import android.support.annotation.CallSuper;
 import android.support.annotation.NonNull;
 import android.support.test.filters.SmallTest;
@@ -65,6 +72,13 @@
     interface TestBrowserCallbackInterface extends TestControllerCallbackInterface {
         // Browser specific callbacks
         default void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra) {}
+        default void onItemLoaded(String mediaId, MediaItem2 result) {}
+        default void onChildrenChanged(String parentId, int childCount, Bundle extras) {}
+        default void onChildrenLoaded(String parentId, int page, int pageSize,
+                List<MediaItem2> result, Bundle extras) {}
+        default void onSearchResultChanged(String query, int itemCount, Bundle extras) {}
+        default void onSearchResultLoaded(String query, int page, int pageSize,
+                List<MediaItem2> result, Bundle extras) {}
     }
 
     @Test
@@ -78,7 +92,7 @@
             public void onGetRootResult(Bundle rootHints, String rootMediaId, Bundle rootExtra) {
                 assertTrue(TestUtils.equals(param, rootHints));
                 assertEquals(MockMediaLibraryService2.ROOT_ID, rootMediaId);
-                assertTrue(TestUtils.equals(MockMediaLibraryService2.EXTRA, rootExtra));
+                assertTrue(TestUtils.equals(MockMediaLibraryService2.EXTRAS, rootExtra));
                 latch.countDown();
             }
         };
@@ -90,6 +104,346 @@
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
     }
 
+    @Test
+    public void testGetItem() throws InterruptedException {
+        final String mediaId = MockMediaLibraryService2.MEDIA_ID_GET_ITEM;
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onItemLoaded(String mediaIdOut, MediaItem2 result) {
+                assertEquals(mediaId, mediaIdOut);
+                assertNotNull(result);
+                assertEquals(mediaId, result.getMediaId());
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getItem(mediaId);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetItemNullResult() throws InterruptedException {
+        final String mediaId = "random_media_id";
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onItemLoaded(String mediaIdOut, MediaItem2 result) {
+                assertEquals(mediaId, mediaIdOut);
+                assertNull(result);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getItem(mediaId);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetChildren() throws InterruptedException {
+        final String parentId = MockMediaLibraryService2.PARENT_ID;
+        final int page = 4;
+        final int pageSize = 10;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onChildrenLoaded(String parentIdOut, int pageOut, int pageSizeOut,
+                    List<MediaItem2> result, Bundle extrasOut) {
+                assertEquals(parentId, parentIdOut);
+                assertEquals(page, pageOut);
+                assertEquals(pageSize, pageSizeOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertNotNull(result);
+
+                int fromIndex = (page - 1) * pageSize;
+                int toIndex = Math.min(page * pageSize, MockMediaLibraryService2.CHILDREN_COUNT);
+
+                // Compare the given results with originals.
+                for (int originalIndex = fromIndex; originalIndex < toIndex; originalIndex++) {
+                    int relativeIndex = originalIndex - fromIndex;
+                    assertEquals(
+                            MockMediaLibraryService2.GET_CHILDREN_RESULT.get(originalIndex)
+                                    .getMediaId(),
+                            result.get(relativeIndex).getMediaId());
+                }
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getChildren(parentId, page, pageSize, extras);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetChildrenEmptyResult() throws InterruptedException {
+        final String parentId = MockMediaLibraryService2.PARENT_ID_NO_CHILDREN;
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onChildrenLoaded(String parentIdOut, int pageOut, int pageSizeOut,
+                    List<MediaItem2> result, Bundle extrasOut) {
+                assertNotNull(result);
+                assertEquals(0, result.size());
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getChildren(parentId, 1, 1, null);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetChildrenNullResult() throws InterruptedException {
+        final String parentId = MockMediaLibraryService2.PARENT_ID_ERROR;
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onChildrenLoaded(String parentIdOut, int pageOut, int pageSizeOut,
+                    List<MediaItem2> result, Bundle extrasOut) {
+                assertNull(result);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.getChildren(parentId, 1, 1, null);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSearch() throws InterruptedException {
+        final String query = MockMediaLibraryService2.SEARCH_QUERY;
+        final int page = 4;
+        final int pageSize = 10;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latchForSearch = new CountDownLatch(1);
+        final CountDownLatch latchForGetSearchResult = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onSearchResultChanged(String queryOut, int itemCount, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertEquals(MockMediaLibraryService2.SEARCH_RESULT_COUNT, itemCount);
+                latchForSearch.countDown();
+            }
+
+            @Override
+            public void onSearchResultLoaded(String queryOut, int pageOut, int pageSizeOut,
+                    List<MediaItem2> result, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertEquals(page, pageOut);
+                assertEquals(pageSize, pageSizeOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertNotNull(result);
+
+                int fromIndex = (page - 1) * pageSize;
+                int toIndex = Math.min(
+                        page * pageSize, MockMediaLibraryService2.SEARCH_RESULT_COUNT);
+
+                // Compare the given results with originals.
+                for (int originalIndex = fromIndex; originalIndex < toIndex; originalIndex++) {
+                    int relativeIndex = originalIndex - fromIndex;
+                    assertEquals(
+                            MockMediaLibraryService2.SEARCH_RESULT.get(originalIndex).getMediaId(),
+                            result.get(relativeIndex).getMediaId());
+                }
+                latchForGetSearchResult.countDown();
+            }
+        };
+
+        // Request the search.
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.search(query, extras);
+        assertTrue(latchForSearch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+        // Get the search result.
+        browser.getSearchResult(query, page, pageSize, extras);
+        assertTrue(latchForGetSearchResult.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSearchTakesTime() throws InterruptedException {
+        final String query = MockMediaLibraryService2.SEARCH_QUERY_TAKES_TIME;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onSearchResultChanged(String queryOut, int itemCount, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertEquals(MockMediaLibraryService2.SEARCH_RESULT_COUNT, itemCount);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.search(query, extras);
+        assertTrue(latch.await(
+                MockMediaLibraryService2.SEARCH_TIME_IN_MS + WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSearchEmptyResult() throws InterruptedException {
+        final String query = MockMediaLibraryService2.SEARCH_QUERY_EMPTY_RESULT;
+        final Bundle extras = new Bundle();
+        extras.putString(TAG, TAG);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestBrowserCallbackInterface() {
+            @Override
+            public void onSearchResultChanged(String queryOut, int itemCount, Bundle extrasOut) {
+                assertEquals(query, queryOut);
+                assertTrue(TestUtils.equals(extras, extrasOut));
+                assertEquals(0, itemCount);
+                latch.countDown();
+            }
+        };
+
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token, true, callback);
+        browser.search(query, extras);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSubscribe() throws InterruptedException {
+        final String testParentId = "testSubscribeId";
+        final Bundle testExtras = new Bundle();
+        testExtras.putString(testParentId, testParentId);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallbackProxy callbackProxy = new SessionCallbackProxy(mContext) {
+            @Override
+            public void onSubscribed(ControllerInfo info, String parentId, Bundle extras) {
+                if (Process.myUid() == info.getUid()) {
+                    assertEquals(testParentId, parentId);
+                    assertTrue(TestUtils.equals(testExtras, extras));
+                    latch.countDown();
+                }
+            }
+        };
+        TestServiceRegistry.getInstance().setSessionCallbackProxy(callbackProxy);
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token);
+        browser.subscribe(testParentId, testExtras);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testUnsubscribe() throws InterruptedException {
+        final String testParentId = "testUnsubscribeId";
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallbackProxy callbackProxy = new SessionCallbackProxy(mContext) {
+            @Override
+            public void onUnsubscribed(ControllerInfo info, String parentId) {
+                if (Process.myUid() == info.getUid()) {
+                    assertEquals(testParentId, parentId);
+                    latch.countDown();
+                }
+            }
+        };
+        TestServiceRegistry.getInstance().setSessionCallbackProxy(callbackProxy);
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        MediaBrowser2 browser = (MediaBrowser2) createController(token);
+        browser.unsubscribe(testParentId);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testBrowserCallback_notifyChildrenChanged() throws InterruptedException {
+        // TODO(jaewan): Add test for the notifyChildrenChanged itself.
+        final String testParentId1 = "testBrowserCallback_notifyChildrenChanged_unexpectedParent";
+        final String testParentId2 = "testBrowserCallback_notifyChildrenChanged";
+        final int testChildrenCount = 101;
+        final Bundle testExtras = new Bundle();
+        testExtras.putString(testParentId1, testParentId1);
+
+        final CountDownLatch latch = new CountDownLatch(3);
+        final SessionCallbackProxy sessionCallbackProxy = new SessionCallbackProxy(mContext) {
+            @Override
+            public CommandGroup onConnect(ControllerInfo controller) {
+                final MockMediaLibraryService2 service = (MockMediaLibraryService2)
+                        TestServiceRegistry.getInstance().getServiceInstance();
+                final MediaLibrarySession session = (MediaLibrarySession) service.getSession();
+                // Shouldn't trigger onChildrenChanged() for the browser, because it hasn't
+                // subscribed.
+                session.notifyChildrenChanged(testParentId1, testChildrenCount, null);
+                session.notifyChildrenChanged(controller, testParentId1, testChildrenCount, null);
+                return super.onConnect(controller);
+            }
+
+            @Override
+            public void onSubscribed(ControllerInfo info, String parentId, Bundle extras) {
+                if (Process.myUid() == info.getUid()) {
+                    final MediaLibrarySession session =  (MediaLibrarySession) mSession;
+                    session.notifyChildrenChanged(testParentId2, testChildrenCount, null);
+                    session.notifyChildrenChanged(info, testParentId2, testChildrenCount,
+                            testExtras);
+                }
+            }
+        };
+        final TestBrowserCallbackInterface controllerCallbackProxy =
+                new TestBrowserCallbackInterface() {
+                    @Override
+                    public void onChildrenChanged(String parentId, int childCount,
+                            Bundle extras) {
+                        switch ((int) latch.getCount()) {
+                            case 3:
+                                assertEquals(testParentId2, parentId);
+                                assertEquals(testChildrenCount, childCount);
+                                assertNull(extras);
+                                latch.countDown();
+                                break;
+                            case 2:
+                                assertEquals(testParentId2, parentId);
+                                assertEquals(testChildrenCount, childCount);
+                                assertTrue(TestUtils.equals(testExtras, extras));
+                                latch.countDown();
+                                break;
+                            default:
+                                // Unexpected call.
+                                fail();
+                        }
+                    }
+                };
+        TestServiceRegistry.getInstance().setSessionCallbackProxy(sessionCallbackProxy);
+        final SessionToken2 token = MockMediaLibraryService2.getToken(mContext);
+        final MediaBrowser2 browser = (MediaBrowser2) createController(
+                token, true, controllerCallbackProxy);
+        final MockMediaLibraryService2 service =
+                (MockMediaLibraryService2) TestServiceRegistry.getInstance().getServiceInstance();
+        if (mSession != null) {
+            mSession.close();
+        }
+        mSession = service.getSession();
+        assertTrue(mSession instanceof MediaLibrarySession);
+        browser.subscribe(testParentId2, null);
+        // This ensures that onChildrenChanged() is only called for the expected reasons.
+        assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+    }
+
     public static class TestBrowserCallback extends BrowserCallback
             implements WaitForConnectionInterface {
         private final TestControllerCallbackInterface mCallbackProxy;
@@ -151,6 +505,52 @@
         }
 
         @Override
+        public void onItemLoaded(String mediaId, MediaItem2 result) {
+            super.onItemLoaded(mediaId, result);
+            if (mCallbackProxy instanceof TestBrowserCallbackInterface) {
+                ((TestBrowserCallbackInterface) mCallbackProxy).onItemLoaded(mediaId, result);
+            }
+        }
+
+        @Override
+        public void onChildrenLoaded(String parentId, int page, int pageSize,
+                List<MediaItem2> result, Bundle extras) {
+            super.onChildrenLoaded(parentId, page, pageSize, result, extras);
+            if (mCallbackProxy instanceof TestBrowserCallbackInterface) {
+                ((TestBrowserCallbackInterface) mCallbackProxy)
+                        .onChildrenLoaded(parentId, page, pageSize, result, extras);
+            }
+        }
+
+        @Override
+        public void onSearchResultChanged(String query, int itemCount, Bundle extras) {
+            super.onSearchResultChanged(query, itemCount, extras);
+            if (mCallbackProxy instanceof TestBrowserCallbackInterface) {
+                ((TestBrowserCallbackInterface) mCallbackProxy)
+                        .onSearchResultChanged(query, itemCount, extras);
+            }
+        }
+
+        @Override
+        public void onSearchResultLoaded(String query, int page, int pageSize,
+                List<MediaItem2> result, Bundle extras) {
+            super.onSearchResultLoaded(query, page, pageSize, result, extras);
+            if (mCallbackProxy instanceof TestBrowserCallbackInterface) {
+                ((TestBrowserCallbackInterface) mCallbackProxy)
+                        .onSearchResultLoaded(query, page, pageSize, result, extras);
+            }
+        }
+
+        @Override
+        public void onChildrenChanged(String parentId, int childCount, Bundle extras) {
+            super.onChildrenChanged(parentId, childCount, extras);
+            if (mCallbackProxy instanceof TestBrowserCallbackInterface) {
+                ((TestBrowserCallbackInterface) mCallbackProxy)
+                        .onChildrenChanged(parentId, childCount, extras);
+            }
+        }
+
+        @Override
         public void waitForConnect(boolean expect) throws InterruptedException {
             if (expect) {
                 assertTrue(connectLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
@@ -183,4 +583,4 @@
             return mCallback;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/MediaComponents/test/src/android/media/MediaController2Test.java b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
index 07baf58..e162f1d 100644
--- a/packages/MediaComponents/test/src/android/media/MediaController2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
@@ -19,11 +19,13 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.media.MediaPlayerInterface.PlaybackListener;
+import android.media.MediaPlayerInterface.EventCallback;
 import android.media.MediaSession2.Command;
+import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.PlaylistParams;
 import android.media.MediaSession2.SessionCallback;
+import android.media.TestServiceRegistry.SessionCallbackProxy;
 import android.media.TestUtils.SyncHandler;
 import android.net.Uri;
 import android.os.Bundle;
@@ -37,7 +39,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,7 +60,6 @@
 @FlakyTest
 public class MediaController2Test extends MediaSession2TestBase {
     private static final String TAG = "MediaController2Test";
-    private static final int DEFAULT_RATING_TYPE = Rating2.RATING_5_STARS;
 
     PendingIntent mIntent;
     MediaSession2 mSession;
@@ -77,7 +77,6 @@
         mPlayer = new MockPlayer(1);
         mSession = new MediaSession2.Builder(mContext, mPlayer)
                 .setSessionCallback(sHandlerExecutor, new SessionCallback(mContext))
-                .setRatingType(DEFAULT_RATING_TYPE)
                 .setSessionActivity(mIntent)
                 .setId(TAG).build();
         mController = createController(mSession.getToken());
@@ -209,11 +208,6 @@
     }
 
     @Test
-    public void testGetRatingType() throws InterruptedException {
-        assertEquals(DEFAULT_RATING_TYPE, mController.getRatingType());
-    }
-
-    @Test
     public void testGetSessionActivity() throws InterruptedException {
         PendingIntent sessionActivity = mController.getSessionActivity();
         assertEquals(mContext.getPackageName(), sessionActivity.getCreatorPackage());
@@ -388,7 +382,7 @@
                 assertEquals(mContext.getPackageName(), controller.getPackageName());
                 assertEquals(request, query);
                 assertTrue(TestUtils.equals(bundle, extras));
-                latch.countDown();;
+                latch.countDown();
             }
         };
         try (MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
@@ -412,7 +406,7 @@
                 assertEquals(mContext.getPackageName(), controller.getPackageName());
                 assertEquals(request, uri);
                 assertTrue(TestUtils.equals(bundle, extras));
-                latch.countDown();;
+                latch.countDown();
             }
         };
         try (MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
@@ -436,7 +430,7 @@
                 assertEquals(mContext.getPackageName(), controller.getPackageName());
                 assertEquals(request, id);
                 assertTrue(TestUtils.equals(bundle, extras));
-                latch.countDown();;
+                latch.countDown();
             }
         };
         try (MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
@@ -457,11 +451,12 @@
         final CountDownLatch latch = new CountDownLatch(1);
         final SessionCallback callback = new SessionCallback(mContext) {
             @Override
-            public void onPrepareFromSearch(ControllerInfo controller, String query, Bundle extras) {
+            public void onPrepareFromSearch(ControllerInfo controller, String query,
+                    Bundle extras) {
                 assertEquals(mContext.getPackageName(), controller.getPackageName());
                 assertEquals(request, query);
                 assertTrue(TestUtils.equals(bundle, extras));
-                latch.countDown();;
+                latch.countDown();
             }
         };
         try (MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
@@ -485,7 +480,7 @@
                 assertEquals(mContext.getPackageName(), controller.getPackageName());
                 assertEquals(request, uri);
                 assertTrue(TestUtils.equals(bundle, extras));
-                latch.countDown();;
+                latch.countDown();
             }
         };
         try (MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
@@ -509,7 +504,7 @@
                 assertEquals(mContext.getPackageName(), controller.getPackageName());
                 assertEquals(request, id);
                 assertTrue(TestUtils.equals(bundle, extras));
-                latch.countDown();;
+                latch.countDown();
             }
         };
         try (MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
@@ -522,6 +517,34 @@
     }
 
     @Test
+    public void testSetRating() throws InterruptedException {
+        final int ratingType = Rating2.RATING_5_STARS;
+        final float ratingValue = 3.5f;
+        final Rating2 rating = Rating2.newStarRating(mContext, ratingType, ratingValue);
+        final String mediaId = "media_id";
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallback callback = new SessionCallback(mContext) {
+            @Override
+            public void onSetRating(ControllerInfo controller, String mediaIdOut,
+                    Rating2 ratingOut) {
+                assertEquals(mContext.getPackageName(), controller.getPackageName());
+                assertEquals(mediaId, mediaIdOut);
+                assertEquals(rating, ratingOut);
+                latch.countDown();
+            }
+        };
+
+        try (MediaSession2 session = new MediaSession2.Builder(mContext, mPlayer)
+                .setSessionCallback(sHandlerExecutor, callback)
+                .setId("testSetRating").build()) {
+            MediaController2 controller = createController(session.getToken());
+            controller.setRating(mediaId, rating);
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        }
+    }
+
+    @Test
     public void testIsConnected() throws InterruptedException {
         assertTrue(mController.isConnected());
         sHandler.postAndSync(()->{
@@ -598,7 +621,6 @@
         }
     }
 
-    @Ignore
     @Test
     public void testGetServiceToken() {
         SessionToken2 token = TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID);
@@ -609,33 +631,40 @@
     }
 
     private void connectToService(SessionToken2 token) throws InterruptedException {
+        if (mSession != null) {
+            mSession.close();
+        }
         mController = createController(token);
         mSession = TestServiceRegistry.getInstance().getServiceInstance().getSession();
         mPlayer = (MockPlayer) mSession.getPlayer();
     }
 
-    // TODO(jaewan): Reenable when session manager detects app installs
-    @Ignore
     @Test
     public void testConnectToService_sessionService() throws InterruptedException {
-        connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
-        testConnectToService();
+        testConnectToService(MockMediaSessionService2.ID);
     }
 
-    // TODO(jaewan): Reenable when session manager detects app installs
-    @Ignore
     @Test
     public void testConnectToService_libraryService() throws InterruptedException {
-        connectToService(TestUtils.getServiceToken(mContext, MockMediaLibraryService2.ID));
-        testConnectToService();
+        testConnectToService(MockMediaLibraryService2.ID);
     }
 
-    public void testConnectToService() throws InterruptedException {
-        TestServiceRegistry serviceInfo = TestServiceRegistry.getInstance();
-        ControllerInfo info = serviceInfo.getOnConnectControllerInfo();
-        assertEquals(mContext.getPackageName(), info.getPackageName());
-        assertEquals(Process.myUid(), info.getUid());
-        assertFalse(info.isTrusted());
+    public void testConnectToService(String id) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        final SessionCallbackProxy proxy = new SessionCallbackProxy(mContext) {
+            @Override
+            public CommandGroup onConnect(ControllerInfo controller) {
+                if (Process.myUid() == controller.getUid()) {
+                    assertEquals(mContext.getPackageName(), controller.getPackageName());
+                    assertFalse(controller.isTrusted());
+                    latch.countDown();
+                }
+                return super.onConnect(controller);
+            }
+        };
+        TestServiceRegistry.getInstance().setSessionCallbackProxy(proxy);
+        connectToService(TestUtils.getServiceToken(mContext, id));
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         // Test command from controller to session service
         mController.play();
@@ -646,7 +675,7 @@
         // TODO(jaewan): Add equivalent tests again
         /*
         final CountDownLatch latch = new CountDownLatch(1);
-        mController.addPlaybackListener((state) -> {
+        mController.registerPlayerEventCallback((state) -> {
             assertNotNull(state);
             assertEquals(PlaybackState.STATE_REWINDING, state.getState());
             latch.countDown();
@@ -657,15 +686,11 @@
         */
     }
 
-    // TODO(jaewan): Re-enable after b/72792686 is fixed
-    @Ignore
     @Test
     public void testControllerAfterSessionIsGone_session() throws InterruptedException {
         testControllerAfterSessionIsGone(mSession.getToken().getId());
     }
 
-    // TODO(jaewan): Re-enable after b/72792686 is fixed
-    @Ignore
     @Test
     public void testControllerAfterSessionIsGone_sessionService() throws InterruptedException {
         connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
@@ -697,31 +722,26 @@
         testControllerAfterSessionIsGone(id);
     }
 
-    // TODO(jaewan): Reenable when session manager detects app installs
-    @Ignore
     @Test
     public void testClose_sessionService() throws InterruptedException {
-        connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
-        testCloseFromService();
+        testCloseFromService(MockMediaSessionService2.ID);
     }
 
-    // TODO(jaewan): Reenable when session manager detects app installs
-    @Ignore
     @Test
     public void testClose_libraryService() throws InterruptedException {
-        connectToService(TestUtils.getServiceToken(mContext, MockMediaSessionService2.ID));
-        testCloseFromService();
+        testCloseFromService(MockMediaLibraryService2.ID);
     }
 
-    private void testCloseFromService() throws InterruptedException {
-        final String id = mController.getSessionToken().getId();
+    private void testCloseFromService(String id) throws InterruptedException {
         final CountDownLatch latch = new CountDownLatch(1);
-        TestServiceRegistry.getInstance().setServiceInstanceChangedCallback((service) -> {
-            if (service == null) {
-                // Destroying..
+        final SessionCallbackProxy proxy = new SessionCallbackProxy(mContext) {
+            @Override
+            public void onServiceDestroyed() {
                 latch.countDown();
             }
-        });
+        };
+        TestServiceRegistry.getInstance().setSessionCallbackProxy(proxy);
+        mController = createController(TestUtils.getServiceToken(mContext, id));
         mController.close();
         // Wait until close triggers onDestroy() of the session service.
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
@@ -741,7 +761,7 @@
         waitForDisconnect(mController, true);
         testNoInteraction();
 
-        // Test with the newly created session.
+        // Ensure that the controller cannot use newly create session with the same ID.
         sHandler.postAndSync(() -> {
             // Recreated session has different session stub, so previously created controller
             // shouldn't be available.
@@ -754,16 +774,19 @@
 
     private void testNoInteraction() throws InterruptedException {
         final CountDownLatch latch = new CountDownLatch(1);
-        final PlaybackListener playbackListener = (state) -> {
-            fail("Controller shouldn't be notified about change in session after the close.");
-            latch.countDown();
+        final EventCallback callback = new EventCallback() {
+            @Override
+            public void onPlaybackStateChanged(PlaybackState2 state) {
+                fail("Controller shouldn't be notified about change in session after the close.");
+                latch.countDown();
+            }
         };
         // TODO(jaewan): Add equivalent tests again
         /*
-        mController.addPlaybackListener(playbackListener, sHandler);
+        mController.registerPlayerEventCallback(playbackListener, sHandler);
         mPlayer.notifyPlaybackState(TestUtils.createPlaybackState(PlaybackState.STATE_BUFFERING));
         assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        mController.removePlaybackListener(playbackListener);
+        mController.unregisterPlayerEventCallback(playbackListener);
         */
     }
 
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index f5ac6aa..9de4ce7 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -28,9 +28,8 @@
 import static org.junit.Assert.fail;
 
 import android.content.Context;
-import android.media.AudioManager;
 import android.media.MediaController2.PlaybackInfo;
-import android.media.MediaPlayerInterface.PlaybackListener;
+import android.media.MediaPlayerInterface.EventCallback;
 import android.media.MediaSession2.Builder;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
@@ -49,7 +48,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -253,51 +251,67 @@
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
     }
 
-    // TODO(jaewan): Re-enable test..
-    @Ignore
     @Test
-    public void testPlaybackStateChangedListener() throws InterruptedException {
-        final CountDownLatch latch = new CountDownLatch(2);
+    public void testRegisterEventCallback() throws InterruptedException {
+        final int testWhat = 1001;
         final MockPlayer player = new MockPlayer(0);
-        final PlaybackListener listener = (state) -> {
-            assertEquals(sHandler.getLooper(), Looper.myLooper());
-            assertNotNull(state);
-            switch ((int) latch.getCount()) {
-                case 2:
-                    assertEquals(PlaybackState2.STATE_PLAYING, state.getState());
-                    break;
-                case 1:
-                    assertEquals(PlaybackState2.STATE_PAUSED, state.getState());
-                    break;
-                case 0:
-                    fail();
+        final CountDownLatch playbackLatch = new CountDownLatch(3);
+        final CountDownLatch errorLatch = new CountDownLatch(1);
+        final EventCallback callback = new EventCallback() {
+            @Override
+            public void onPlaybackStateChanged(PlaybackState2 state) {
+                assertEquals(sHandler.getLooper(), Looper.myLooper());
+                switch ((int) playbackLatch.getCount()) {
+                    case 3:
+                        assertNull(state);
+                        break;
+                    case 2:
+                        assertNotNull(state);
+                        assertEquals(PlaybackState2.STATE_PLAYING, state.getState());
+                        break;
+                    case 1:
+                        assertNotNull(state);
+                        assertEquals(PlaybackState2.STATE_PAUSED, state.getState());
+                        break;
+                    case 0:
+                        fail();
+                }
+                playbackLatch.countDown();
             }
-            latch.countDown();
+
+            @Override
+            public void onError(String mediaId, int what, int extra) {
+                assertEquals(testWhat, what);
+                errorLatch.countDown();
+            }
         };
         player.notifyPlaybackState(createPlaybackState(PlaybackState2.STATE_PLAYING));
-        sHandler.postAndSync(() -> {
-            mSession.addPlaybackListener(sHandlerExecutor, listener);
-            // When the player is set, listeners will be notified about the player's current state.
-            mSession.setPlayer(player);
-        });
+        // EventCallback will be notified with the mPlayer's playback state (null)
+        mSession.registerPlayerEventCallback(sHandlerExecutor, callback);
+        // When the player is set, EventCallback will be notified about the new player's state.
+        mSession.setPlayer(player);
+        // When the player is set, EventCallback will be notified about the new player's state.
         player.notifyPlaybackState(createPlaybackState(PlaybackState2.STATE_PAUSED));
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertTrue(playbackLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        player.notifyError(testWhat);
+        assertTrue(errorLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     @Test
     public void testBadPlayer() throws InterruptedException {
         // TODO(jaewan): Add equivalent tests again
-        final CountDownLatch latch = new CountDownLatch(3); // expected call + 1
+        final CountDownLatch latch = new CountDownLatch(4); // expected call + 1
         final BadPlayer player = new BadPlayer(0);
-        sHandler.postAndSync(() -> {
-            mSession.addPlaybackListener(sHandlerExecutor, (state) -> {
+        mSession.registerPlayerEventCallback(sHandlerExecutor, new EventCallback() {
+            @Override
+            public void onPlaybackStateChanged(PlaybackState2 state) {
                 // This will be called for every setPlayer() calls, but no more.
                 assertNull(state);
                 latch.countDown();
-            });
-            mSession.setPlayer(player);
-            mSession.setPlayer(mPlayer);
+            }
         });
+        mSession.setPlayer(player);
+        mSession.setPlayer(mPlayer);
         player.notifyPlaybackState(createPlaybackState(PlaybackState2.STATE_PAUSED));
         assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
     }
@@ -308,7 +322,7 @@
         }
 
         @Override
-        public void removePlaybackListener(@NonNull PlaybackListener listener) {
+        public void unregisterEventCallback(@NonNull EventCallback listener) {
             // No-op. This bad player will keep push notification to the listener that is previously
             // registered by session.setPlayer().
         }
@@ -461,7 +475,8 @@
         }
 
         @Override
-        public boolean onCommandRequest(ControllerInfo controllerInfo, MediaSession2.Command command) {
+        public boolean onCommandRequest(ControllerInfo controllerInfo,
+                MediaSession2.Command command) {
             assertEquals(mContext.getPackageName(), controllerInfo.getPackageName());
             assertEquals(Process.myUid(), controllerInfo.getUid());
             assertFalse(controllerInfo.isTrusted());
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index f5abfff..7106561 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -118,7 +118,7 @@
      */
     public PlaybackState2 createPlaybackState(int state) {
         return new PlaybackState2(mContext, state, 0, 0, 1.0f,
-                0, 0, null);
+                0, 0);
     }
 
     final MediaController2 createController(SessionToken2 token) throws InterruptedException {
diff --git a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
index 852f2fa..d61baab 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSessionManager_MediaSession2.java
@@ -26,7 +26,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -40,9 +39,6 @@
  */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-@Ignore
-// TODO(jaewan): Reenable test when the media session service detects newly installed sesison
-//               service app.
 public class MediaSessionManager_MediaSession2 extends MediaSession2TestBase {
     private static final String TAG = "MediaSessionManager_MediaSession2";
 
@@ -101,7 +97,7 @@
     }
 
     /**
-     * Test if server recognizes session even if session refuses the connection from server.
+     * Test if server recognizes a session even if the session refuses the connection from server.
      *
      * @throws InterruptedException
      */
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
index ec69ff6..e1cce25 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
@@ -23,9 +23,18 @@
 import android.content.Context;
 import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
+import android.media.TestServiceRegistry.SessionCallbackProxy;
 import android.media.TestUtils.SyncHandler;
 import android.os.Bundle;
-import android.os.Process;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 import javax.annotation.concurrent.GuardedBy;
 
@@ -37,29 +46,74 @@
     public static final String ID = "TestLibrary";
 
     public static final String ROOT_ID = "rootId";
-    public static final Bundle EXTRA = new Bundle();
+    public static final Bundle EXTRAS = new Bundle();
+
+    public static final String MEDIA_ID_GET_ITEM = "media_id_get_item";
+
+    public static final String PARENT_ID = "parent_id";
+    public static final String PARENT_ID_NO_CHILDREN = "parent_id_no_children";
+    public static final String PARENT_ID_ERROR = "parent_id_error";
+
+    public static final List<MediaItem2> GET_CHILDREN_RESULT = new ArrayList<>();
+    public static final int CHILDREN_COUNT = 100;
+
+    public static final String SEARCH_QUERY = "search_query";
+    public static final String SEARCH_QUERY_TAKES_TIME = "search_query_takes_time";
+    public static final int SEARCH_TIME_IN_MS = 5000;
+    public static final String SEARCH_QUERY_EMPTY_RESULT = "search_query_empty_result";
+
+    public static final List<MediaItem2> SEARCH_RESULT = new ArrayList<>();
+    public static final int SEARCH_RESULT_COUNT = 50;
+
+    private static final DataSourceDesc DATA_SOURCE_DESC =
+            new DataSourceDesc.Builder().setDataSource(new FileDescriptor()).build();
+
+    private static final String TAG = "MockMediaLibrarySvc2";
+
     static {
-        EXTRA.putString(ROOT_ID, ROOT_ID);
+        EXTRAS.putString(ROOT_ID, ROOT_ID);
     }
     @GuardedBy("MockMediaLibraryService2.class")
     private static SessionToken2 sToken;
 
     private MediaLibrarySession mSession;
 
+    public MockMediaLibraryService2() {
+        super();
+        GET_CHILDREN_RESULT.clear();
+        String getChildrenMediaIdPrefix = "get_children_media_id_";
+        for (int i = 0; i < CHILDREN_COUNT; i++) {
+            GET_CHILDREN_RESULT.add(createMediaItem(getChildrenMediaIdPrefix + i));
+        }
+
+        SEARCH_RESULT.clear();
+        String getSearchResultMediaIdPrefix = "get_search_result_media_id_";
+        for (int i = 0; i < SEARCH_RESULT_COUNT; i++) {
+            SEARCH_RESULT.add(createMediaItem(getSearchResultMediaIdPrefix + i));
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        TestServiceRegistry.getInstance().setServiceInstance(this);
+    }
+
     @Override
     public MediaLibrarySession onCreateSession(String sessionId) {
         final MockPlayer player = new MockPlayer(1);
         final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
-        try {
-            handler.postAndSync(() -> {
-                TestLibrarySessionCallback callback = new TestLibrarySessionCallback();
-                mSession = new MediaLibrarySessionBuilder(MockMediaLibraryService2.this,
-                        player, (runnable) -> handler.post(runnable), callback)
-                        .setId(sessionId).build();
-            });
-        } catch (InterruptedException e) {
-            fail(e.toString());
+        final Executor executor = (runnable) -> handler.post(runnable);
+        SessionCallbackProxy sessionCallbackProxy = TestServiceRegistry.getInstance()
+                .getSessionCallbackProxy();
+        if (sessionCallbackProxy == null) {
+            // Ensures non-null
+            sessionCallbackProxy = new SessionCallbackProxy(this) {};
         }
+        TestLibrarySessionCallback callback =
+                new TestLibrarySessionCallback(sessionCallbackProxy);
+        mSession = new MediaLibrarySessionBuilder(MockMediaLibraryService2.this, player,
+                executor, callback).setId(sessionId).build();
         return mSession;
     }
 
@@ -81,24 +135,117 @@
     }
 
     private class TestLibrarySessionCallback extends MediaLibrarySessionCallback {
-        public TestLibrarySessionCallback() {
+        private final SessionCallbackProxy mCallbackProxy;
+
+        public TestLibrarySessionCallback(SessionCallbackProxy callbackProxy) {
             super(MockMediaLibraryService2.this);
+            mCallbackProxy = callbackProxy;
         }
 
         @Override
         public CommandGroup onConnect(ControllerInfo controller) {
-            if (Process.myUid() != controller.getUid()) {
-                // It's system app wants to listen changes. Ignore.
-                return super.onConnect(controller);
-            }
-            TestServiceRegistry.getInstance().setServiceInstance(
-                    MockMediaLibraryService2.this, controller);
-            return super.onConnect(controller);
+            return mCallbackProxy.onConnect(controller);
         }
 
         @Override
         public LibraryRoot onGetRoot(ControllerInfo controller, Bundle rootHints) {
-            return new LibraryRoot(MockMediaLibraryService2.this, ROOT_ID, EXTRA);
+            return new LibraryRoot(MockMediaLibraryService2.this, ROOT_ID, EXTRAS);
+        }
+
+        @Override
+        public MediaItem2 onLoadItem(ControllerInfo controller, String mediaId) {
+            if (MEDIA_ID_GET_ITEM.equals(mediaId)) {
+                return createMediaItem(mediaId);
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public List<MediaItem2> onLoadChildren(ControllerInfo controller, String parentId, int page,
+                int pageSize, Bundle extras) {
+            if (PARENT_ID.equals(parentId)) {
+                return getPaginatedResult(GET_CHILDREN_RESULT, page, pageSize);
+            } else if (PARENT_ID_ERROR.equals(parentId)) {
+                return null;
+            }
+            // Includes the case of PARENT_ID_NO_CHILDREN.
+            return new ArrayList<>();
+        }
+
+        @Override
+        public void onSearch(ControllerInfo controllerInfo, String query, Bundle extras) {
+            if (SEARCH_QUERY.equals(query)) {
+                mSession.notifySearchResultChanged(controllerInfo, query, SEARCH_RESULT_COUNT,
+                        extras);
+            } else if (SEARCH_QUERY_TAKES_TIME.equals(query)) {
+                // Searching takes some time. Notify after 5 seconds.
+                Executors.newSingleThreadScheduledExecutor().schedule(new Runnable() {
+                    @Override
+                    public void run() {
+                        mSession.notifySearchResultChanged(
+                                controllerInfo, query, SEARCH_RESULT_COUNT, extras);
+                    }
+                }, SEARCH_TIME_IN_MS, TimeUnit.MILLISECONDS);
+            } else if (SEARCH_QUERY_EMPTY_RESULT.equals(query)) {
+                mSession.notifySearchResultChanged(controllerInfo, query, 0, extras);
+            } else {
+                // TODO: For the error case, how should we notify the browser?
+            }
+        }
+
+        @Override
+        public List<MediaItem2> onLoadSearchResult(ControllerInfo controllerInfo,
+                String query, int page, int pageSize, Bundle extras) {
+            if (SEARCH_QUERY.equals(query)) {
+                return getPaginatedResult(SEARCH_RESULT, page, pageSize);
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public void onSubscribed(ControllerInfo controller, String parentId, Bundle extras) {
+            mCallbackProxy.onSubscribed(controller, parentId, extras);
+        }
+
+        @Override
+        public void onUnsubscribed(ControllerInfo controller, String parentId) {
+            mCallbackProxy.onUnsubscribed(controller, parentId);
         }
     }
-}
\ No newline at end of file
+
+    private List<MediaItem2> getPaginatedResult(List<MediaItem2> items, int page, int pageSize) {
+        if (items == null) {
+            return null;
+        } else if (items.size() == 0) {
+            return new ArrayList<>();
+        }
+
+        final int totalItemCount = items.size();
+        int fromIndex = (page - 1) * pageSize;
+        int toIndex = Math.min(page * pageSize, totalItemCount);
+
+        List<MediaItem2> paginatedResult = new ArrayList<>();
+        try {
+            // The case of (fromIndex >= totalItemCount) will throw exception below.
+            paginatedResult = items.subList(fromIndex, toIndex);
+        } catch (IndexOutOfBoundsException | IllegalArgumentException ex) {
+            Log.d(TAG, "Result is empty for given pagination arguments: totalItemCount="
+                    + totalItemCount + ", page=" + page + ", pageSize=" + pageSize, ex);
+        }
+        return paginatedResult;
+    }
+
+    private MediaItem2 createMediaItem(String mediaId) {
+        Context context = MockMediaLibraryService2.this;
+        return new MediaItem2(
+                context,
+                mediaId,
+                DATA_SOURCE_DESC,
+                new MediaMetadata2.Builder(context)
+                        .putString(MediaMetadata2.METADATA_KEY_MEDIA_ID, mediaId)
+                        .build(),
+                0 /* Flags */);
+    }
+}
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
index c8ed184..12c2c9f 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaSessionService2.java
@@ -22,11 +22,11 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSession2.SessionCallback;
+import android.media.TestServiceRegistry.SessionCallbackProxy;
 import android.media.TestUtils.SyncHandler;
-import android.media.session.PlaybackState;
-import android.os.Process;
 
 import java.util.concurrent.Executor;
 
@@ -45,29 +45,32 @@
     private NotificationManager mNotificationManager;
 
     @Override
+    public void onCreate() {
+        super.onCreate();
+        TestServiceRegistry.getInstance().setServiceInstance(this);
+        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+    }
+
+    @Override
     public MediaSession2 onCreateSession(String sessionId) {
         final MockPlayer player = new MockPlayer(1);
         final SyncHandler handler = (SyncHandler) TestServiceRegistry.getInstance().getHandler();
         final Executor executor = (runnable) -> handler.post(runnable);
-        try {
-            handler.postAndSync(() -> {
-                mSession = new MediaSession2.Builder(MockMediaSessionService2.this, player)
-                        .setSessionCallback(executor, new MySessionCallback())
-                        .setId(sessionId).build();
-            });
-        } catch (InterruptedException e) {
-            fail(e.toString());
+        SessionCallbackProxy sessionCallbackProxy = TestServiceRegistry.getInstance()
+                .getSessionCallbackProxy();
+        if (sessionCallbackProxy == null) {
+            // Ensures non-null
+            sessionCallbackProxy = new SessionCallbackProxy(this) {};
         }
+        TestSessionServiceCallback callback =
+                new TestSessionServiceCallback(sessionCallbackProxy);
+        mSession = new MediaSession2.Builder(this, player)
+                .setSessionCallback(executor, callback)
+                .setId(sessionId).build();
         return mSession;
     }
 
     @Override
-    public void onCreate() {
-        super.onCreate();
-        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-    }
-
-    @Override
     public void onDestroy() {
         TestServiceRegistry.getInstance().cleanUp();
         super.onDestroy();
@@ -90,20 +93,17 @@
         return new MediaNotification(this, DEFAULT_MEDIA_NOTIFICATION_ID, notification);
     }
 
-    private class MySessionCallback extends SessionCallback {
-        public MySessionCallback() {
+    private class TestSessionServiceCallback extends SessionCallback {
+        private final SessionCallbackProxy mCallbackProxy;
+
+        public TestSessionServiceCallback(SessionCallbackProxy callbackProxy) {
             super(MockMediaSessionService2.this);
+            mCallbackProxy = callbackProxy;
         }
 
         @Override
-        public MediaSession2.CommandGroup onConnect(ControllerInfo controller) {
-            if (Process.myUid() != controller.getUid()) {
-                // It's system app wants to listen changes. Ignore.
-                return super.onConnect(controller);
-            }
-            TestServiceRegistry.getInstance().setServiceInstance(
-                    MockMediaSessionService2.this, controller);
-            return super.onConnect(controller);
+        public CommandGroup onConnect(ControllerInfo controller) {
+            return mCallbackProxy.onConnect(controller);
         }
     }
 }
diff --git a/packages/MediaComponents/test/src/android/media/MockPlayer.java b/packages/MediaComponents/test/src/android/media/MockPlayer.java
index 1faf0f4..ae31ce6 100644
--- a/packages/MediaComponents/test/src/android/media/MockPlayer.java
+++ b/packages/MediaComponents/test/src/android/media/MockPlayer.java
@@ -19,6 +19,7 @@
 import android.media.MediaSession2.PlaylistParams;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.util.ArrayMap;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -46,7 +47,7 @@
     public boolean mSetPlaylistCalled;
     public boolean mSetPlaylistParamsCalled;
 
-    public List<PlaybackListenerHolder> mListeners = new ArrayList<>();
+    public ArrayMap<EventCallback, Executor> mCallbacks = new ArrayMap<>();
     public List<MediaItem2> mPlaylist;
     public PlaylistParams mPlaylistParams;
 
@@ -146,23 +147,30 @@
     }
 
     @Override
-    public void addPlaybackListener(@NonNull Executor executor,
-            @NonNull PlaybackListener listener) {
-        mListeners.add(new PlaybackListenerHolder(executor, listener));
+    public void registerEventCallback(@NonNull Executor executor,
+            @NonNull EventCallback callback) {
+        mCallbacks.put(callback, executor);
     }
 
     @Override
-    public void removePlaybackListener(@NonNull PlaybackListener listener) {
-        int index = PlaybackListenerHolder.indexOf(mListeners, listener);
-        if (index >= 0) {
-            mListeners.remove(index);
-        }
+    public void unregisterEventCallback(@NonNull EventCallback callback) {
+        mCallbacks.remove(callback);
     }
 
     public void notifyPlaybackState(final PlaybackState2 state) {
         mLastPlaybackState = state;
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).postPlaybackChange(state);
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            final EventCallback callback = mCallbacks.keyAt(i);
+            final Executor executor = mCallbacks.valueAt(i);
+            executor.execute(() -> callback.onPlaybackStateChanged(state));
+        }
+    }
+
+    public void notifyError(int what) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            final EventCallback callback = mCallbacks.keyAt(i);
+            final Executor executor = mCallbacks.valueAt(i);
+            executor.execute(() -> callback.onError(null, what, 0));
         }
     }
 
diff --git a/packages/MediaComponents/test/src/android/media/PlaybackListenerHolder.java b/packages/MediaComponents/test/src/android/media/PlaybackListenerHolder.java
deleted file mode 100644
index 0f1644c..0000000
--- a/packages/MediaComponents/test/src/android/media/PlaybackListenerHolder.java
+++ /dev/null
@@ -1,71 +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.
- */
-
-package android.media;
-
-import android.media.MediaPlayerInterface.PlaybackListener;
-import android.os.Handler;
-import android.support.annotation.NonNull;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Holds {@link PlaybackListener} with the {@link Handler}.
- */
-public class PlaybackListenerHolder {
-    public final Executor executor;
-    public final PlaybackListener listener;
-
-    public PlaybackListenerHolder(Executor executor, @NonNull PlaybackListener listener) {
-        this.executor = executor;
-        this.listener = listener;
-    }
-
-    public void postPlaybackChange(final PlaybackState2 state) {
-        executor.execute(() -> listener.onPlaybackChanged(state));
-    }
-
-    /**
-     * Returns {@code true} if the given list contains a {@link PlaybackListenerHolder} that holds
-     * the given listener.
-     *
-     * @param list list to check
-     * @param listener listener to check
-     * @return {@code true} if the given list contains listener. {@code false} otherwise.
-     */
-    public static <Holder extends PlaybackListenerHolder> boolean contains(
-            @NonNull List<Holder> list, PlaybackListener listener) {
-        return indexOf(list, listener) >= 0;
-    }
-
-    /**
-     * Returns the index of the {@link PlaybackListenerHolder} that contains the given listener.
-     *
-     * @param list list to check
-     * @param listener listener to check
-     * @return {@code index} of item if the given list contains listener. {@code -1} otherwise.
-     */
-    public static <Holder extends PlaybackListenerHolder> int indexOf(
-            @NonNull List<Holder> list, PlaybackListener listener) {
-        for (int i = 0; i < list.size(); i++) {
-            if (list.get(i).listener == listener) {
-                return i;
-            }
-        }
-        return -1;
-    }
-}
diff --git a/packages/MediaComponents/test/src/android/media/SessionToken2Test.java b/packages/MediaComponents/test/src/android/media/SessionToken2Test.java
new file mode 100644
index 0000000..efde78a
--- /dev/null
+++ b/packages/MediaComponents/test/src/android/media/SessionToken2Test.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.content.Context;
+import android.os.Process;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests {@link SessionToken2}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SessionToken2Test {
+    private Context mContext;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
+    public void testConstructor_sessionService() {
+        SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
+                MockMediaSessionService2.class.getCanonicalName());
+        assertEquals(MockMediaSessionService2.ID, token.getId());
+        assertEquals(mContext.getPackageName(), token.getPackageName());
+        assertEquals(Process.myUid(), token.getUid());
+        assertEquals(SessionToken2.TYPE_SESSION_SERVICE, token.getType());
+    }
+
+    @Test
+    public void testConstructor_libraryService() {
+        SessionToken2 token = new SessionToken2(mContext, mContext.getPackageName(),
+                MockMediaLibraryService2.class.getCanonicalName());
+        assertEquals(MockMediaLibraryService2.ID, token.getId());
+        assertEquals(mContext.getPackageName(), token.getPackageName());
+        assertEquals(Process.myUid(), token.getUid());
+        assertEquals(SessionToken2.TYPE_LIBRARY_SERVICE, token.getType());
+    }
+}
\ No newline at end of file
diff --git a/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java b/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java
index 6f5512e..a18ad8e 100644
--- a/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java
+++ b/packages/MediaComponents/test/src/android/media/TestServiceRegistry.java
@@ -18,10 +18,13 @@
 
 import static org.junit.Assert.fail;
 
+import android.content.Context;
+import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
 import android.media.TestUtils.SyncHandler;
+import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
+import android.os.Process;
 import android.support.annotation.GuardedBy;
 
 /**
@@ -31,8 +34,49 @@
  * It only support only one service at a time.
  */
 public class TestServiceRegistry {
-    public interface ServiceInstanceChangedCallback {
-        void OnServiceInstanceChanged(MediaSessionService2 service);
+    /**
+     * Proxy for both {@link MediaSession2.SessionCallback} and
+     * {@link MediaLibraryService2.MediaLibrarySessionCallback}.
+     */
+    public static abstract class SessionCallbackProxy {
+        private final Context mContext;
+
+        /**
+         * Constructor
+         */
+        public SessionCallbackProxy(Context context) {
+            mContext = context;
+        }
+
+        public final Context getContext() {
+            return mContext;
+        }
+
+        /**
+         * @param controller
+         * @return
+         */
+        public CommandGroup onConnect(ControllerInfo controller) {
+            if (Process.myUid() == controller.getUid()) {
+                CommandGroup commands = new CommandGroup(mContext);
+                commands.addAllPredefinedCommands();
+                return commands;
+            }
+            return null;
+        }
+
+        /**
+         * Called when enclosing service is created.
+         */
+        public void onServiceCreated(MediaSessionService2 service) { }
+
+        /**
+         * Called when enclosing service is destroyed.
+         */
+        public void onServiceDestroyed() { }
+
+        public void onSubscribed(ControllerInfo info, String parentId, Bundle extra) { }
+        public void onUnsubscribed(ControllerInfo info, String parentId) { }
     }
 
     @GuardedBy("TestServiceRegistry.class")
@@ -42,9 +86,7 @@
     @GuardedBy("TestServiceRegistry.class")
     private SyncHandler mHandler;
     @GuardedBy("TestServiceRegistry.class")
-    private ControllerInfo mOnConnectControllerInfo;
-    @GuardedBy("TestServiceRegistry.class")
-    private ServiceInstanceChangedCallback mCallback;
+    private SessionCallbackProxy mCallbackProxy;
 
     public static TestServiceRegistry getInstance() {
         synchronized (TestServiceRegistry.class) {
@@ -61,28 +103,33 @@
         }
     }
 
-    public void setServiceInstanceChangedCallback(ServiceInstanceChangedCallback callback) {
-        synchronized (TestServiceRegistry.class) {
-            mCallback = callback;
-        }
-    }
-
     public Handler getHandler() {
         synchronized (TestServiceRegistry.class) {
             return mHandler;
         }
     }
 
-    public void setServiceInstance(MediaSessionService2 service, ControllerInfo controller) {
+    public void setSessionCallbackProxy(SessionCallbackProxy callbackProxy) {
+        synchronized (TestServiceRegistry.class) {
+            mCallbackProxy = callbackProxy;
+        }
+    }
+
+    public SessionCallbackProxy getSessionCallbackProxy() {
+        synchronized (TestServiceRegistry.class) {
+            return mCallbackProxy;
+        }
+    }
+
+    public void setServiceInstance(MediaSessionService2 service) {
         synchronized (TestServiceRegistry.class) {
             if (mService != null) {
                 fail("Previous service instance is still running. Clean up manually to ensure"
                         + " previoulsy running service doesn't break current test");
             }
             mService = service;
-            mOnConnectControllerInfo = controller;
-            if (mCallback != null) {
-                mCallback.OnServiceInstanceChanged(service);
+            if (mCallbackProxy != null) {
+                mCallbackProxy.onServiceCreated(service);
             }
         }
     }
@@ -93,28 +140,11 @@
         }
     }
 
-    public ControllerInfo getOnConnectControllerInfo() {
-        synchronized (TestServiceRegistry.class) {
-            return mOnConnectControllerInfo;
-        }
-    }
-
-
     public void cleanUp() {
         synchronized (TestServiceRegistry.class) {
-            final ServiceInstanceChangedCallback callback = mCallback;
+            final SessionCallbackProxy callbackProxy = mCallbackProxy;
             if (mService != null) {
-                try {
-                    if (mHandler.getLooper() == Looper.myLooper()) {
-                        mService.getSession().close();
-                    } else {
-                        mHandler.postAndSync(() -> {
-                            mService.getSession().close();
-                        });
-                    }
-                } catch (InterruptedException e) {
-                    // No-op. Service containing session will die, but shouldn't be a huge issue.
-                }
+                mService.getSession().close();
                 // stopSelf() would not kill service while the binder connection established by
                 // bindService() exists, and close() above will do the job instead.
                 // So stopSelf() isn't really needed, but just for sure.
@@ -124,11 +154,10 @@
             if (mHandler != null) {
                 mHandler.removeCallbacksAndMessages(null);
             }
-            mCallback = null;
-            mOnConnectControllerInfo = null;
+            mCallbackProxy = null;
 
-            if (callback != null) {
-                callback.OnServiceInstanceChanged(null);
+            if (callbackProxy != null) {
+                callbackProxy.onServiceDestroyed();
             }
         }
     }
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index a3ce1f6..9a30f71 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1099,26 +1099,17 @@
     if (status != NO_ERROR) {
         return status;
     }
+    if (output == AUDIO_IO_HANDLE_NONE) {
+        return BAD_VALUE;
+    }
     ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume");
 
     AutoMutex lock(mLock);
-    Vector<VolumeInterface *> volumeInterfaces;
-    if (output != AUDIO_IO_HANDLE_NONE) {
-        VolumeInterface *volumeInterface = getVolumeInterface_l(output);
-        if (volumeInterface == NULL) {
-            return BAD_VALUE;
-        }
-        volumeInterfaces.add(volumeInterface);
+    VolumeInterface *volumeInterface = getVolumeInterface_l(output);
+    if (volumeInterface == NULL) {
+        return BAD_VALUE;
     }
-
-    mStreamTypes[stream].volume = value;
-
-    if (volumeInterfaces.size() == 0) {
-        volumeInterfaces = getAllVolumeInterfaces_l();
-    }
-    for (size_t i = 0; i < volumeInterfaces.size(); i++) {
-        volumeInterfaces[i]->setStreamVolume(stream, value);
-    }
+    volumeInterface->setStreamVolume(stream, value);
 
     return NO_ERROR;
 }
@@ -1157,21 +1148,17 @@
     if (status != NO_ERROR) {
         return 0.0f;
     }
-
-    AutoMutex lock(mLock);
-    float volume;
-    if (output != AUDIO_IO_HANDLE_NONE) {
-        VolumeInterface *volumeInterface = getVolumeInterface_l(output);
-        if (volumeInterface != NULL) {
-            volume = volumeInterface->streamVolume(stream);
-        } else {
-            volume = 0.0f;
-        }
-    } else {
-        volume = streamVolume_l(stream);
+    if (output == AUDIO_IO_HANDLE_NONE) {
+        return 0.0f;
     }
 
-    return volume;
+    AutoMutex lock(mLock);
+    VolumeInterface *volumeInterface = getVolumeInterface_l(output);
+    if (volumeInterface == NULL) {
+        return 0.0f;
+    }
+
+    return volumeInterface->streamVolume(stream);
 }
 
 bool AudioFlinger::streamMute(audio_stream_type_t stream) const
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 7c38bcc..ebd1b18 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -616,9 +616,6 @@
               // no range check, AudioFlinger::mLock held
               bool streamMute_l(audio_stream_type_t stream) const
                                 { return mStreamTypes[stream].mute; }
-              // no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held
-              float streamVolume_l(audio_stream_type_t stream) const
-                                { return mStreamTypes[stream].volume; }
               void ioConfigChanged(audio_io_config_event event,
                                    const sp<AudioIoDescriptor>& ioDesc,
                                    pid_t pid = 0);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index ace586c..ef466a2 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -79,7 +79,6 @@
 
     unsigned i;
     for (i = 0; i < FastMixerState::sMaxFastTracks; ++i) {
-        mFastTrackNames[i] = -1;
         mGenerations[i] = 0;
     }
 #ifdef FAST_THREAD_STATISTICS
@@ -190,7 +189,7 @@
             // FIXME new may block for unbounded time at internal mutex of the heap
             //       implementation; it would be better to have normal mixer allocate for us
             //       to avoid blocking here and to prevent possible priority inversion
-            mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::sMaxFastTracks);
+            mMixer = new AudioMixer(frameCount, mSampleRate);
             // FIXME See the other FIXME at FastMixer::setNBLogWriter()
             const size_t mixerFrameSize = mSinkChannelCount
                     * audio_bytes_per_sample(mMixerBufferFormat);
@@ -235,7 +234,6 @@
     dumpState->mTrackMask = currentTrackMask;
     if (current->mFastTracksGen != mFastTracksGen) {
         ALOG_ASSERT(mMixerBuffer != NULL);
-        int name;
 
         // process removed tracks first to avoid running out of track names
         unsigned removedTracks = previousTrackMask & ~currentTrackMask;
@@ -245,9 +243,7 @@
             const FastTrack* fastTrack = &current->mFastTracks[i];
             ALOG_ASSERT(fastTrack->mBufferProvider == NULL);
             if (mMixer != NULL) {
-                name = mFastTrackNames[i];
-                ALOG_ASSERT(name >= 0);
-                mMixer->deleteTrackName(name);
+                mMixer->destroy(i);
             }
 #if !LOG_NDEBUG
             mFastTrackNames[i] = -1;
@@ -265,10 +261,16 @@
             AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
             ALOG_ASSERT(bufferProvider != NULL && mFastTrackNames[i] == -1);
             if (mMixer != NULL) {
-                name = mMixer->getTrackName(fastTrack->mChannelMask,
+                const int name = i; // for clarity, choose name as fast track index.
+                status_t status = mMixer->create(
+                        name,
+                        fastTrack->mChannelMask,
                         fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
-                ALOG_ASSERT(name >= 0);
-                mFastTrackNames[i] = name;
+                LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
+                        "%s: cannot create track name"
+                        " %d, mask %#x, format %#x, sessionId %d in AudioMixer",
+                        __func__, name,
+                        fastTrack->mChannelMask, fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX);
                 mMixer->setBufferProvider(name, bufferProvider);
                 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
                         (void *)mMixerBuffer);
@@ -300,8 +302,7 @@
                 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
                 ALOG_ASSERT(bufferProvider != NULL);
                 if (mMixer != NULL) {
-                    name = mFastTrackNames[i];
-                    ALOG_ASSERT(name >= 0);
+                    const int name = i;
                     mMixer->setBufferProvider(name, bufferProvider);
                     if (fastTrack->mVolumeProvider == NULL) {
                         float f = AudioMixer::UNITY_GAIN_FLOAT;
@@ -378,8 +379,7 @@
             perTrackTimestamp.mPosition[ExtendedTimestamp::LOCATION_SERVER] = trackFramesWritten;
             fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp);
 
-            int name = mFastTrackNames[i];
-            ALOG_ASSERT(name >= 0);
+            const int name = i;
             if (fastTrack->mVolumeProvider != NULL) {
                 gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR();
                 float vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 930fa8d..235d23f 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -57,8 +57,6 @@
     static const FastMixerState sInitial;
 
     FastMixerState  mPreIdle;   // copy of state before we went into idle
-    int             mFastTrackNames[FastMixerState::kMaxFastTracks];
-                                // handles used by mixer to identify tracks
     int             mGenerations[FastMixerState::kMaxFastTracks];
                                 // last observed mFastTracks[i].mGeneration
     NBAIO_Sink*     mOutputSink;
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 27c6d35..e5cb8a2 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -497,9 +497,6 @@
                                            patch->mPatchRecord->buffer(),
                                            patch->mPatchRecord->bufferSize(),
                                            AUDIO_OUTPUT_FLAG_NONE);
-    if (patch->mPatchTrack == 0) {
-        return NO_MEMORY;
-    }
     status = patch->mPatchTrack->initCheck();
     if (status != NO_ERROR) {
         return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index e97bb06..6454be5 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -51,6 +51,11 @@
             void        flush();
             void        destroy();
             int         name() const { return mName; }
+            void        setName(int name) {
+                LOG_ALWAYS_FATAL_IF(mName >= 0 && name >= 0,
+                        "%s both old name %d and new name %d are valid", __func__, mName, name);
+                mName = name;
+            }
 
     virtual uint32_t    sampleRate() const;
 
@@ -146,10 +151,7 @@
 
     bool                mResetDone;
     const audio_stream_type_t mStreamType;
-    int                 mName;      // track name on the normal mixer,
-                                    // allocated statically at track creation time,
-                                    // and is even allocated (though unused) for fast tracks
-                                    // FIXME don't allocate track name for fast tracks
+    int                 mName;
     effect_buffer_t     *mMainBuffer;
 
     int32_t             *mAuxBuffer;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d6021b3..3134323 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1661,6 +1661,7 @@
         mSuspendedFrames(0),
         mActiveTracks(&this->mLocalLog),
         // mStreamTypes[] initialized in constructor body
+        mTracks(type == MIXER),
         mOutput(output),
         mLastWriteTime(-1), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
         mMixerStatus(MIXER_IDLE),
@@ -1702,11 +1703,14 @@
     readOutputParameters_l();
 
     // ++ operator does not compile
-    for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_CNT;
+    for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_FOR_POLICY_CNT;
             stream = (audio_stream_type_t) (stream + 1)) {
-        mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
+        mStreamTypes[stream].volume = 0.0f;
         mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
     }
+    // Audio patch volume is always max
+    mStreamTypes[AUDIO_STREAM_PATCH].volume = 1.0f;
+    mStreamTypes[AUDIO_STREAM_PATCH].mute = false;
 }
 
 AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -2157,6 +2161,53 @@
     return track;
 }
 
+template<typename T>
+ssize_t AudioFlinger::PlaybackThread::Tracks<T>::add(const sp<T> &track)
+{
+    const ssize_t index = mTracks.add(track);
+    if (index >= 0) {
+        // set name for track when adding.
+        int name;
+        if (mUnusedTrackNames.empty()) {
+            name = mTracks.size() - 1; // new name {0 ... size-1}.
+        } else {
+            // reuse smallest name for deleted track.
+            auto it = mUnusedTrackNames.begin();
+            name = *it;
+            (void)mUnusedTrackNames.erase(it);
+        }
+        track->setName(name);
+    } else {
+        LOG_ALWAYS_FATAL("cannot add track");
+    }
+    return index;
+}
+
+template<typename T>
+ssize_t AudioFlinger::PlaybackThread::Tracks<T>::remove(const sp<T> &track)
+{
+    const int name = track->name();
+    const ssize_t index = mTracks.remove(track);
+    if (index >= 0) {
+        // invalidate name when removing from mTracks.
+        LOG_ALWAYS_FATAL_IF(name < 0, "invalid name %d for track on mTracks", name);
+
+        if (mSaveDeletedTrackNames) {
+            // We can't directly access mAudioMixer since the caller may be outside of threadLoop.
+            // Instead, we add to mDeletedTrackNames which is solely used for mAudioMixer update,
+            // to be handled when MixerThread::prepareTracks_l() next changes mAudioMixer.
+            mDeletedTrackNames.emplace(name);
+        }
+
+        mUnusedTrackNames.emplace(name);
+        track->setName(T::TRACK_NAME_PENDING);
+    } else {
+        LOG_ALWAYS_FATAL_IF(name >= 0,
+                "valid name %d for track not in mTracks (returned %zd)", name, index);
+    }
+    return index;
+}
+
 uint32_t AudioFlinger::PlaybackThread::correctLatency_l(uint32_t latency) const
 {
     return latency;
@@ -2313,9 +2364,6 @@
     mLocalLog.log("removeTrack_l (%p) %s", track.get(), result.string());
 
     mTracks.remove(track);
-    deleteTrackName_l(track->name());
-    // redundant as track is about to be destroyed, for dumpsys only
-    track->mName = -1;
     if (track->isFastTrack()) {
         int index = track->mFastIndex;
         ALOG_ASSERT(0 < index && index < (int)FastMixerState::sMaxFastTracks);
@@ -4111,6 +4159,14 @@
 AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
         Vector< sp<Track> > *tracksToRemove)
 {
+    // clean up deleted track names in AudioMixer before allocating new tracks
+    (void)mTracks.processDeletedTrackNames([this](int name) {
+        // for each name, destroy it in the AudioMixer
+        if (mAudioMixer->exists(name)) {
+            mAudioMixer->destroy(name);
+        }
+    });
+    mTracks.clearDeletedTrackNames();
 
     mixer_state mixerStatus = MIXER_IDLE;
     // find out which tracks need to be processed
@@ -4332,6 +4388,24 @@
         // The first time a track is added we wait
         // for all its buffers to be filled before processing it
         int name = track->name();
+
+        // if an active track doesn't exist in the AudioMixer, create it.
+        if (!mAudioMixer->exists(name)) {
+            status_t status = mAudioMixer->create(
+                    name,
+                    track->mChannelMask,
+                    track->mFormat,
+                    track->mSessionId);
+            if (status != OK) {
+                ALOGW("%s: cannot create track name"
+                        " %d, mask %#x, format %#x, sessionId %d in AudioMixer",
+                        __func__, name, track->mChannelMask, track->mFormat, track->mSessionId);
+                tracksToRemove->add(track);
+                track->invalidate(); // consider it dead.
+                continue;
+            }
+        }
+
         // make sure that we have enough frames to mix one full buffer.
         // enforce this condition only once to enable draining the buffer in case the client
         // app does not call stop() and relies on underrun to stop:
@@ -4357,20 +4431,9 @@
         size_t framesReady = track->framesReady();
         if (ATRACE_ENABLED()) {
             // I wish we had formatted trace names
-            char traceName[16];
-            strcpy(traceName, "nRdy");
-            int name = track->name();
-            if (AudioMixer::TRACK0 <= name &&
-                    name < (int) (AudioMixer::TRACK0 + AudioMixer::MAX_NUM_TRACKS)) {
-                name -= AudioMixer::TRACK0;
-                traceName[4] = (name / 10) + '0';
-                traceName[5] = (name % 10) + '0';
-            } else {
-                traceName[4] = '?';
-                traceName[5] = '?';
-            }
-            traceName[6] = '\0';
-            ATRACE_INT(traceName, framesReady);
+            std::string traceName("nRdy");
+            traceName += std::to_string(track->name());
+            ATRACE_INT(traceName.c_str(), framesReady);
         }
         if ((framesReady >= minFrames) && track->isReady() &&
                 !track->isPaused() && !track->isTerminated())
@@ -4736,7 +4799,7 @@
 }
 
 // trackCountForUid_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::PlaybackThread::trackCountForUid_l(uid_t uid)
+uint32_t AudioFlinger::PlaybackThread::trackCountForUid_l(uid_t uid) const
 {
     uint32_t trackCount = 0;
     for (size_t i = 0; i < mTracks.size() ; i++) {
@@ -4747,21 +4810,24 @@
     return trackCount;
 }
 
-// getTrackName_l() must be called with ThreadBase::mLock held
-int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask,
-        audio_format_t format, audio_session_t sessionId, uid_t uid)
+// isTrackAllowed_l() must be called with ThreadBase::mLock held
+bool AudioFlinger::MixerThread::isTrackAllowed_l(
+        audio_channel_mask_t channelMask, audio_format_t format,
+        audio_session_t sessionId, uid_t uid) const
 {
-    if (trackCountForUid_l(uid) > (PlaybackThread::kMaxTracksPerUid - 1)) {
-        return -1;
+    if (!PlaybackThread::isTrackAllowed_l(channelMask, format, sessionId, uid)) {
+        return false;
     }
-    return mAudioMixer->getTrackName(channelMask, format, sessionId);
-}
-
-// deleteTrackName_l() must be called with ThreadBase::mLock held
-void AudioFlinger::MixerThread::deleteTrackName_l(int name)
-{
-    ALOGV("remove track (%d) and delete from mixer", name);
-    mAudioMixer->deleteTrackName(name);
+    // Check validity as we don't call AudioMixer::create() here.
+    if (!AudioMixer::isValidFormat(format)) {
+        ALOGW("%s: invalid format: %#x", __func__, format);
+        return false;
+    }
+    if (!AudioMixer::isValidChannelMask(channelMask)) {
+        ALOGW("%s: invalid channelMask: %#x", __func__, channelMask);
+        return false;
+    }
+    return true;
 }
 
 // checkForNewParameter_l() must be called with ThreadBase::mLock held
@@ -4854,13 +4920,18 @@
             readOutputParameters_l();
             delete mAudioMixer;
             mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
-            for (size_t i = 0; i < mTracks.size() ; i++) {
-                int name = getTrackName_l(mTracks[i]->mChannelMask,
-                        mTracks[i]->mFormat, mTracks[i]->mSessionId, mTracks[i]->uid());
-                if (name < 0) {
-                    break;
-                }
-                mTracks[i]->mName = name;
+            for (const auto &track : mTracks) {
+                const int name = track->name();
+                status_t status = mAudioMixer->create(
+                        name,
+                        track->mChannelMask,
+                        track->mFormat,
+                        track->mSessionId);
+                ALOGW_IF(status != NO_ERROR,
+                        "%s: cannot create track name"
+                        " %d, mask %#x, format %#x, sessionId %d in AudioMixer",
+                        __func__,
+                        name, track->mChannelMask, track->mFormat, track->mSessionId);
             }
             sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
         }
@@ -5309,21 +5380,6 @@
     return !mStandby && !(trackPaused || (mHwPaused && !trackStopped));
 }
 
-// getTrackName_l() must be called with ThreadBase::mLock held
-int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
-        audio_format_t format __unused, audio_session_t sessionId __unused, uid_t uid)
-{
-    if (trackCountForUid_l(uid) > (PlaybackThread::kMaxTracksPerUid - 1)) {
-        return -1;
-    }
-    return 0;
-}
-
-// deleteTrackName_l() must be called with ThreadBase::mLock held
-void AudioFlinger::DirectOutputThread::deleteTrackName_l(int name __unused)
-{
-}
-
 // checkForNewParameter_l() must be called with ThreadBase::mLock held
 bool AudioFlinger::DirectOutputThread::checkForNewParameter_l(const String8& keyValuePair,
                                                               status_t& status)
@@ -5941,6 +5997,31 @@
     }
 }
 
+void AudioFlinger::DuplicatingThread::dumpInternals(int fd, const Vector<String16>& args __unused)
+{
+    MixerThread::dumpInternals(fd, args);
+
+    std::stringstream ss;
+    const size_t numTracks = mOutputTracks.size();
+    ss << "  " << numTracks << " OutputTracks";
+    if (numTracks > 0) {
+        ss << ":";
+        for (const auto &track : mOutputTracks) {
+            const sp<ThreadBase> thread = track->thread().promote();
+            ss << " (" << track->name() << " : ";
+            if (thread.get() != nullptr) {
+                ss << thread.get() << ", " << thread->id();
+            } else {
+                ss << "null";
+            }
+            ss << ")";
+        }
+    }
+    ss << "\n";
+    std::string result = ss.str();
+    write(fd, result.c_str(), result.size());
+}
+
 void AudioFlinger::DuplicatingThread::saveOutputTracks()
 {
     outputTracks = mOutputTracks;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 53cb8ad..ae14ac1 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -624,6 +624,7 @@
     static const int8_t kMaxTrackStartupRetriesOffload = 100;
     static const int8_t kMaxTrackStopRetriesOffload = 2;
     static constexpr uint32_t kMaxTracksPerUid = 40;
+    static constexpr size_t kMaxTracks = 256;
 
     // Maximum delay (in nanoseconds) for upcoming buffers in suspend mode, otherwise
     // if delay is greater, the estimated time for timeLoopNextNs is reset.
@@ -778,6 +779,16 @@
 
     virtual     bool        isOutput() const override { return true; }
 
+                // returns true if the track is allowed to be added to the thread.
+    virtual     bool        isTrackAllowed_l(
+                                    audio_channel_mask_t channelMask __unused,
+                                    audio_format_t format __unused,
+                                    audio_session_t sessionId __unused,
+                                    uid_t uid) const {
+                                return trackCountForUid_l(uid) < PlaybackThread::kMaxTracksPerUid
+                                       && mTracks.size() < PlaybackThread::kMaxTracks;
+                            }
+
 protected:
     // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
@@ -866,12 +877,6 @@
 protected:
     ActiveTracks<Track>     mActiveTracks;
 
-    // Allocate a track name for a given channel mask.
-    //   Returns name >= 0 if successful, -1 on failure.
-    virtual int             getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
-                                           audio_session_t sessionId, uid_t uid) = 0;
-    virtual void            deleteTrackName_l(int name) = 0;
-
     // Time to sleep between cycles when:
     virtual uint32_t        activeSleepTimeUs() const;      // mixer state MIXER_TRACKS_ENABLED
     virtual uint32_t        idleSleepTimeUs() const = 0;    // mixer state MIXER_IDLE
@@ -899,7 +904,7 @@
                                     && mHwSupportsPause
                                     && (mOutput->flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC); }
 
-                uint32_t    trackCountForUid_l(uid_t uid);
+                uint32_t    trackCountForUid_l(uid_t uid) const;
 
 private:
 
@@ -916,7 +921,64 @@
     virtual void dumpInternals(int fd, const Vector<String16>& args);
     void        dumpTracks(int fd, const Vector<String16>& args);
 
-    SortedVector< sp<Track> >       mTracks;
+    // The Tracks class manages names for all tracks
+    // added and removed from the Thread.
+    template <typename T>
+    class Tracks {
+    public:
+        Tracks(bool saveDeletedTrackNames) :
+            mSaveDeletedTrackNames(saveDeletedTrackNames) { }
+
+        // SortedVector methods
+        ssize_t         add(const sp<T> &track);
+        ssize_t         remove(const sp<T> &track);
+        size_t          size() const {
+            return mTracks.size();
+        }
+        bool            isEmpty() const {
+            return mTracks.isEmpty();
+        }
+        ssize_t         indexOf(const sp<T> &item) {
+            return mTracks.indexOf(item);
+        }
+        sp<T>           operator[](size_t index) const {
+            return mTracks[index];
+        }
+        typename SortedVector<sp<T>>::iterator begin() {
+            return mTracks.begin();
+        }
+        typename SortedVector<sp<T>>::iterator end() {
+            return mTracks.end();
+        }
+
+        size_t          processDeletedTrackNames(std::function<void(int)> f) {
+            const size_t size = mDeletedTrackNames.size();
+            if (size > 0) {
+                for (const int name : mDeletedTrackNames) {
+                    f(name);
+                }
+            }
+            return size;
+        }
+
+        void            clearDeletedTrackNames() { mDeletedTrackNames.clear(); }
+
+    private:
+        // Track names pending deletion for MIXER type threads
+        const bool mSaveDeletedTrackNames; // true to enable tracking
+        std::set<int> mDeletedTrackNames;
+
+        // Fast lookup of previously deleted track names for reuse.
+        // This is an arbitrary decision (actually any non-negative
+        // integer that isn't in mTracks[*]->names() could be used) - we attempt
+        // to use the smallest possible available name.
+        std::set<int> mUnusedTrackNames;
+
+        SortedVector<sp<T>> mTracks; // wrapped SortedVector.
+    };
+
+    Tracks<Track>                   mTracks;
+
     stream_type_t                   mStreamTypes[AUDIO_STREAM_CNT];
     AudioStreamOut                  *mOutput;
 
@@ -1023,11 +1085,11 @@
                                                    status_t& status);
     virtual     void        dumpInternals(int fd, const Vector<String16>& args);
 
+    virtual     bool        isTrackAllowed_l(
+                                    audio_channel_mask_t channelMask, audio_format_t format,
+                                    audio_session_t sessionId, uid_t uid) const override;
 protected:
     virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
-    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
-                                           audio_session_t sessionId, uid_t uid);
-    virtual     void        deleteTrackName_l(int name);
     virtual     uint32_t    idleSleepTimeUs() const;
     virtual     uint32_t    suspendSleepTimeUs() const;
     virtual     void        cacheParameters_l();
@@ -1105,9 +1167,6 @@
     virtual     void        flushHw_l();
 
 protected:
-    virtual     int         getTrackName_l(audio_channel_mask_t channelMask, audio_format_t format,
-                                           audio_session_t sessionId, uid_t uid);
-    virtual     void        deleteTrackName_l(int name);
     virtual     uint32_t    activeSleepTimeUs() const;
     virtual     uint32_t    idleSleepTimeUs() const;
     virtual     uint32_t    suspendSleepTimeUs() const;
@@ -1211,6 +1270,8 @@
     virtual                 ~DuplicatingThread();
 
     // Thread virtuals
+    virtual     void        dumpInternals(int fd, const Vector<String16>& args) override;
+
                 void        addOutputTrack(MixerThread* thread);
                 void        removeOutputTrack(MixerThread* thread);
                 uint32_t    waitTimeMs() const { return mWaitTimeMs; }
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index a3ea756..a7e966f 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -54,6 +54,11 @@
         TYPE_PATCH,
     };
 
+    enum {
+        TRACK_NAME_PENDING = -1,
+        TRACK_NAME_FAILURE = -2,
+    };
+
                         TrackBase(ThreadBase *thread,
                                 const sp<Client>& client,
                                 uint32_t sampleRate,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 67f27d0..9b93939 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -394,7 +394,7 @@
     // mRetryCount initialized later when needed
     mSharedBuffer(sharedBuffer),
     mStreamType(streamType),
-    mName(-1),  // see note below
+    mName(TRACK_NAME_FAILURE),  // set to TRACK_NAME_PENDING on constructor success.
     mMainBuffer(thread->sinkBuffer()),
     mAuxBuffer(NULL),
     mAuxEffectId(0), mHasVolumeController(false),
@@ -427,9 +427,8 @@
     }
     mServerProxy = mAudioTrackServerProxy;
 
-    mName = thread->getTrackName_l(channelMask, format, sessionId, uid);
-    if (mName < 0) {
-        ALOGE("no more track names available");
+    if (!thread->isTrackAllowed_l(channelMask, format, sessionId, uid)) {
+        ALOGE("no more tracks available");
         return;
     }
     // only allocate a fast track index if we were able to allocate a normal track name
@@ -448,6 +447,7 @@
         mFastIndex = i;
         thread->mFastTrackAvailMask &= ~(1 << i);
     }
+    mName = TRACK_NAME_PENDING;
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
@@ -466,7 +466,7 @@
 status_t AudioFlinger::PlaybackThread::Track::initCheck() const
 {
     status_t status = TrackBase::initCheck();
-    if (status == NO_ERROR && mName < 0) {
+    if (status == NO_ERROR && mName == TRACK_NAME_FAILURE) {
         status = NO_MEMORY;
     }
     return status;
@@ -527,10 +527,12 @@
 
     if (isFastTrack()) {
         result.appendFormat("F%c %3d", trackType, mFastIndex);
-    } else if (mName >= AudioMixer::TRACK0) {
-        result.appendFormat("%c %4d", trackType, mName - AudioMixer::TRACK0);
+    } else if (mName == TRACK_NAME_PENDING) {
+        result.appendFormat("%c pend", trackType);
+    } else if (mName == TRACK_NAME_FAILURE) {
+        result.appendFormat("%c fail", trackType);
     } else {
-        result.appendFormat("%c none", trackType);
+        result.appendFormat("%c %4d", trackType, mName);
     }
 
     char nowInUnderrun;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index cd2174d..78a184b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -133,6 +133,9 @@
             // Note: called after changeRefCount(-1);
             void stop();
             void close();
+            status_t openDuplicating(const sp<SwAudioOutputDescriptor>& output1,
+                                     const sp<SwAudioOutputDescriptor>& output2,
+                                     audio_io_handle_t *ioHandle);
 
     const sp<IOProfile> mProfile;          // I/O profile this output derives from
     audio_io_handle_t mIoHandle;           // output handle
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 17fc272..caaa0f7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -222,7 +222,7 @@
 SwAudioOutputDescriptor::SwAudioOutputDescriptor(const sp<IOProfile>& profile,
                                                  AudioPolicyClientInterface *clientInterface)
     : AudioOutputDescriptor(profile, clientInterface),
-    mProfile(profile), mIoHandle(0), mLatency(0),
+    mProfile(profile), mIoHandle(AUDIO_IO_HANDLE_NONE), mLatency(0),
     mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
     mOutput1(0), mOutput2(0), mDirectOpenCount(0),
     mDirectClientSession(AUDIO_SESSION_NONE), mGlobalRefCount(0)
@@ -509,6 +509,30 @@
     }
 }
 
+status_t SwAudioOutputDescriptor::openDuplicating(const sp<SwAudioOutputDescriptor>& output1,
+                                                  const sp<SwAudioOutputDescriptor>& output2,
+                                                  audio_io_handle_t *ioHandle)
+{
+    // open a duplicating output thread for the new output and the primary output
+    // Note: openDuplicateOutput() API expects the output handles in the reverse order from the
+    // numbering in SwAudioOutputDescriptor mOutput1 and mOutput2
+    *ioHandle = mClientInterface->openDuplicateOutput(output2->mIoHandle, output1->mIoHandle);
+    if (*ioHandle == AUDIO_IO_HANDLE_NONE) {
+        return INVALID_OPERATION;
+    }
+
+    mId = AudioPort::getNextUniqueId();
+    mIoHandle = *ioHandle;
+    mOutput1 = output1;
+    mOutput2 = output2;
+    mSamplingRate = output2->mSamplingRate;
+    mFormat = output2->mFormat;
+    mChannelMask = output2->mChannelMask;
+    mLatency = output2->mLatency;
+
+    return NO_ERROR;
+}
+
 // HwAudioOutputDescriptor implementation
 HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
                                                  AudioPolicyClientInterface *clientInterface)
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 54bfcbc..57d9371 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -67,7 +67,9 @@
                                                       const char *device_address,
                                                       const char *device_name)
 {
-    return setDeviceConnectionStateInt(device, state, device_address, device_name);
+    status_t status = setDeviceConnectionStateInt(device, state, device_address, device_name);
+    nextAudioPortGeneration();
+    return status;
 }
 
 void AudioPolicyManager::broadcastDeviceConnectionState(audio_devices_t device,
@@ -1158,6 +1160,12 @@
     bool force = !outputDesc->isActive() &&
             (outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
 
+    // requiresMuteCheck is false when we can bypass mute strategy.
+    // It covers a common case when there is no materially active audio
+    // and muting would result in unnecessary delay and dropped audio.
+    const uint32_t outputLatencyMs = outputDesc->latency();
+    bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2);  // account for drain
+
     // increment usage count for this stream on the requested output:
     // NOTE that the usage count is the same for duplicated output and hardware output which is
     // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1181,29 +1189,44 @@
         for (size_t i = 0; i < mOutputs.size(); i++) {
             sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
             if (desc != outputDesc) {
+                // An output has a shared device if
+                // - managed by the same hw module
+                // - supports the currently selected device
+                const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
+                        && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+
                 // force a device change if any other output is:
                 // - managed by the same hw module
-                // - has a current device selection that differs from selected device.
                 // - supports currently selected device
+                // - has a current device selection that differs from selected device.
                 // - has an active audio patch
                 // In this case, the audio HAL must receive the new device selection so that it can
-                // change the device currently selected by the other active output.
-                if (outputDesc->sharesHwModuleWith(desc) &&
+                // change the device currently selected by the other output.
+                if (sharedDevice &&
                         desc->device() != device &&
-                        desc->supportedDevices() & device &&
                         desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
                     force = true;
                 }
                 // wait for audio on other active outputs to be presented when starting
                 // a notification so that audio focus effect can propagate, or that a mute/unmute
                 // event occurred for beacon
-                uint32_t latency = desc->latency();
-                if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
-                    waitMs = latency;
+                const uint32_t latencyMs = desc->latency();
+                const bool isActive = desc->isActive(latencyMs * 2);  // account for drain
+
+                if (shouldWait && isActive && (waitMs < latencyMs)) {
+                    waitMs = latencyMs;
                 }
+
+                // Require mute check if another output is on a shared device
+                // and currently active to have proper drain and avoid pops.
+                // Note restoring AudioTracks onto this output needs to invoke
+                // a volume ramp if there is no mute.
+                requiresMuteCheck |= sharedDevice && isActive;
             }
         }
-        uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
+
+        const uint32_t muteWaitMs =
+                setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
 
         // handle special case for sonification while in call
         if (isInCall()) {
@@ -1228,6 +1251,14 @@
         if (waitMs > muteWaitMs) {
             *delayMs = waitMs - muteWaitMs;
         }
+
+        // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
+        // A volume change enacted by APM with 0 delay is not synchronous, as it goes
+        // via AudioCommandThread to AudioFlinger.  Hence it is possible that the volume
+        // change occurs after the MixerThread starts and causes a stream volume
+        // glitch.
+        //
+        // We do not introduce additional delay here.
     }
 
     return NO_ERROR;
@@ -3760,9 +3791,11 @@
 
 // ---
 
-void AudioPolicyManager::addOutput(audio_io_handle_t output, const sp<SwAudioOutputDescriptor>& outputDesc)
+void AudioPolicyManager::addOutput(audio_io_handle_t output,
+                                   const sp<SwAudioOutputDescriptor>& outputDesc)
 {
     mOutputs.add(output, outputDesc);
+    applyStreamVolumes(outputDesc, AUDIO_DEVICE_NONE, 0 /* delayMs */, true /* force */);
     updateMono(output); // update mono status when adding to output list
     selectOutputForMusicEffects();
     nextAudioPortGeneration();
@@ -3774,7 +3807,8 @@
     selectOutputForMusicEffects();
 }
 
-void AudioPolicyManager::addInput(audio_io_handle_t input, const sp<AudioInputDescriptor>& inputDesc)
+void AudioPolicyManager::addInput(audio_io_handle_t input,
+                                  const sp<AudioInputDescriptor>& inputDesc)
 {
     mInputs.add(input, inputDesc);
     nextAudioPortGeneration();
@@ -3924,27 +3958,16 @@
                         // outputs used by dynamic policy mixes
                         audio_io_handle_t duplicatedOutput = AUDIO_IO_HANDLE_NONE;
 
-                        // set initial stream volume for device
-                        applyStreamVolumes(desc, device, 0, true);
-
                         //TODO: configure audio effect output stage here
 
                         // open a duplicating output thread for the new output and the primary output
-                        duplicatedOutput =
-                                mpClientInterface->openDuplicateOutput(output,
-                                                                       mPrimaryOutput->mIoHandle);
-                        if (duplicatedOutput != AUDIO_IO_HANDLE_NONE) {
+                        sp<SwAudioOutputDescriptor> dupOutputDesc =
+                                new SwAudioOutputDescriptor(NULL, mpClientInterface);
+                        status_t status = dupOutputDesc->openDuplicating(mPrimaryOutput, desc,
+                                                                         &duplicatedOutput);
+                        if (status == NO_ERROR) {
                             // add duplicated output descriptor
-                            sp<SwAudioOutputDescriptor> dupOutputDesc =
-                                    new SwAudioOutputDescriptor(NULL, mpClientInterface);
-                            dupOutputDesc->mOutput1 = mPrimaryOutput;
-                            dupOutputDesc->mOutput2 = desc;
-                            dupOutputDesc->mSamplingRate = desc->mSamplingRate;
-                            dupOutputDesc->mFormat = desc->mFormat;
-                            dupOutputDesc->mChannelMask = desc->mChannelMask;
-                            dupOutputDesc->mLatency = desc->mLatency;
                             addOutput(duplicatedOutput, dupOutputDesc);
-                            applyStreamVolumes(dupOutputDesc, device, 0, true);
                         } else {
                             ALOGW("checkOutputsForDevice() could not open dup output for %d and %d",
                                     mPrimaryOutput->mIoHandle, output);
@@ -4742,21 +4765,24 @@
                                              bool force,
                                              int delayMs,
                                              audio_patch_handle_t *patchHandle,
-                                             const char* address)
+                                             const char *address,
+                                             bool requiresMuteCheck)
 {
     ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
     AudioParameter param;
     uint32_t muteWaitMs;
 
     if (outputDesc->isDuplicated()) {
-        muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
-        muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
+        muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
+                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+        muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
+                nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
         return muteWaitMs;
     }
     // no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
     // output profile
     if ((device != AUDIO_DEVICE_NONE) &&
-            ((device & outputDesc->supportedDevices()) == 0)) {
+            ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
         return 0;
     }
 
@@ -4770,7 +4796,14 @@
     if (device != AUDIO_DEVICE_NONE) {
         outputDesc->mDevice = device;
     }
-    muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+    // if the outputs are not materially active, there is no need to mute.
+    if (requiresMuteCheck) {
+        muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+    } else {
+        ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+        muteWaitMs = 0;
+    }
 
     // Do not change the routing if:
     //      the requested device is AUDIO_DEVICE_NONE
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index ee339e7..2b68882 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -317,7 +317,8 @@
                              bool force = false,
                              int delayMs = 0,
                              audio_patch_handle_t *patchHandle = NULL,
-                             const char* address = NULL);
+                             const char *address = nullptr,
+                             bool requiresMuteCheck = true);
         status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
                                    int delayMs = 0,
                                    audio_patch_handle_t *patchHandle = NULL);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 7fe363d..c7dfe0f 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -399,11 +399,12 @@
         while (pos + size > *totSize) {
             *totSize += ((*totSize + 7) / 8) * 4;
         }
-        *param = (char *)realloc(*param, *totSize);
-        if (*param == NULL) {
+        char *newParam = (char *)realloc(*param, *totSize);
+        if (newParam == NULL) {
             ALOGE("%s realloc error for size %zu", __func__, *totSize);
             return 0;
         }
+        *param = newParam;
     }
     *curSize = pos + size;
     return pos;
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index e06a81f..394701a 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -32,13 +32,15 @@
 
 namespace android {
 
+using hardware::camera::common::V1_0::TorchModeStatus;
+
 /////////////////////////////////////////////////////////////////////
 // CameraFlashlight implementation begins
 // used by camera service to control flashflight.
 /////////////////////////////////////////////////////////////////////
 
 CameraFlashlight::CameraFlashlight(sp<CameraProviderManager> providerManager,
-        camera_module_callbacks_t* callbacks) :
+        CameraProviderManager::StatusListener* callbacks) :
         mProviderManager(providerManager),
         mCallbacks(callbacks),
         mFlashlightMapInitialized(false) {
@@ -59,7 +61,7 @@
     } else {
         // Only HAL1 devices do not support setTorchMode
         mFlashControl =
-                new CameraHardwareInterfaceFlashControl(mProviderManager, *mCallbacks);
+                new CameraHardwareInterfaceFlashControl(mProviderManager, mCallbacks);
     }
 
     return OK;
@@ -119,7 +121,8 @@
 }
 
 int CameraFlashlight::getNumberOfCameras() {
-    return mProviderManager->getAPI1CompatibleCameraCount();
+    size_t len = mProviderManager->getAPI1CompatibleCameraDeviceIds().size();
+    return static_cast<int>(len);
 }
 
 status_t CameraFlashlight::findFlashUnits() {
@@ -221,9 +224,8 @@
             int numCameras = getNumberOfCameras();
             for (int i = 0; i < numCameras; i++) {
                 if (hasFlashUnitLocked(String8::format("%d", i))) {
-                    mCallbacks->torch_mode_status_change(mCallbacks,
-                            String8::format("%d", i).string(),
-                            TORCH_MODE_STATUS_NOT_AVAILABLE);
+                    mCallbacks->onTorchStatusChanged(
+                            String8::format("%d", i), TorchModeStatus::NOT_AVAILABLE);
                 }
             }
         }
@@ -266,9 +268,8 @@
         int numCameras = getNumberOfCameras();
         for (int i = 0; i < numCameras; i++) {
             if (hasFlashUnitLocked(String8::format("%d", i))) {
-                mCallbacks->torch_mode_status_change(mCallbacks,
-                        String8::format("%d", i).string(),
-                        TORCH_MODE_STATUS_AVAILABLE_OFF);
+                mCallbacks->onTorchStatusChanged(
+                        String8::format("%d", i), TorchModeStatus::AVAILABLE_OFF);
             }
         }
     }
@@ -315,9 +316,9 @@
 
 CameraHardwareInterfaceFlashControl::CameraHardwareInterfaceFlashControl(
         sp<CameraProviderManager> manager,
-        const camera_module_callbacks_t& callbacks) :
+        CameraProviderManager::StatusListener* callbacks) :
         mProviderManager(manager),
-        mCallbacks(&callbacks),
+        mCallbacks(callbacks),
         mTorchEnabled(false) {
 }
 
@@ -333,8 +334,7 @@
         if (mCallbacks) {
             ALOGV("%s: notify the framework that torch was turned off",
                     __FUNCTION__);
-            mCallbacks->torch_mode_status_change(mCallbacks,
-                    mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+            mCallbacks->onTorchStatusChanged(mCameraId, TorchModeStatus::AVAILABLE_OFF);
         }
     }
 }
@@ -368,8 +368,7 @@
         // disabling the torch mode of currently opened device
         disconnectCameraDevice();
         mTorchEnabled = false;
-        mCallbacks->torch_mode_status_change(mCallbacks,
-            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+        mCallbacks->onTorchStatusChanged(cameraId, TorchModeStatus::AVAILABLE_OFF);
         return OK;
     }
 
@@ -379,8 +378,7 @@
     }
 
     mTorchEnabled = true;
-    mCallbacks->torch_mode_status_change(mCallbacks,
-            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
+    mCallbacks->onTorchStatusChanged(cameraId, TorchModeStatus::AVAILABLE_ON);
     return OK;
 }
 
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
index c86ee85..07ce829 100644
--- a/services/camera/libcameraservice/CameraFlashlight.h
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -19,7 +19,6 @@
 
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
-#include <hardware/camera_common.h>
 #include <utils/KeyedVector.h>
 #include <utils/SortedVector.h>
 #include "common/CameraProviderManager.h"
@@ -55,7 +54,7 @@
 class CameraFlashlight : public virtual VirtualLightRefBase {
     public:
         CameraFlashlight(sp<CameraProviderManager> providerManager,
-                camera_module_callbacks_t* callbacks);
+                CameraProviderManager::StatusListener* callbacks);
         virtual ~CameraFlashlight();
 
         // Find all flash units. This must be called before other methods. All
@@ -99,7 +98,7 @@
 
         sp<CameraProviderManager> mProviderManager;
 
-        const camera_module_callbacks_t *mCallbacks;
+        CameraProviderManager::StatusListener* mCallbacks;
         SortedVector<String8> mOpenedCameraIds;
 
         // camera id -> if it has a flash unit
@@ -134,7 +133,7 @@
     public:
         CameraHardwareInterfaceFlashControl(
                 sp<CameraProviderManager> manager,
-                const camera_module_callbacks_t& callbacks);
+                CameraProviderManager::StatusListener* callbacks);
         virtual ~CameraHardwareInterfaceFlashControl();
 
         // FlashControlBase
@@ -166,7 +165,7 @@
         status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash, bool keepDeviceOpen);
 
         sp<CameraProviderManager> mProviderManager;
-        const camera_module_callbacks_t *mCallbacks;
+        CameraProviderManager::StatusListener* mCallbacks;
         sp<CameraHardwareInterface> mDevice;
         String8 mCameraId;
         CameraParameters mParameters;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index e7609ed..1df6b6a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -67,6 +67,7 @@
 #include "api1/Camera2Client.h"
 #include "api2/CameraDeviceClient.h"
 #include "utils/CameraTraces.h"
+#include "utils/TagMonitor.h"
 
 namespace {
     const char* kPermissionServiceName = "permission";
@@ -107,79 +108,13 @@
 
 // ----------------------------------------------------------------------------
 
-extern "C" {
-static void camera_device_status_change(
-        const struct camera_module_callbacks* callbacks,
-        int camera_id,
-        int new_status) {
-    sp<CameraService> cs = const_cast<CameraService*>(
-            static_cast<const CameraService*>(callbacks));
-    String8 id = String8::format("%d", camera_id);
-
-    CameraDeviceStatus newStatus{CameraDeviceStatus::NOT_PRESENT};
-    switch (new_status) {
-        case CAMERA_DEVICE_STATUS_NOT_PRESENT:
-            newStatus = CameraDeviceStatus::NOT_PRESENT;
-            break;
-        case CAMERA_DEVICE_STATUS_PRESENT:
-            newStatus = CameraDeviceStatus::PRESENT;
-            break;
-        case CAMERA_DEVICE_STATUS_ENUMERATING:
-            newStatus = CameraDeviceStatus::ENUMERATING;
-            break;
-        default:
-            ALOGW("Unknown device status change to %d", new_status);
-            break;
-    }
-    cs->onDeviceStatusChanged(id, newStatus);
-}
-
-static void torch_mode_status_change(
-        const struct camera_module_callbacks* callbacks,
-        const char* camera_id,
-        int new_status) {
-    if (!callbacks || !camera_id) {
-        ALOGE("%s invalid parameters. callbacks %p, camera_id %p", __FUNCTION__,
-                callbacks, camera_id);
-    }
-    sp<CameraService> cs = const_cast<CameraService*>(
-                                static_cast<const CameraService*>(callbacks));
-
-    TorchModeStatus status;
-    switch (new_status) {
-        case TORCH_MODE_STATUS_NOT_AVAILABLE:
-            status = TorchModeStatus::NOT_AVAILABLE;
-            break;
-        case TORCH_MODE_STATUS_AVAILABLE_OFF:
-            status = TorchModeStatus::AVAILABLE_OFF;
-            break;
-        case TORCH_MODE_STATUS_AVAILABLE_ON:
-            status = TorchModeStatus::AVAILABLE_ON;
-            break;
-        default:
-            ALOGE("Unknown torch status %d", new_status);
-            return;
-    }
-
-    cs->onTorchStatusChanged(
-        String8(camera_id),
-        status);
-}
-} // extern "C"
-
-// ----------------------------------------------------------------------------
-
 static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");
 
 CameraService::CameraService() :
         mEventLog(DEFAULT_EVENT_LOG_LENGTH),
-        mNumberOfCameras(0), mNumberOfNormalCameras(0),
+        mNumberOfCameras(0),
         mSoundRef(0), mInitialized(false) {
     ALOGI("CameraService started (pid=%d)", getpid());
-
-    this->camera_device_status_change = android::camera_device_status_change;
-    this->torch_mode_status_change = android::torch_mode_status_change;
-
     mServiceLockWrapper = std::make_shared<WaitableMutexWrapper>(&mServiceLock);
 }
 
@@ -209,52 +144,42 @@
 
 status_t CameraService::enumerateProviders() {
     status_t res;
-    Mutex::Autolock l(mServiceLock);
 
-    if (nullptr == mCameraProviderManager.get()) {
-        mCameraProviderManager = new CameraProviderManager();
-        res = mCameraProviderManager->initialize(this);
-        if (res != OK) {
-            ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",
-                    __FUNCTION__, strerror(-res), res);
-            return res;
-        }
-    }
+    std::vector<std::string> deviceIds;
+    {
+        Mutex::Autolock l(mServiceLock);
 
-    mNumberOfCameras = mCameraProviderManager->getCameraCount();
-    mNumberOfNormalCameras =
-            mCameraProviderManager->getAPI1CompatibleCameraCount();
-
-    // Setup vendor tags before we call get_camera_info the first time
-    // because HAL might need to setup static vendor keys in get_camera_info
-    // TODO: maybe put this into CameraProviderManager::initialize()?
-    mCameraProviderManager->setUpVendorTags();
-
-    if (nullptr == mFlashlight.get()) {
-        mFlashlight = new CameraFlashlight(mCameraProviderManager, this);
-    }
-
-    res = mFlashlight->findFlashUnits();
-    if (res != OK) {
-        ALOGE("Failed to enumerate flash units: %s (%d)", strerror(-res), res);
-    }
-
-    for (auto& cameraId : mCameraProviderManager->getCameraDeviceIds()) {
-        String8 id8 = String8(cameraId.c_str());
-        bool cameraFound = false;
-        {
-
-            Mutex::Autolock lock(mCameraStatesLock);
-            auto iter = mCameraStates.find(id8);
-            if (iter != mCameraStates.end()) {
-                cameraFound = true;
+        if (nullptr == mCameraProviderManager.get()) {
+            mCameraProviderManager = new CameraProviderManager();
+            res = mCameraProviderManager->initialize(this);
+            if (res != OK) {
+                ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",
+                        __FUNCTION__, strerror(-res), res);
+                return res;
             }
         }
 
-        if (!cameraFound) {
-            addStates(id8);
+
+        // Setup vendor tags before we call get_camera_info the first time
+        // because HAL might need to setup static vendor keys in get_camera_info
+        // TODO: maybe put this into CameraProviderManager::initialize()?
+        mCameraProviderManager->setUpVendorTags();
+
+        if (nullptr == mFlashlight.get()) {
+            mFlashlight = new CameraFlashlight(mCameraProviderManager, this);
         }
 
+        res = mFlashlight->findFlashUnits();
+        if (res != OK) {
+            ALOGE("Failed to enumerate flash units: %s (%d)", strerror(-res), res);
+        }
+
+        deviceIds = mCameraProviderManager->getCameraDeviceIds();
+    }
+
+
+    for (auto& cameraId : deviceIds) {
+        String8 id8 = String8(cameraId.c_str());
         onDeviceStatusChanged(id8, CameraDeviceStatus::PRESENT);
     }
 
@@ -291,6 +216,13 @@
     enumerateProviders();
 }
 
+void CameraService::updateCameraNumAndIds() {
+    Mutex::Autolock l(mServiceLock);
+    mNumberOfCameras = mCameraProviderManager->getCameraCount();
+    mNormalDeviceIds =
+            mCameraProviderManager->getAPI1CompatibleCameraDeviceIds();
+}
+
 void CameraService::addStates(const String8 id) {
     std::string cameraId(id.c_str());
     hardware::camera::common::V1_0::CameraResourceCost cost;
@@ -313,10 +245,13 @@
     if (mFlashlight->hasFlashUnit(id)) {
         mTorchStatusMap.add(id, TorchModeStatus::AVAILABLE_OFF);
     }
+
+    updateCameraNumAndIds();
     logDeviceAdded(id, "Device added");
 }
 
 void CameraService::removeStates(const String8 id) {
+    updateCameraNumAndIds();
     if (mFlashlight->hasFlashUnit(id)) {
         mTorchStatusMap.removeItem(id);
     }
@@ -361,15 +296,16 @@
     if (newStatus == StatusInternal::NOT_PRESENT) {
         logDeviceRemoved(id, String8::format("Device status changed from %d to %d", oldStatus,
                 newStatus));
+
+        // Set the device status to NOT_PRESENT, clients will no longer be able to connect
+        // to this device until the status changes
+        updateStatus(StatusInternal::NOT_PRESENT, id);
+
         sp<BasicClient> clientToDisconnect;
         {
             // Don't do this in updateStatus to avoid deadlock over mServiceLock
             Mutex::Autolock lock(mServiceLock);
 
-            // Set the device status to NOT_PRESENT, clients will no longer be able to connect
-            // to this device until the status changes
-            updateStatus(StatusInternal::NOT_PRESENT, id);
-
             // Remove cached shim parameters
             state->setShimParams(CameraParameters());
 
@@ -472,7 +408,7 @@
     Mutex::Autolock l(mServiceLock);
     switch (type) {
         case CAMERA_TYPE_BACKWARD_COMPATIBLE:
-            *numCameras = mNumberOfNormalCameras;
+            *numCameras = static_cast<int>(mNormalDeviceIds.size());
             break;
         case CAMERA_TYPE_ALL:
             *numCameras = mNumberOfCameras;
@@ -502,7 +438,8 @@
     }
 
     Status ret = Status::ok();
-    status_t err = mCameraProviderManager->getCameraInfo(std::to_string(cameraId), cameraInfo);
+    status_t err = mCameraProviderManager->getCameraInfo(
+            cameraIdIntToStrLocked(cameraId), cameraInfo);
     if (err != OK) {
         ret = STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
                 "Error retrieving camera info from device %d: %s (%d)", cameraId,
@@ -512,13 +449,19 @@
     return ret;
 }
 
-int CameraService::cameraIdToInt(const String8& cameraId) {
-    int id;
-    bool success = base::ParseInt(cameraId.string(), &id, 0);
-    if (!success) {
-        return -1;
+std::string CameraService::cameraIdIntToStrLocked(int cameraIdInt) {
+    if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(mNormalDeviceIds.size())) {
+        ALOGE("%s: input id %d invalid: valid range  (0, %zu)",
+                __FUNCTION__, cameraIdInt, mNormalDeviceIds.size());
+        return std::string{};
     }
-    return id;
+
+    return mNormalDeviceIds[cameraIdInt];
+}
+
+String8 CameraService::cameraIdIntToStr(int cameraIdInt) {
+    Mutex::Autolock lock(mServiceLock);
+    return String8(cameraIdIntToStrLocked(cameraIdInt).c_str());
 }
 
 Status CameraService::getCameraCharacteristics(const String16& cameraId,
@@ -635,8 +578,8 @@
 
 Status CameraService::makeClient(const sp<CameraService>& cameraService,
         const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
-        int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
-        int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+        int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
+        bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
         /*out*/sp<BasicClient>* client) {
 
     if (halVersion < 0 || halVersion == deviceVersion) {
@@ -646,8 +589,9 @@
           case CAMERA_DEVICE_API_VERSION_1_0:
             if (effectiveApiLevel == API_1) {  // Camera1 API route
                 sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
-                *client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),
-                        facing, clientPid, clientUid, getpid(), legacyMode);
+                *client = new CameraClient(cameraService, tmp, packageName,
+                        api1CameraId, facing, clientPid, clientUid,
+                        getpid(), legacyMode);
             } else { // Camera2 API route
                 ALOGW("Camera using old HAL version: %d", deviceVersion);
                 return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
@@ -662,8 +606,10 @@
           case CAMERA_DEVICE_API_VERSION_3_4:
             if (effectiveApiLevel == API_1) { // Camera1 API route
                 sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
-                *client = new Camera2Client(cameraService, tmp, packageName, cameraIdToInt(cameraId),
-                        facing, clientPid, clientUid, servicePid, legacyMode);
+                *client = new Camera2Client(cameraService, tmp, packageName,
+                        cameraId, api1CameraId,
+                        facing, clientPid, clientUid,
+                        servicePid, legacyMode);
             } else { // Camera2 API route
                 sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
                         static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
@@ -685,8 +631,9 @@
             halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
             // Only support higher HAL version device opened as HAL1.0 device.
             sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
-            *client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),
-                    facing, clientPid, clientUid, servicePid, legacyMode);
+            *client = new CameraClient(cameraService, tmp, packageName,
+                    api1CameraId, facing, clientPid, clientUid,
+                    servicePid, legacyMode);
         } else {
             // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
             ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
@@ -782,7 +729,8 @@
     Status ret = Status::ok();
     sp<Client> tmp = nullptr;
     if (!(ret = connectHelper<ICameraClient,Client>(
-            sp<ICameraClient>{nullptr}, id, static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
+            sp<ICameraClient>{nullptr}, id, cameraId,
+            static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
             internalPackageName, uid, USE_CALLING_PID,
             API_1, /*legacyMode*/ false, /*shimUpdateOnly*/ true,
             /*out*/ tmp)
@@ -1235,7 +1183,7 @@
 
 Status CameraService::connect(
         const sp<ICameraClient>& cameraClient,
-        int cameraId,
+        int api1CameraId,
         const String16& clientPackageName,
         int clientUid,
         int clientPid,
@@ -1244,9 +1192,10 @@
 
     ATRACE_CALL();
     Status ret = Status::ok();
-    String8 id = String8::format("%d", cameraId);
+
+    String8 id = cameraIdIntToStr(api1CameraId);
     sp<Client> client = nullptr;
-    ret = connectHelper<ICameraClient,Client>(cameraClient, id,
+    ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
             CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
             /*legacyMode*/ false, /*shimUpdateOnly*/ false,
             /*out*/client);
@@ -1263,18 +1212,18 @@
 
 Status CameraService::connectLegacy(
         const sp<ICameraClient>& cameraClient,
-        int cameraId, int halVersion,
+        int api1CameraId, int halVersion,
         const String16& clientPackageName,
         int clientUid,
         /*out*/
         sp<ICamera>* device) {
 
     ATRACE_CALL();
-    String8 id = String8::format("%d", cameraId);
+    String8 id = cameraIdIntToStr(api1CameraId);
 
     Status ret = Status::ok();
     sp<Client> client = nullptr;
-    ret = connectHelper<ICameraClient,Client>(cameraClient, id, halVersion,
+    ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
             clientPackageName, clientUid, USE_CALLING_PID, API_1,
             /*legacyMode*/ true, /*shimUpdateOnly*/ false,
             /*out*/client);
@@ -1302,6 +1251,7 @@
     String8 id = String8(cameraId);
     sp<CameraDeviceClient> client = nullptr;
     ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
+            /*api1CameraId*/-1,
             CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
             clientUid, USE_CALLING_PID, API_2,
             /*legacyMode*/ false, /*shimUpdateOnly*/ false,
@@ -1319,8 +1269,8 @@
 
 template<class CALLBACK, class CLIENT>
 Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
-        int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
-        apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+        int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
+        int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
         /*out*/sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
 
@@ -1403,8 +1353,10 @@
         }
 
         sp<BasicClient> tmp = nullptr;
-        if(!(ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,
-                clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
+        if(!(ret = makeClient(this, cameraCb, clientPackageName,
+                cameraId, api1CameraId, facing,
+                clientPid, clientUid, getpid(), legacyMode,
+                halVersion, deviceVersion, effectiveApiLevel,
                 /*out*/&tmp)).isOk()) {
             return ret;
         }
@@ -1413,7 +1365,7 @@
         LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
                 __FUNCTION__);
 
-        err = client->initialize(mCameraProviderManager);
+        err = client->initialize(mCameraProviderManager, mMonitorTags);
         if (err != OK) {
             ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
             // Errors could be from the HAL module open call or from AppOpsManager
@@ -1782,8 +1734,6 @@
 }
 
 bool CameraService::evictClientIdByRemote(const wp<IBinder>& remote) {
-    const int callingPid = getCallingPid();
-    const int servicePid = getpid();
     bool ret = false;
     {
         // Acquire mServiceLock and prevent other clients from connecting
@@ -1799,8 +1749,7 @@
                 mActiveClientManager.remove(i);
                 continue;
             }
-            if (remote == clientSp->getRemote() && (callingPid == servicePid ||
-                    callingPid == clientSp->getClientPid())) {
+            if (remote == clientSp->getRemote()) {
                 mActiveClientManager.remove(i);
                 evicted.push_back(clientSp);
 
@@ -2112,7 +2061,8 @@
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
         const String16& clientPackageName,
-        const String8& cameraIdStr, int cameraFacing,
+        const String8& cameraIdStr,
+        int api1CameraId, int cameraFacing,
         int clientPid, uid_t clientUid,
         int servicePid) :
         CameraService::BasicClient(cameraService,
@@ -2121,7 +2071,7 @@
                 cameraIdStr, cameraFacing,
                 clientPid, clientUid,
                 servicePid),
-        mCameraId(CameraService::cameraIdToInt(cameraIdStr))
+        mCameraId(api1CameraId)
 {
     int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, mCameraId);
@@ -2676,7 +2626,10 @@
     }
     dprintf(fd, "\n== Service global info: ==\n\n");
     dprintf(fd, "Number of camera devices: %d\n", mNumberOfCameras);
-    dprintf(fd, "Number of normal camera devices: %d\n", mNumberOfNormalCameras);
+    dprintf(fd, "Number of normal camera devices: %zu\n", mNormalDeviceIds.size());
+    for (size_t i = 0; i < mNormalDeviceIds.size(); i++) {
+        dprintf(fd, "    Device %zu maps to \"%s\"\n", i, mNormalDeviceIds[i].c_str());
+    }
     String8 activeClientString = mActiveClientManager.toString();
     dprintf(fd, "Active Camera Clients:\n%s", activeClientString.string());
     dprintf(fd, "Allowed user IDs: %s\n", toString(mAllowedUsers).string());
@@ -2688,6 +2641,16 @@
         dprintf(fd, "CameraStates in use, may be deadlocked\n");
     }
 
+    int argSize = args.size();
+    for (int i = 0; i < argSize; i++) {
+        if (args[i] == TagMonitor::kMonitorOption) {
+            if (i + 1 < argSize) {
+                mMonitorTags = String8(args[i + 1]);
+            }
+            break;
+        }
+    }
+
     for (auto& state : mCameraStates) {
         String8 cameraId = state.first;
 
@@ -2815,7 +2778,7 @@
       * While tempting to promote the wp<IBinder> into a sp, it's actually not supported by the
       * binder driver
       */
-
+    // PID here is approximate and can be wrong.
     logClientDied(getCallingPid(), String8("Binder died unexpectedly"));
 
     // check torch client
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 67db7ec..cbfc50b 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -62,7 +62,6 @@
     public BinderService<CameraService>,
     public virtual ::android::hardware::BnCameraService,
     public virtual IBinder::DeathRecipient,
-    public camera_module_callbacks_t,
     public virtual CameraProviderManager::StatusListener
 {
     friend class BinderService<CameraService>;
@@ -205,7 +204,8 @@
 
     class BasicClient : public virtual RefBase {
     public:
-        virtual status_t       initialize(sp<CameraProviderManager> manager) = 0;
+        virtual status_t       initialize(sp<CameraProviderManager> manager,
+                const String8& monitorTags) = 0;
         virtual binder::Status disconnect();
 
         // because we can't virtually inherit IInterface, which breaks
@@ -333,6 +333,7 @@
                 const sp<hardware::ICameraClient>& cameraClient,
                 const String16& clientPackageName,
                 const String8& cameraIdStr,
+                int api1CameraId,
                 int cameraFacing,
                 int clientPid,
                 uid_t clientUid,
@@ -551,7 +552,8 @@
     // Eumerate all camera providers in the system
     status_t enumerateProviders();
 
-    // Add a new camera to camera and torch state lists or remove an unplugged one
+    // Add/remove a new camera to camera and torch state lists or remove an unplugged one
+    // Caller must not hold mServiceLock
     void addStates(const String8 id);
     void removeStates(const String8 id);
 
@@ -578,7 +580,7 @@
     // Single implementation shared between the various connect calls
     template<class CALLBACK, class CLIENT>
     binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
-            int halVersion, const String16& clientPackageName,
+            int api1CameraId, int halVersion, const String16& clientPackageName,
             int clientUid, int clientPid,
             apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
             /*out*/sp<CLIENT>& device);
@@ -605,6 +607,9 @@
     RingBuffer<String8> mEventLog;
     Mutex mLogLock;
 
+    // The last monitored tags set by client
+    String8 mMonitorTags;
+
     // Currently allowed user IDs
     std::set<userid_t> mAllowedUsers;
 
@@ -640,9 +645,16 @@
     void finishConnectLocked(const sp<BasicClient>& client, const DescriptorPtr& desc);
 
     /**
-     * Returns the integer corresponding to the given camera ID string, or -1 on failure.
+     * Returns the underlying camera Id string mapped to a camera id int
+     * Empty string is returned when the cameraIdInt is invalid.
      */
-    static int cameraIdToInt(const String8& cameraId);
+    String8 cameraIdIntToStr(int cameraIdInt);
+
+    /**
+     * Returns the underlying camera Id string mapped to a camera id int
+     * Empty string is returned when the cameraIdInt is invalid.
+     */
+    std::string cameraIdIntToStrLocked(int cameraIdInt);
 
     /**
      * Remove a single client corresponding to the given camera id from the list of active clients.
@@ -710,8 +722,14 @@
      */
     void dumpEventLog(int fd);
 
+    /**
+     * This method will acquire mServiceLock
+     */
+    void updateCameraNumAndIds();
+
     int                 mNumberOfCameras;
-    int                 mNumberOfNormalCameras;
+
+    std::vector<std::string> mNormalDeviceIds;
 
     // sounds
     MediaPlayer*        newMediaPlayer(const char *file);
@@ -821,8 +839,8 @@
 
     static binder::Status makeClient(const sp<CameraService>& cameraService,
             const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
-            int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
-            int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+            int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
+            bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
             /*out*/sp<BasicClient>* client);
 
     status_t checkCameraAccess(const String16& opPackageName);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 585d2eb..3578bba 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -49,16 +49,17 @@
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
         const sp<hardware::ICameraClient>& cameraClient,
         const String16& clientPackageName,
-        int cameraId,
+        const String8& cameraDeviceId,
+        int api1CameraId,
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
         int servicePid,
         bool legacyMode):
         Camera2ClientBase(cameraService, cameraClient, clientPackageName,
-                String8::format("%d", cameraId), cameraFacing,
+                cameraDeviceId, api1CameraId, cameraFacing,
                 clientPid, clientUid, servicePid),
-        mParameters(cameraId, cameraFacing)
+        mParameters(api1CameraId, cameraFacing)
 {
     ATRACE_CALL();
 
@@ -68,8 +69,8 @@
     mLegacyMode = legacyMode;
 }
 
-status_t Camera2Client::initialize(sp<CameraProviderManager> manager) {
-    return initializeImpl(manager);
+status_t Camera2Client::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
+    return initializeImpl(manager, monitorTags);
 }
 
 bool Camera2Client::isZslEnabledInStillTemplate() {
@@ -87,13 +88,13 @@
 }
 
 template<typename TProviderPtr>
-status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
+status_t Camera2Client::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags)
 {
     ATRACE_CALL();
     ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
-    res = Camera2ClientBase::initialize(providerPtr);
+    res = Camera2ClientBase::initialize(providerPtr, monitorTags);
     if (res != OK) {
         return res;
     }
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 5af74eb..44929c3 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -91,7 +91,8 @@
     Camera2Client(const sp<CameraService>& cameraService,
             const sp<hardware::ICameraClient>& cameraClient,
             const String16& clientPackageName,
-            int cameraId,
+            const String8& cameraDeviceId,
+            int api1CameraId,
             int cameraFacing,
             int clientPid,
             uid_t clientUid,
@@ -100,7 +101,8 @@
 
     virtual ~Camera2Client();
 
-    virtual status_t initialize(sp<CameraProviderManager> manager) override;
+    virtual status_t initialize(sp<CameraProviderManager> manager,
+            const String8& monitorTags) override;
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
@@ -223,7 +225,7 @@
     status_t overrideVideoSnapshotSize(Parameters &params);
 
     template<typename TProviderPtr>
-    status_t initializeImpl(TProviderPtr providerPtr);
+    status_t initializeImpl(TProviderPtr providerPtr, const String8& monitorTags);
 
     bool isZslEnabledInStillTemplate();
 };
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index e848a3f..f6d27ab 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -42,7 +42,7 @@
         int clientPid, int clientUid,
         int servicePid, bool legacyMode):
         Client(cameraService, cameraClient, clientPackageName,
-                String8::format("%d", cameraId), cameraFacing, clientPid,
+                String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
                 clientUid, servicePid)
 {
     int callingPid = getCallingPid();
@@ -62,7 +62,8 @@
     LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
 }
 
-status_t CameraClient::initialize(sp<CameraProviderManager> manager) {
+status_t CameraClient::initialize(sp<CameraProviderManager> manager,
+        const String8& /*monitorTags*/) {
     int callingPid = getCallingPid();
     status_t res;
 
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 7f93fef..1910536 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -72,7 +72,8 @@
             bool legacyMode = false);
     ~CameraClient();
 
-    virtual status_t initialize(sp<CameraProviderManager> manager) override;
+    virtual status_t initialize(sp<CameraProviderManager> manager,
+            const String8& monitorTags) override;
 
     virtual status_t dump(int fd, const Vector<String16>& args);
 
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 050c3f7..b4c7e9d 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -759,12 +759,17 @@
     focusingAreas.clear();
     focusingAreas.add(Parameters::Area(0,0,0,0,0));
 
-    camera_metadata_ro_entry_t availableFocalLengths =
-        staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, false);
-    if (!availableFocalLengths.count) return NO_INIT;
+    if (fastInfo.isExternalCamera) {
+        params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, -1.0);
+    } else {
+        camera_metadata_ro_entry_t availableFocalLengths =
+            staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, false);
+        if (!availableFocalLengths.count) return NO_INIT;
 
-    float minFocalLength = availableFocalLengths.data.f[0];
-    params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+        float minFocalLength = availableFocalLengths.data.f[0];
+        params.setFloat(CameraParameters::KEY_FOCAL_LENGTH, minFocalLength);
+    }
+
 
     float horizFov, vertFov;
     res = calculatePictureFovs(&horizFov, &vertFov);
@@ -1091,9 +1096,15 @@
             focusDistanceCalibration.data.u8[0] !=
             ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED);
 
+
+    camera_metadata_ro_entry_t hwLevel = staticInfo(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
+    if (!hwLevel.count) return NO_INIT;
+    fastInfo.isExternalCamera =
+            hwLevel.data.u8[0] == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
+
     camera_metadata_ro_entry_t availableFocalLengths =
-        staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
-    if (!availableFocalLengths.count) return NO_INIT;
+        staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, /*required*/false);
+    if (!availableFocalLengths.count && !fastInfo.isExternalCamera) return NO_INIT;
 
     SortedVector<int32_t> availableFormats = getAvailableOutputFormats();
     if (!availableFormats.size()) return NO_INIT;
@@ -1178,10 +1189,14 @@
 
     // Find smallest (widest-angle) focal length to use as basis of still
     // picture FOV reporting.
-    fastInfo.minFocalLength = availableFocalLengths.data.f[0];
-    for (size_t i = 1; i < availableFocalLengths.count; i++) {
-        if (fastInfo.minFocalLength > availableFocalLengths.data.f[i]) {
-            fastInfo.minFocalLength = availableFocalLengths.data.f[i];
+    if (fastInfo.isExternalCamera) {
+        fastInfo.minFocalLength = -1.0;
+    } else {
+        fastInfo.minFocalLength = availableFocalLengths.data.f[0];
+        for (size_t i = 1; i < availableFocalLengths.count; i++) {
+            if (fastInfo.minFocalLength > availableFocalLengths.data.f[i]) {
+                fastInfo.minFocalLength = availableFocalLengths.data.f[i];
+            }
         }
     }
 
@@ -2870,8 +2885,13 @@
         if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
                 sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
                 sc.width <= limit.width && sc.height <= limit.height) {
-            Size sz = {sc.width, sc.height};
-            sizes->push(sz);
+            int64_t minFrameDuration = getMinFrameDurationNs(
+                    {sc.width, sc.height}, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+            if (minFrameDuration > MAX_PREVIEW_RECORD_DURATION_NS) {
+                // Filter slow sizes from preview/record
+                continue;
+            }
+            sizes->push({sc.width, sc.height});
         }
     }
 
@@ -3081,6 +3101,16 @@
 
 status_t Parameters::calculatePictureFovs(float *horizFov, float *vertFov)
         const {
+    if (fastInfo.isExternalCamera) {
+        if (horizFov != NULL) {
+            *horizFov = -1.0;
+        }
+        if (vertFov != NULL) {
+            *vertFov = -1.0;
+        }
+        return OK;
+    }
+
     camera_metadata_ro_entry_t sensorSize =
             staticInfo(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, 2, 2);
     if (!sensorSize.count) return NO_INIT;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 17e3d75..fe725fd 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -207,6 +207,11 @@
     static const int32_t FPS_MARGIN = 1;
     // Max FPS for default parameters
     static const int32_t MAX_DEFAULT_FPS = 30;
+    // Minimum FPS for a size to be listed in supported preview/video sizes
+    // Set to slightly less than 30.0 to have some tolerance margin
+    static constexpr double MIN_PREVIEW_RECORD_FPS = 29.97;
+    // Maximum frame duration for a size to be listed in supported preview/video sizes
+    static constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / MIN_PREVIEW_RECORD_FPS;
 
     // Full static camera info, object owned by someone else, such as
     // Camera2Device.
@@ -233,6 +238,7 @@
             }
         };
         DefaultKeyedVector<uint8_t, OverrideModes> sceneModeOverrides;
+        bool isExternalCamera;
         float minFocalLength;
         bool useFlexibleYuv;
         Size maxJpegSize;
@@ -380,6 +386,7 @@
     Vector<Size> availablePreviewSizes;
     Vector<Size> availableVideoSizes;
     // Get size list (that are no larger than limit) from static metadata.
+    // This method filtered size with minFrameDuration < MAX_PREVIEW_RECORD_DURATION_NS
     status_t getFilteredSizes(Size limit, Vector<Size> *sizes);
     // Get max size (from the size array) that matches the given aspect ratio.
     Size getMaxSizeForRatio(float ratio, const int32_t* sizeArray, size_t count);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 8e112a1..efe3ca1 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -28,6 +28,8 @@
 #include "common/CameraDeviceBase.h"
 #include "api2/CameraDeviceClient.h"
 
+#include <camera_metadata_hidden.h>
+
 // Convenience methods for constructing binder::Status objects for error returns
 
 #define STATUS_ERROR(errorCode, errorString) \
@@ -47,6 +49,7 @@
         const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
         const String16& clientPackageName,
         const String8& cameraId,
+        int api1CameraId,
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
@@ -60,6 +63,8 @@
             clientUid,
             servicePid),
     mRemoteCallback(remoteCallback) {
+    // We don't need it for API2 clients, but Camera2ClientBase requires it.
+    (void) api1CameraId;
 }
 
 // Interface used by CameraService
@@ -73,7 +78,8 @@
         uid_t clientUid,
         int servicePid) :
     Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
-                cameraId, cameraFacing, clientPid, clientUid, servicePid),
+                cameraId, /*API1 camera ID*/ -1,
+                cameraFacing, clientPid, clientUid, servicePid),
     mInputStream(),
     mStreamingRequestId(REQUEST_ID_NONE),
     mRequestIdCounter(0) {
@@ -82,16 +88,17 @@
     ALOGI("CameraDeviceClient %s: Opened", cameraId.string());
 }
 
-status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager) {
-    return initializeImpl(manager);
+status_t CameraDeviceClient::initialize(sp<CameraProviderManager> manager,
+        const String8& monitorTags) {
+    return initializeImpl(manager, monitorTags);
 }
 
 template<typename TProviderPtr>
-status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr) {
+status_t CameraDeviceClient::initializeImpl(TProviderPtr providerPtr, const String8& monitorTags) {
     ATRACE_CALL();
     status_t res;
 
-    res = Camera2ClientBase::initialize(providerPtr);
+    res = Camera2ClientBase::initialize(providerPtr, monitorTags);
     if (res != OK) {
         return res;
     }
@@ -106,6 +113,15 @@
                                       /*listener*/this,
                                       /*sendPartials*/true);
 
+    auto deviceInfo = mDevice->info();
+    camera_metadata_entry_t physicalKeysEntry = deviceInfo.find(
+            ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
+    if (physicalKeysEntry.count > 0) {
+        mSupportedPhysicalRequestKeys.insert(mSupportedPhysicalRequestKeys.begin(),
+                physicalKeysEntry.data.i32,
+                physicalKeysEntry.data.i32 + physicalKeysEntry.count);
+    }
+
     return OK;
 }
 
@@ -291,6 +307,13 @@
 
         CameraDeviceBase::PhysicalCameraSettingsList physicalSettingsList;
         for (const auto& it : request.mPhysicalCameraSettings) {
+            if (it.settings.isEmpty()) {
+                ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
+                        __FUNCTION__, mCameraIdStr.string());
+                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+                        "Request settings are empty");
+            }
+
             String8 physicalId(it.id.c_str());
             if (physicalId != mDevice->getId()) {
                 auto found = std::find(requestedPhysicalIds.begin(), requestedPhysicalIds.end(),
@@ -301,24 +324,27 @@
                     return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
                             "Invalid physical camera id");
                 }
+
+                if (!mSupportedPhysicalRequestKeys.empty()) {
+                    // Filter out any unsupported physical request keys.
+                    CameraMetadata filteredParams(mSupportedPhysicalRequestKeys.size());
+                    camera_metadata_t *meta = const_cast<camera_metadata_t *>(
+                            filteredParams.getAndLock());
+                    set_camera_metadata_vendor_id(meta, mDevice->getVendorTagId());
+                    filteredParams.unlock(meta);
+
+                    for (const auto& keyIt : mSupportedPhysicalRequestKeys) {
+                        camera_metadata_ro_entry entry = it.settings.find(keyIt);
+                        if (entry.count > 0) {
+                            filteredParams.update(entry);
+                        }
+                    }
+
+                    physicalSettingsList.push_back({it.id, filteredParams});
+                }
+            } else {
+                physicalSettingsList.push_back({it.id, it.settings});
             }
-
-            CameraMetadata metadata(it.settings);
-            if (metadata.isEmpty()) {
-                ALOGE("%s: Camera %s: Sent empty metadata packet. Rejecting request.",
-                        __FUNCTION__, mCameraIdStr.string());
-                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                        "Request settings are empty");
-            }
-
-            physicalSettingsList.push_back({it.id, metadata});
-        }
-
-        if (streaming && (physicalSettingsList.size() > 1)) {
-            ALOGE("%s: Camera %s: Individual physical camera settings are not supported in "
-                    "streaming requests. Rejecting request.", __FUNCTION__, mCameraIdStr.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
-                    "Streaming request contains individual physical requests");
         }
 
         if (!enforceRequestPermissions(physicalSettingsList.begin()->metadata)) {
@@ -633,14 +659,6 @@
             return res;
 
         if (!isStreamInfoValid) {
-            // Streaming sharing is only supported for IMPLEMENTATION_DEFINED
-            // formats.
-            if (isShared && streamInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-                String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
-                        "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
-                ALOGW("%s: %s", __FUNCTION__, msg.string());
-                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-            }
             isStreamInfoValid = true;
         }
 
@@ -920,14 +938,6 @@
         if (!res.isOk())
             return res;
 
-        // Stream sharing is only supported for IMPLEMENTATION_DEFINED
-        // formats.
-        if (outInfo.format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-            String8 msg = String8::format("Camera %s: Stream sharing is only supported for "
-                    "IMPLEMENTATION_DEFINED format", mCameraIdStr.string());
-            ALOGW("%s: %s", __FUNCTION__, msg.string());
-            return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
-        }
         streamInfos.push_back(outInfo);
         newOutputs.push_back(surface);
     }
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 435c99d..5aaf5aa 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -45,6 +45,7 @@
             const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
             const String16& clientPackageName,
             const String8& cameraId,
+            int api1CameraId,
             int cameraFacing,
             int clientPid,
             uid_t clientUid,
@@ -156,7 +157,8 @@
             int servicePid);
     virtual ~CameraDeviceClient();
 
-    virtual status_t      initialize(sp<CameraProviderManager> manager) override;
+    virtual status_t      initialize(sp<CameraProviderManager> manager,
+            const String8& monitorTags) override;
 
     virtual status_t      dump(int fd, const Vector<String16>& args);
 
@@ -221,8 +223,10 @@
     static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
     static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
 
+    std::vector<int32_t> mSupportedPhysicalRequestKeys;
+
     template<typename TProviderPtr>
-    status_t      initializeImpl(TProviderPtr providerPtr);
+    status_t      initializeImpl(TProviderPtr providerPtr, const String8& monitorTags);
 
     /** Utility members */
     binder::Status checkPidStatus(const char* checkLocation);
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 4ce82dc..459e45d 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -48,15 +48,16 @@
         const sp<TCamCallbacks>& remoteCallback,
         const String16& clientPackageName,
         const String8& cameraId,
+        int api1CameraId,
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
         int servicePid):
         TClientBase(cameraService, remoteCallback, clientPackageName,
-                cameraId, cameraFacing, clientPid, clientUid, servicePid),
+                cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
         mSharedCameraCallbacks(remoteCallback),
         mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
-        mDeviceActive(false)
+        mDeviceActive(false), mApi1CameraId(api1CameraId)
 {
     ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
             String8(clientPackageName).string(), clientPid, clientUid);
@@ -79,13 +80,15 @@
 }
 
 template <typename TClientBase>
-status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager) {
-    return initializeImpl(manager);
+status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager,
+        const String8& monitorTags) {
+    return initializeImpl(manager, monitorTags);
 }
 
 template <typename TClientBase>
 template <typename TProviderPtr>
-status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr) {
+status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr,
+        const String8& monitorTags) {
     ATRACE_CALL();
     ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
           TClientBase::mCameraIdStr.string());
@@ -103,7 +106,7 @@
         return NO_INIT;
     }
 
-    res = mDevice->initialize(providerPtr);
+    res = mDevice->initialize(providerPtr, monitorTags);
     if (res != OK) {
         ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
                 __FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res);
@@ -329,7 +332,7 @@
 
 template <typename TClientBase>
 int Camera2ClientBase<TClientBase>::getCameraId() const {
-    return std::stoi(TClientBase::mCameraIdStr.string());
+    return mApi1CameraId;
 }
 
 template <typename TClientBase>
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index e898d5d..e74fbdf 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -49,13 +49,14 @@
                       const sp<TCamCallbacks>& remoteCallback,
                       const String16& clientPackageName,
                       const String8& cameraId,
+                      int api1CameraId,
                       int cameraFacing,
                       int clientPid,
                       uid_t clientUid,
                       int servicePid);
     virtual ~Camera2ClientBase();
 
-    virtual status_t      initialize(sp<CameraProviderManager> manager);
+    virtual status_t      initialize(sp<CameraProviderManager> manager, const String8& monitorTags);
     virtual status_t      dumpClient(int fd, const Vector<String16>& args);
 
     /**
@@ -140,9 +141,11 @@
 
     bool                  mDeviceActive;
 
+    const int             mApi1CameraId; // -1 if client is API2
+
 private:
     template<typename TProviderPtr>
-    status_t              initializeImpl(TProviderPtr providerPtr);
+    status_t              initializeImpl(TProviderPtr providerPtr, const String8& monitorTags);
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 7956be5..0ba7403 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -55,7 +55,12 @@
      */
     virtual const String8& getId() const = 0;
 
-    virtual status_t initialize(sp<CameraProviderManager> manager) = 0;
+    /**
+     * The device vendor tag ID
+     */
+    virtual metadata_vendor_id_t getVendorTagId() const = 0;
+
+    virtual status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) = 0;
     virtual status_t disconnect() = 0;
 
     virtual status_t dump(int fd, const Vector<String16> &args) = 0;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 70e7761..b37f004 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -20,11 +20,13 @@
 
 #include "CameraProviderManager.h"
 
+#include <algorithm>
 #include <chrono>
 #include <inttypes.h>
 #include <hidl/ServiceManagement.h>
 #include <functional>
 #include <camera_metadata_hidden.h>
+#include <android-base/parseint.h>
 
 namespace android {
 
@@ -38,7 +40,7 @@
 const std::string kExternalProviderName("external/0");
 
 // Slash-separated list of provider types to consider for use via the old camera API
-const std::string kStandardProviderTypes("internal/legacy");
+const std::string kStandardProviderTypes("internal/legacy/external");
 
 } // anonymous namespace
 
@@ -79,18 +81,7 @@
     std::lock_guard<std::mutex> lock(mInterfaceMutex);
     int count = 0;
     for (auto& provider : mProviders) {
-        count += provider->mUniqueDeviceCount;
-    }
-    return count;
-}
-
-int CameraProviderManager::getAPI1CompatibleCameraCount() const {
-    std::lock_guard<std::mutex> lock(mInterfaceMutex);
-    int count = 0;
-    for (auto& provider : mProviders) {
-        if (kStandardProviderTypes.find(provider->getType()) != std::string::npos) {
-            count += provider->mUniqueAPI1CompatibleCameraIds.size();
-        }
+        count += provider->mUniqueCameraIds.size();
     }
     return count;
 }
@@ -116,6 +107,24 @@
             }
         }
     }
+
+    std::sort(deviceIds.begin(), deviceIds.end(),
+            [](const std::string& a, const std::string& b) -> bool {
+                uint32_t aUint = 0, bUint = 0;
+                bool aIsUint = base::ParseUint(a, &aUint);
+                bool bIsUint = base::ParseUint(b, &bUint);
+
+                // Uint device IDs first
+                if (aIsUint && bIsUint) {
+                    return aUint < bUint;
+                } else if (aIsUint) {
+                    return true;
+                } else if (bIsUint) {
+                    return false;
+                }
+                // Simple string compare if both id are not uint
+                return a < b;
+            });
     return deviceIds;
 }
 
@@ -480,6 +489,8 @@
     }
     ALOGI("Connecting to new camera provider: %s, isRemote? %d",
             mProviderName.c_str(), mInterface->isRemote());
+    // cameraDeviceStatusChange callbacks may be called (and causing new devices added)
+    // before setCallback returns
     hardware::Return<Status> status = mInterface->setCallback(this);
     if (!status.isOk()) {
         ALOGE("%s: Transaction error setting up callbacks with camera provider '%s': %s",
@@ -536,17 +547,10 @@
         }
     }
 
-    for (auto& device : mDevices) {
-        mUniqueCameraIds.insert(device->mId);
-        if (device->isAPI1Compatible()) {
-            mUniqueAPI1CompatibleCameraIds.insert(device->mId);
-        }
-    }
-    mUniqueDeviceCount = mUniqueCameraIds.size();
-
     ALOGI("Camera provider %s ready with %zu camera devices",
             mProviderName.c_str(), mDevices.size());
 
+    mInitialized = true;
     return OK;
 }
 
@@ -594,9 +598,15 @@
     }
     if (deviceInfo == nullptr) return BAD_VALUE;
     deviceInfo->mStatus = initialStatus;
+    bool isAPI1Compatible = deviceInfo->isAPI1Compatible();
 
     mDevices.push_back(std::move(deviceInfo));
 
+    mUniqueCameraIds.insert(id);
+    if (isAPI1Compatible) {
+        mUniqueAPI1CompatibleCameraIds.insert(id);
+    }
+
     if (parsedId != nullptr) {
         *parsedId = id;
     }
@@ -606,6 +616,10 @@
 void CameraProviderManager::ProviderInfo::removeDevice(std::string id) {
     for (auto it = mDevices.begin(); it != mDevices.end(); it++) {
         if ((*it)->mId == id) {
+            mUniqueCameraIds.erase(id);
+            if ((*it)->isAPI1Compatible()) {
+                mUniqueAPI1CompatibleCameraIds.erase(id);
+            }
             mDevices.erase(it);
             break;
         }
@@ -671,6 +685,7 @@
         CameraDeviceStatus newStatus) {
     sp<StatusListener> listener;
     std::string id;
+    bool initialized = false;
     {
         std::lock_guard<std::mutex> lock(mLock);
         bool known = false;
@@ -697,9 +712,13 @@
             removeDevice(id);
         }
         listener = mManager->getStatusListener();
+        initialized = mInitialized;
     }
     // Call without lock held to allow reentrancy into provider manager
-    if (listener != nullptr) {
+    // Don't send the callback if providerInfo hasn't been initialized.
+    // CameraService will initialize device status after provider is
+    // initialized
+    if (listener != nullptr && initialized) {
         listener->onDeviceStatusChanged(String8(id.c_str()), newStatus);
     }
     return hardware::Void();
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index d02abb0..bbe6789 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -18,7 +18,7 @@
 #define ANDROID_SERVERS_CAMERA_CAMERAPROVIDER_H
 
 #include <vector>
-#include <set>
+#include <unordered_set>
 #include <string>
 #include <mutex>
 
@@ -125,16 +125,14 @@
      */
     int getCameraCount() const;
 
+    std::vector<std::string> getCameraDeviceIds() const;
+
     /**
      * Retrieve the number of API1 compatible cameras; these are internal and
      * backwards-compatible. This is the set of cameras that will be
-     * accessible via the old camera API, with IDs in range of
-     * [0, getAPI1CompatibleCameraCount()-1]. This value is not expected to change dynamically.
+     * accessible via the old camera API.
+     * The return value may change dynamically due to external camera hotplug.
      */
-    int getAPI1CompatibleCameraCount() const;
-
-    std::vector<std::string> getCameraDeviceIds() const;
-
     std::vector<std::string> getAPI1CompatibleCameraDeviceIds() const;
 
     /**
@@ -314,9 +312,9 @@
             static status_t setTorchMode(InterfaceT& interface, bool enabled);
         };
         std::vector<std::unique_ptr<DeviceInfo>> mDevices;
-        std::set<std::string> mUniqueCameraIds;
+        std::unordered_set<std::string> mUniqueCameraIds;
         int mUniqueDeviceCount;
-        std::set<std::string> mUniqueAPI1CompatibleCameraIds;
+        std::unordered_set<std::string> mUniqueAPI1CompatibleCameraIds;
 
         // HALv1-specific camera fields, including the actual device interface
         struct DeviceInfo1 : public DeviceInfo {
@@ -366,6 +364,8 @@
 
         CameraProviderManager *mManager;
 
+        bool mInitialized = false;
+
         // Templated method to instantiate the right kind of DeviceInfo and call the
         // right CameraProvider getCameraDeviceInterface_* method.
         template<class DeviceInfoT>
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 324201b..42bcb2d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -96,7 +96,7 @@
     return mId;
 }
 
-status_t Camera3Device::initialize(sp<CameraProviderManager> manager) {
+status_t Camera3Device::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
     ATRACE_CALL();
     Mutex::Autolock il(mInterfaceLock);
     Mutex::Autolock l(mLock);
@@ -169,6 +169,10 @@
     mInterface = new HalInterface(session, queue);
     std::string providerType;
     mVendorTagId = manager->getProviderTagIdLocked(mId.string());
+    mTagMonitor.initialize(mVendorTagId);
+    if (!monitorTags.isEmpty()) {
+        mTagMonitor.parseTagsToMonitor(String8(monitorTags));
+    }
 
     return initializeCommonLocked();
 }
@@ -192,8 +196,6 @@
     /** Create buffer manager */
     mBufferManager = new Camera3BufferManager();
 
-    mTagMonitor.initialize(mVendorTagId);
-
     Vector<int32_t> sessionParamKeys;
     camera_metadata_entry_t sessionKeysEntry = mDeviceInfo.find(
             ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
@@ -582,13 +584,12 @@
     bool dumpTemplates = false;
 
     String16 templatesOption("-t");
-    String16 monitorOption("-m");
     int n = args.size();
     for (int i = 0; i < n; i++) {
         if (args[i] == templatesOption) {
             dumpTemplates = true;
         }
-        if (args[i] == monitorOption) {
+        if (args[i] == TagMonitor::kMonitorOption) {
             if (i + 1 < n) {
                 String8 monitorTags = String8(args[i + 1]);
                 if (monitorTags == "off") {
@@ -676,8 +677,6 @@
             "TEMPLATE_VIDEO_SNAPSHOT",
             "TEMPLATE_ZERO_SHUTTER_LAG",
             "TEMPLATE_MANUAL",
-            "TEMPLATE_MOTION_TRACKING_PREVIEW",
-            "TEMPALTE_MOTION_TRACKING_BEST"
         };
 
         for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
@@ -3435,65 +3434,31 @@
             }
         };
     hardware::Return<void> err;
-    if (mHidlSession_3_4 != nullptr) {
-        device::V3_4::RequestTemplate id;
-        switch (templateId) {
-            case CAMERA3_TEMPLATE_PREVIEW:
-                id = device::V3_4::RequestTemplate::PREVIEW;
-                break;
-            case CAMERA3_TEMPLATE_STILL_CAPTURE:
-                id = device::V3_4::RequestTemplate::STILL_CAPTURE;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_RECORD:
-                id = device::V3_4::RequestTemplate::VIDEO_RECORD;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
-                id = device::V3_4::RequestTemplate::VIDEO_SNAPSHOT;
-                break;
-            case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
-                id = device::V3_4::RequestTemplate::ZERO_SHUTTER_LAG;
-                break;
-            case CAMERA3_TEMPLATE_MANUAL:
-                id = device::V3_4::RequestTemplate::MANUAL;
-                break;
-            case CAMERA3_TEMPLATE_MOTION_TRACKING_PREVIEW:
-                id = device::V3_4::RequestTemplate::MOTION_TRACKING_PREVIEW;
-                break;
-            case CAMERA3_TEMPLATE_MOTION_TRACKING_BEST:
-                id = device::V3_4::RequestTemplate::MOTION_TRACKING_BEST;
-                break;
-            default:
-                // Unknown template ID
-                return BAD_VALUE;
-        }
-        err = mHidlSession_3_4->constructDefaultRequestSettings_3_4(id, requestCallback);
-    } else {
-        RequestTemplate id;
-        switch (templateId) {
-            case CAMERA3_TEMPLATE_PREVIEW:
-                id = RequestTemplate::PREVIEW;
-                break;
-            case CAMERA3_TEMPLATE_STILL_CAPTURE:
-                id = RequestTemplate::STILL_CAPTURE;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_RECORD:
-                id = RequestTemplate::VIDEO_RECORD;
-                break;
-            case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
-                id = RequestTemplate::VIDEO_SNAPSHOT;
-                break;
-            case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
-                id = RequestTemplate::ZERO_SHUTTER_LAG;
-                break;
-            case CAMERA3_TEMPLATE_MANUAL:
-                id = RequestTemplate::MANUAL;
-                break;
-            default:
-                // Unknown template ID, or this HAL is too old to support it
-                return BAD_VALUE;
-        }
-        err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
+    RequestTemplate id;
+    switch (templateId) {
+        case CAMERA3_TEMPLATE_PREVIEW:
+            id = RequestTemplate::PREVIEW;
+            break;
+        case CAMERA3_TEMPLATE_STILL_CAPTURE:
+            id = RequestTemplate::STILL_CAPTURE;
+            break;
+        case CAMERA3_TEMPLATE_VIDEO_RECORD:
+            id = RequestTemplate::VIDEO_RECORD;
+            break;
+        case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
+            id = RequestTemplate::VIDEO_SNAPSHOT;
+            break;
+        case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
+            id = RequestTemplate::ZERO_SHUTTER_LAG;
+            break;
+        case CAMERA3_TEMPLATE_MANUAL:
+            id = RequestTemplate::MANUAL;
+            break;
+        default:
+            // Unknown template ID, or this HAL is too old to support it
+            return BAD_VALUE;
     }
+    err = mHidlSession->constructDefaultRequestSettings(id, requestCallback);
 
     if (!err.isOk()) {
         ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
@@ -3864,21 +3829,27 @@
         if (hidlSession_3_4 != nullptr) {
             captureRequests_3_4[i].physicalCameraSettings.resize(request->num_physcam_settings);
             for (size_t j = 0; j < request->num_physcam_settings; j++) {
-                size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
-                if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
-                            reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
-                            settingsSize)) {
-                    captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
-                    captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = settingsSize;
-                } else {
-                    if (mRequestMetadataQueue != nullptr) {
-                        ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+                if (request->physcam_settings != nullptr) {
+                    size_t settingsSize = get_camera_metadata_size(request->physcam_settings[j]);
+                    if (mRequestMetadataQueue != nullptr && mRequestMetadataQueue->write(
+                                reinterpret_cast<const uint8_t*>(request->physcam_settings[j]),
+                                settingsSize)) {
+                        captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
+                        captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize =
+                            settingsSize;
+                    } else {
+                        if (mRequestMetadataQueue != nullptr) {
+                            ALOGW("%s: couldn't utilize fmq, fallback to hwbinder", __FUNCTION__);
+                        }
+                        captureRequests_3_4[i].physicalCameraSettings[j].settings.setToExternal(
+                                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
+                                        request->physcam_settings[j])),
+                                get_camera_metadata_size(request->physcam_settings[j]));
+                        captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = 0u;
                     }
-                    captureRequests_3_4[i].physicalCameraSettings[j].settings.setToExternal(
-                            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(
-                                    request->physcam_settings[j])),
-                            get_camera_metadata_size(request->physcam_settings[j]));
+                } else {
                     captureRequests_3_4[i].physicalCameraSettings[j].fmqSettingsSize = 0u;
+                    captureRequests_3_4[i].physicalCameraSettings[j].settings.resize(0);
                 }
                 captureRequests_3_4[i].physicalCameraSettings[j].physicalCameraId =
                     request->physcam_id[j];
@@ -4716,7 +4687,8 @@
         mPrevTriggers = triggerCount;
 
         // If the request is the same as last, or we had triggers last time
-        if (mPrevRequest != captureRequest || triggersMixedIn) {
+        bool newRequest = mPrevRequest != captureRequest || triggersMixedIn;
+        if (newRequest) {
             /**
              * HAL workaround:
              * Insert a dummy trigger ID if a trigger is set but no trigger ID is
@@ -4761,14 +4733,20 @@
         if (captureRequest->mSettingsList.size() > 1) {
             halRequest->num_physcam_settings = captureRequest->mSettingsList.size() - 1;
             halRequest->physcam_id = new const char* [halRequest->num_physcam_settings];
-            halRequest->physcam_settings =
-                new const camera_metadata* [halRequest->num_physcam_settings];
+            if (newRequest) {
+                halRequest->physcam_settings =
+                    new const camera_metadata* [halRequest->num_physcam_settings];
+            } else {
+                halRequest->physcam_settings = nullptr;
+            }
             auto it = ++captureRequest->mSettingsList.begin();
             size_t i = 0;
             for (; it != captureRequest->mSettingsList.end(); it++, i++) {
                 halRequest->physcam_id[i] = it->cameraId.c_str();
-                it->metadata.sort();
-                halRequest->physcam_settings[i] = it->metadata.getAndLock();
+                if (newRequest) {
+                    it->metadata.sort();
+                    halRequest->physcam_settings[i] = it->metadata.getAndLock();
+                }
             }
         }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 12cb6b4..13b83ba 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -93,8 +93,10 @@
 
     const String8& getId() const override;
 
+    metadata_vendor_id_t getVendorTagId() const override { return mVendorTagId; }
+
     // Transitions to idle state on success.
-    status_t initialize(sp<CameraProviderManager> manager) override;
+    status_t initialize(sp<CameraProviderManager> manager, const String8& monitorTags) override;
     status_t disconnect() override;
     status_t dump(int fd, const Vector<String16> &args) override;
     const CameraMetadata& info() const override;
diff --git a/services/camera/libcameraservice/utils/TagMonitor.cpp b/services/camera/libcameraservice/utils/TagMonitor.cpp
index dec97d7..c0a353f 100644
--- a/services/camera/libcameraservice/utils/TagMonitor.cpp
+++ b/services/camera/libcameraservice/utils/TagMonitor.cpp
@@ -33,6 +33,8 @@
         mVendorTagId(CAMERA_METADATA_INVALID_VENDOR_ID)
 {}
 
+const String16 TagMonitor::kMonitorOption = String16("-m");
+
 const char* TagMonitor::k3aTags =
         "android.control.aeMode, android.control.afMode, android.control.awbMode,"
         "android.control.aeState, android.control.afState, android.control.awbState,"
diff --git a/services/camera/libcameraservice/utils/TagMonitor.h b/services/camera/libcameraservice/utils/TagMonitor.h
index 7155314..2dece62 100644
--- a/services/camera/libcameraservice/utils/TagMonitor.h
+++ b/services/camera/libcameraservice/utils/TagMonitor.h
@@ -38,6 +38,10 @@
  * buffer log that can be dumped at will. */
 class TagMonitor {
   public:
+
+    // Monitor argument
+    static const String16 kMonitorOption;
+
     enum eventSource {
         REQUEST,
         RESULT
diff --git a/services/minijail/Android.bp b/services/minijail/Android.bp
new file mode 100644
index 0000000..07a94cc
--- /dev/null
+++ b/services/minijail/Android.bp
@@ -0,0 +1,38 @@
+minijail_common_cflags = [
+    "-Wall",
+    "-Werror",
+]
+
+cc_defaults {
+    name: "libavservices_minijail_defaults",
+    srcs: ["minijail.cpp"],
+    cflags: minijail_common_cflags,
+    shared_libs: [
+        "libbase",
+        "libminijail",
+    ],
+}
+
+// Small library for media.extractor and media.codec sandboxing.
+cc_library_shared {
+    name: "libavservices_minijail",
+    defaults: ["libavservices_minijail_defaults"],
+    export_include_dirs: ["."],
+}
+
+// Small library for media.extractor and media.codec sandboxing.
+cc_library_shared {
+    name: "libavservices_minijail_vendor",
+    vendor: true,
+    defaults: ["libavservices_minijail_defaults"],
+    export_include_dirs: ["."],
+}
+
+// Unit tests.
+cc_test {
+    name: "libavservices_minijail_unittest",
+    defaults: ["libavservices_minijail_defaults"],
+    srcs: [
+        "av_services_minijail_unittest.cpp",
+    ],
+}
diff --git a/services/minijail/Android.mk b/services/minijail/Android.mk
deleted file mode 100644
index 67055a8..0000000
--- a/services/minijail/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-minijail_common_cflags := -Wall -Werror
-
-# Small library for media.extractor and media.codec sandboxing.
-include $(CLEAR_VARS)
-LOCAL_MODULE := libavservices_minijail
-LOCAL_SRC_FILES := minijail.cpp
-LOCAL_CFLAGS := $(minijail_common_cflags)
-LOCAL_SHARED_LIBRARIES := libbase libminijail
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-include $(BUILD_SHARED_LIBRARY)
-
-# Small library for media.extractor and media.codec sandboxing.
-include $(CLEAR_VARS)
-LOCAL_MODULE := libavservices_minijail_vendor
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := minijail.cpp
-LOCAL_CFLAGS := $(minijail_common_cflags)
-LOCAL_SHARED_LIBRARIES := libbase libminijail
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-include $(BUILD_SHARED_LIBRARY)
-
-# Unit tests.
-include $(CLEAR_VARS)
-LOCAL_MODULE := libavservices_minijail_unittest
-LOCAL_SRC_FILES := minijail.cpp av_services_minijail_unittest.cpp
-LOCAL_CFLAGS := $(minijail_common_cflags)
-LOCAL_SHARED_LIBRARIES := libbase libminijail
-include $(BUILD_NATIVE_TEST)