Merge "Change MediaControlView2 APIs"
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 982b117..e51ec4d 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -227,6 +227,7 @@
 DrmHal::DrmHal()
    : mDrmSessionClient(new DrmSessionClient(this)),
      mFactories(makeDrmFactories()),
+     mOpenSessionCounter("/drm/mediadrm/open_session", "status"),
      mInitCheck((mFactories.size() == 0) ? ERROR_UNSUPPORTED : NO_INIT) {
 }
 
@@ -517,6 +518,8 @@
                 mDrmSessionClient, sessionId);
         mOpenSessions.push(sessionId);
     }
+
+    mOpenSessionCounter.Increment(err);
     return err;
 }
 
@@ -985,8 +988,25 @@
 }
 
 status_t DrmHal::getMetrics(MediaAnalyticsItem* metrics) {
-    // TODO: Replace this with real metrics.
-    metrics->setCString("/drm/mediadrm/dummymetric", "dummy");
+    // TODO: Move mOpenSessionCounter and suffixes to a separate class
+    // that manages the collection of metrics and exporting them.
+    std::string success_count_name =
+        mOpenSessionCounter.metric_name() + "/ok/count";
+    std::string error_count_name =
+        mOpenSessionCounter.metric_name() + "/error/count";
+    mOpenSessionCounter.ExportValues(
+        [&] (status_t status, int64_t value) {
+            if (status == OK) {
+                metrics->setInt64(success_count_name.c_str(), value);
+            } else {
+                int64_t total_errors(0);
+                metrics->getInt64(error_count_name.c_str(), &total_errors);
+                metrics->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.
+            }
+        });
     return OK;
 }
 
diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp
new file mode 100644
index 0000000..674d3eb
--- /dev/null
+++ b/drm/libmediadrm/tests/Android.bp
@@ -0,0 +1,12 @@
+// Build definitions for unit tests.
+
+cc_test {
+    name: "CounterMetric_test",
+    srcs: ["CounterMetric_test.cpp"],
+    shared_libs: ["libmediadrm"],
+    include_dirs: ["frameworks/av/include/media"],
+    cflags: [
+      "-Werror",
+      "-Wall",
+    ],
+}
diff --git a/drm/libmediadrm/tests/CounterMetric_test.cpp b/drm/libmediadrm/tests/CounterMetric_test.cpp
new file mode 100644
index 0000000..6bca0da
--- /dev/null
+++ b/drm/libmediadrm/tests/CounterMetric_test.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "CounterMetric.h"
+
+namespace android {
+
+/**
+ * Unit tests for the CounterMetric class.
+ */
+class CounterMetricTest : public ::testing::Test {
+};
+
+TEST_F(CounterMetricTest, IntDataTypeEmpty) {
+  CounterMetric<int> metric("MyMetricName", "MetricAttributeName");
+
+  std::map<int, int64_t> values;
+
+  metric.ExportValues(
+      [&] (int attribute_value, int64_t value) {
+          values[attribute_value] = value;
+      });
+
+  EXPECT_TRUE(values.empty());
+}
+
+TEST_F(CounterMetricTest, IntDataType) {
+  CounterMetric<int> metric("MyMetricName", "MetricAttributeName");
+
+  std::map<int, int64_t> values;
+
+  metric.Increment(7);
+  metric.Increment(8);
+  metric.Increment(8);
+
+  metric.ExportValues(
+      [&] (int attribute_value, int64_t value) {
+          values[attribute_value] = value;
+      });
+
+  ASSERT_EQ(2u, values.size());
+  EXPECT_EQ(1, values[7]);
+  EXPECT_EQ(2, values[8]);
+}
+
+TEST_F(CounterMetricTest, StringDataType) {
+  CounterMetric<std::string> metric("MyMetricName", "MetricAttributeName");
+
+  std::map<std::string, int64_t> values;
+
+  metric.Increment("a");
+  metric.Increment("b");
+  metric.Increment("b");
+
+  metric.ExportValues(
+      [&] (std::string attribute_value, int64_t value) {
+          values[attribute_value] = value;
+      });
+
+  ASSERT_EQ(2u, values.size());
+  EXPECT_EQ(1, values["a"]);
+  EXPECT_EQ(2, values["b"]);
+}
+
+}  // namespace android
diff --git a/include/media/CounterMetric.h b/include/media/CounterMetric.h
new file mode 120000
index 0000000..baba043
--- /dev/null
+++ b/include/media/CounterMetric.h
@@ -0,0 +1 @@
+../../media/libmedia/include/media/CounterMetric.h
\ No newline at end of file
diff --git a/media/libmedia/MediaCodecBuffer.cpp b/media/libmedia/MediaCodecBuffer.cpp
index 59d6164..68ae3ea 100644
--- a/media/libmedia/MediaCodecBuffer.cpp
+++ b/media/libmedia/MediaCodecBuffer.cpp
@@ -21,15 +21,13 @@
 #include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/MediaBufferBase.h>
 
 namespace android {
 
 MediaCodecBuffer::MediaCodecBuffer(const sp<AMessage> &format, const sp<ABuffer> &buffer)
     : mMeta(new AMessage),
       mFormat(format),
-      mBuffer(buffer),
-      mMediaBufferBase(nullptr) {
+      mBuffer(buffer) {
 }
 
 // ABuffer-like interface
@@ -58,20 +56,6 @@
     return OK;
 }
 
-MediaBufferBase *MediaCodecBuffer::getMediaBufferBase() {
-    if (mMediaBufferBase != NULL) {
-        mMediaBufferBase->add_ref();
-    }
-    return mMediaBufferBase;
-}
-
-void MediaCodecBuffer::setMediaBufferBase(MediaBufferBase *mediaBuffer) {
-    if (mMediaBufferBase != NULL) {
-        mMediaBufferBase->release();
-    }
-    mMediaBufferBase = mediaBuffer;
-}
-
 sp<AMessage> MediaCodecBuffer::meta() {
     return mMeta;
 }
diff --git a/media/libmedia/include/media/CounterMetric.h b/media/libmedia/include/media/CounterMetric.h
new file mode 100644
index 0000000..f39ca7c
--- /dev/null
+++ b/media/libmedia/include/media/CounterMetric.h
@@ -0,0 +1,90 @@
+/*
+ * 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_COUNTER_METRIC_H_
+#define ANDROID_COUNTER_METRIC_H_
+
+#include <media/MediaAnalyticsItem.h>
+#include <utils/Log.h>
+
+namespace android {
+
+
+// The CounterMetric class is used to hold counts of operations or events.
+// A CounterMetric can break down counts by a dimension specified by the
+// application. E.g. an application may want to track counts broken out by
+// error code or the size of some parameter.
+//
+// Example:
+//
+//   CounterMetric<status_t> workCounter;
+//   workCounter("workCounterName", "result_status");
+//
+//   status_t err = DoWork();
+//
+//   // Increments the number of times called with the given error code.
+//   workCounter.Increment(err);
+//
+//   std::map<int, int64_t> values;
+//    metric.ExportValues(
+//        [&] (int attribute_value, int64_t value) {
+//             values[attribute_value] = value;
+//        });
+//
+//   // Do something with the exported stat.
+//
+template<typename AttributeType>
+class CounterMetric {
+ public:
+  // Instantiate the counter with the given metric name and
+  // attribute names. |attribute_names| must not be null.
+  CounterMetric(
+      const std::string& metric_name,
+      const std::string& attribute_name)
+          : metric_name_(metric_name),
+            attribute_name_(attribute_name) {}
+
+  // Increment the count of times the operation occurred with this
+  // combination of attributes.
+  void Increment(AttributeType attribute) {
+    if (values_.find(attribute) == values_.end()) {
+      values_[attribute] = 1;
+    } else {
+      values_[attribute] = values_[attribute] + 1;
+    }
+  };
+
+  // Export the metrics to the provided |function|. Each value for Attribute
+  // has a separate count. As such, |function| will be called once per value
+  // of Attribute.
+  void ExportValues(
+      std::function<void (const AttributeType&,
+                          const int64_t count)> function) {
+    for (auto it = values_.begin(); it != values_.end(); it++) {
+      function(it->first, it->second);
+    }
+  }
+
+  const std::string& metric_name() { return metric_name_; };
+
+ private:
+  const std::string metric_name_;
+  const std::string attribute_name_;
+  std::map<AttributeType, int64_t> values_;
+};
+
+}  // namespace android
+
+#endif  // ANDROID_COUNTER_METRIC_H_
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index 1a0553e..f2b25cd 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -23,6 +23,7 @@
 #include <android/hardware/drm/1.0/IDrmPluginListener.h>
 #include <android/hardware/drm/1.0/IDrmFactory.h>
 
+#include <media/CounterMetric.h>
 #include <media/IDrm.h>
 #include <media/IDrmClient.h>
 #include <media/MediaAnalyticsItem.h>
@@ -180,6 +181,8 @@
     sp<IDrmPlugin> mPlugin;
     sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
 
+    CounterMetric<status_t> mOpenSessionCounter;
+
     Vector<Vector<uint8_t>> mOpenSessions;
     void closeOpenSessions();
 
diff --git a/media/libmedia/include/media/MediaBufferHolder.h b/media/libmedia/include/media/MediaBufferHolder.h
new file mode 100644
index 0000000..e8e2c4b
--- /dev/null
+++ b/media/libmedia/include/media/MediaBufferHolder.h
@@ -0,0 +1,48 @@
+/*
+ * 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 MEDIA_BUFFER_HOLDER_H_
+
+#define MEDIA_BUFFER_HOLDER_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaBufferHolder : public RefBase {
+    MediaBufferHolder(MediaBuffer* buffer)
+        : mMediaBuffer(buffer) {
+        if (mMediaBuffer != nullptr) {
+            mMediaBuffer->add_ref();
+        }
+    }
+
+    virtual ~MediaBufferHolder() {
+        if (mMediaBuffer != nullptr) {
+            mMediaBuffer->release();
+        }
+    }
+
+    MediaBuffer* mediaBuffer() { return mMediaBuffer; }
+
+private:
+    MediaBuffer* const mMediaBuffer;
+};
+
+}  // android
+
+#endif  // MEDIA_BUFFER_HOLDER_H_
diff --git a/media/libmedia/include/media/MediaCodecBuffer.h b/media/libmedia/include/media/MediaCodecBuffer.h
index 501c00b..2c16fba 100644
--- a/media/libmedia/include/media/MediaCodecBuffer.h
+++ b/media/libmedia/include/media/MediaCodecBuffer.h
@@ -50,9 +50,6 @@
     size_t offset() const;
     // Default implementation calls ABuffer::setRange() and returns OK.
     virtual status_t setRange(size_t offset, size_t size);
-    // TODO: These can be removed if we finish replacing all MediaBuffer's.
-    MediaBufferBase *getMediaBufferBase();
-    void setMediaBufferBase(MediaBufferBase *mediaBuffer);
 
     // TODO: Specify each field for meta/format.
     sp<AMessage> meta();
@@ -66,7 +63,6 @@
     const sp<AMessage> mMeta;
     sp<AMessage> mFormat;
     const sp<ABuffer> mBuffer;
-    MediaBufferBase *mMediaBufferBase;
 };
 
 }  // namespace android
diff --git a/media/libmedia/nuplayer2/GenericSource.cpp b/media/libmedia/nuplayer2/GenericSource.cpp
index c0b81fb..6d5b14d 100644
--- a/media/libmedia/nuplayer2/GenericSource.cpp
+++ b/media/libmedia/nuplayer2/GenericSource.cpp
@@ -24,6 +24,7 @@
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <media/DataSource.h>
+#include <media/MediaBufferHolder.h>
 #include <media/IMediaExtractorService.h>
 #include <media/MediaHTTPService.h>
 #include <media/MediaExtractor.h>
@@ -1167,8 +1168,7 @@
 
         // data is already provided in the buffer
         ab = new ABuffer(NULL, mb->range_length());
-        mb->add_ref();
-        ab->setMediaBufferBase(mb);
+        ab->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mb));
 
         // Modular DRM: Required b/c of the above add_ref.
         // If ref>0, there must be an observer, or it'll crash at release().
diff --git a/media/libmedia/nuplayer2/NuPlayer2Decoder.cpp b/media/libmedia/nuplayer2/NuPlayer2Decoder.cpp
index 715d6fc..a436592 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Decoder.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2Decoder.cpp
@@ -28,6 +28,7 @@
 #include "NuPlayer2Source.h"
 
 #include <cutils/properties.h>
+#include <media/MediaBufferHolder.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/NdkMediaCodec.h>
 #include <media/NdkWrapper.h>
@@ -1081,16 +1082,17 @@
                 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
             } else { // No buffer->data()
                 //Modular DRM
-                mediaBuf = (MediaBuffer*)buffer->getMediaBufferBase();
+                sp<RefBase> holder;
+                if (buffer->meta()->findObject("mediaBufferHolder", &holder)) {
+                    mediaBuf = (holder != nullptr) ?
+                        static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
+                }
                 if (mediaBuf != NULL) {
                     codecBuffer->setRange(0, mediaBuf->size());
                     memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
 
                     sp<MetaData> meta_data = mediaBuf->meta_data();
                     cryptInfo = AMediaCodecCryptoInfoWrapper::Create(meta_data);
-
-                    // since getMediaBuffer() has incremented the refCount
-                    mediaBuf->release();
                 } else { // No mediaBuf
                     ALOGE("onInputBufferFetched: buffer->data()/mediaBuf are NULL for %p",
                             buffer.get());
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 18573db..83fea39 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -15,6 +15,7 @@
     ],
 
     shared_libs: [
+        "libbinder",
         "libstagefright_foundation",
         "libutils",
         "libcutils",
@@ -23,6 +24,8 @@
 
     srcs: [
         "DataSource.cpp",
+        "MediaBuffer.cpp",
+        "MediaBufferGroup.cpp",
         "MediaSource.cpp",
         "MediaExtractor.cpp",
     ],
diff --git a/media/libstagefright/foundation/MediaBuffer.cpp b/media/libmediaextractor/MediaBuffer.cpp
similarity index 98%
rename from media/libstagefright/foundation/MediaBuffer.cpp
rename to media/libmediaextractor/MediaBuffer.cpp
index 95951dd..28fc760 100644
--- a/media/libstagefright/foundation/MediaBuffer.cpp
+++ b/media/libmediaextractor/MediaBuffer.cpp
@@ -26,8 +26,6 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 
-#include <ui/GraphicBuffer.h>
-
 namespace android {
 
 /* static */
diff --git a/media/libstagefright/foundation/MediaBufferGroup.cpp b/media/libmediaextractor/MediaBufferGroup.cpp
similarity index 100%
rename from media/libstagefright/foundation/MediaBufferGroup.cpp
rename to media/libmediaextractor/MediaBufferGroup.cpp
diff --git a/media/libstagefright/include/media/stagefright/MediaBuffer.h b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
similarity index 97%
rename from media/libstagefright/include/media/stagefright/MediaBuffer.h
rename to media/libmediaextractor/include/media/stagefright/MediaBuffer.h
index 367a467..2b51081 100644
--- a/media/libstagefright/include/media/stagefright/MediaBuffer.h
+++ b/media/libmediaextractor/include/media/stagefright/MediaBuffer.h
@@ -20,7 +20,6 @@
 
 #include <atomic>
 #include <list>
-#include <media/stagefright/foundation/MediaBufferBase.h>
 
 #include <pthread.h>
 
@@ -48,7 +47,7 @@
     MediaBufferObserver &operator=(const MediaBufferObserver &);
 };
 
-class MediaBuffer : public MediaBufferBase {
+class MediaBuffer {
 public:
     // allocations larger than or equal to this will use shared memory.
     static const size_t kSharedMemThreshold = 64 * 1024;
@@ -72,11 +71,11 @@
     //
     // If no MediaBufferGroup is set, the local reference count must be zero
     // when called, whereupon the MediaBuffer is deleted.
-    virtual void release();
+    void release();
 
     // Increments the local reference count.
     // Use only when MediaBufferGroup is set.
-    virtual void add_ref();
+    void add_ref();
 
     void *data() const;
     size_t size() const;
@@ -144,7 +143,7 @@
         return mObserver != nullptr;
     }
 
-    virtual ~MediaBuffer();
+    ~MediaBuffer();
 
     sp<IMemory> mMemory;
 
diff --git a/media/libstagefright/include/media/stagefright/MediaBufferGroup.h b/media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/MediaBufferGroup.h
rename to media/libmediaextractor/include/media/stagefright/MediaBufferGroup.h
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 33c3094..511f46f 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -24,6 +24,7 @@
 #include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <media/DataSource.h>
+#include <media/MediaBufferHolder.h>
 #include <media/MediaExtractor.h>
 #include <media/MediaSource.h>
 #include <media/IMediaHTTPService.h>
@@ -1160,14 +1161,12 @@
 
         // data is already provided in the buffer
         ab = new ABuffer(NULL, mb->range_length());
-        mb->add_ref();
-        ab->setMediaBufferBase(mb);
+        ab->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mb));
 
         // Modular DRM: Required b/c of the above add_ref.
         // If ref>0, there must be an observer, or it'll crash at release().
         // TODO: MediaBuffer might need to be revised to ease such need.
         mb->setObserver(this);
-        // setMediaBufferBase() interestingly doesn't increment the ref count on its own.
         // Extra increment (since we want to keep mb alive and attached to ab beyond this function
         // call. This is to counter the effect of mb->release() towards the end.
         mb->add_ref();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1b02adb..1aca96c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -29,6 +29,7 @@
 
 #include <cutils/properties.h>
 #include <media/ICrypto.h>
+#include <media/MediaBufferHolder.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -1061,16 +1062,17 @@
                 memcpy(codecBuffer->data(), buffer->data(), buffer->size());
             } else { // No buffer->data()
                 //Modular DRM
-                mediaBuf = (MediaBuffer*)buffer->getMediaBufferBase();
+                sp<RefBase> holder;
+                if (buffer->meta()->findObject("mediaBufferHolder", &holder)) {
+                    mediaBuf = (holder != nullptr) ?
+                        static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
+                }
                 if (mediaBuf != NULL) {
                     codecBuffer->setRange(0, mediaBuf->size());
                     memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
 
                     sp<MetaData> meta_data = mediaBuf->meta_data();
                     cryptInfo = NuPlayerDrm::getSampleCryptoInfo(meta_data);
-
-                    // since getMediaBuffer() has incremented the refCount
-                    mediaBuf->release();
                 } else { // No mediaBuf
                     ALOGE("onInputBufferFetched: buffer->data()/mediaBuf are NULL for %p",
                             buffer.get());
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 14ea2a8..0ded5be 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -43,6 +43,7 @@
 #include <media/stagefright/PersistentSurface.h>
 #include <media/stagefright/SurfaceUtils.h>
 #include <media/hardware/HardwareAPI.h>
+#include <media/MediaBufferHolder.h>
 #include <media/OMXBuffer.h>
 #include <media/omx/1.0/WOmxNode.h>
 
@@ -5606,7 +5607,7 @@
     // by this "MediaBuffer" object. Now that the OMX component has
     // told us that it's done with the input buffer, we can decrement
     // the mediaBuffer's reference count.
-    info->mData->setMediaBufferBase(NULL);
+    info->mData->meta()->setObject("mediaBufferHolder", sp<MediaBufferHolder>(nullptr));
 
     PortMode mode = getPortMode(kPortIndexInput);
 
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index eea9c78..ebc9b0a 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -665,16 +665,16 @@
     int32_t flags = 0;
     int32_t tmp = 0;
     if (buffer->meta()->findInt32("eos", &tmp) && tmp) {
-        flags |= C2BufferPack::FLAG_END_OF_STREAM;
+        flags |= C2FrameData::FLAG_END_OF_STREAM;
         ALOGV("input EOS");
     }
     if (buffer->meta()->findInt32("csd", &tmp) && tmp) {
-        flags |= C2BufferPack::FLAG_CODEC_CONFIG;
+        flags |= C2FrameData::FLAG_CODEC_CONFIG;
     }
     std::unique_ptr<C2Work> work(new C2Work);
-    work->input.flags = (C2BufferPack::flags_t)flags;
+    work->input.flags = (C2FrameData::flags_t)flags;
     work->input.ordinal.timestamp = timeUs;
-    work->input.ordinal.frame_index = mFrameIndex++;
+    work->input.ordinal.frameIndex = mFrameIndex++;
     work->input.buffers.clear();
     {
         Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
@@ -724,7 +724,7 @@
         return OK;
     }
 
-    std::list<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
+    std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
     if (blocks.size() != 1u) {
         ALOGE("# of graphic blocks expected to be 1, but %zu", blocks.size());
         return UNKNOWN_ERROR;
@@ -881,7 +881,7 @@
         }
 
         const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
-        if (worklet->output.ordinal.frame_index < mFirstValidFrameIndex) {
+        if ((worklet->output.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
             // Discard frames from previous generation.
             continue;
         }
@@ -897,7 +897,7 @@
         if (buffer) {
             // TODO: transfer infos() into buffer metadata
         }
-        for (const auto &info : worklet->output.infos) {
+        for (const auto &info : worklet->output.configUpdate) {
             if (info->coreIndex() == C2StreamCsdInfo::output::CORE_INDEX) {
                 ALOGV("csd found");
                 csdInfo = static_cast<const C2StreamCsdInfo::output *>(info.get());
@@ -905,7 +905,7 @@
         }
 
         int32_t flags = 0;
-        if (worklet->output.flags & C2BufferPack::FLAG_END_OF_STREAM) {
+        if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
             flags |= MediaCodec::BUFFER_FLAG_EOS;
             ALOGV("output EOS");
         }
@@ -914,7 +914,7 @@
         if (csdInfo != nullptr) {
             Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
             if ((*buffers)->registerCsd(csdInfo, &index, &outBuffer)) {
-                outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp);
+                outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp.peek());
                 outBuffer->meta()->setInt32("flags", flags | MediaCodec::BUFFER_FLAG_CODECCONFIG);
                 ALOGV("csd index = %zu", index);
 
@@ -947,7 +947,7 @@
             }
         }
 
-        outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp);
+        outBuffer->meta()->setInt64("timeUs", worklet->output.ordinal.timestamp.peek());
         outBuffer->meta()->setInt32("flags", flags);
         ALOGV("index = %zu", index);
         mCallback->onOutputBufferAvailable(index, outBuffer);
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 8bd0a51..04d83af 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -23,6 +23,7 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/Surface.h>
 #include <media/ICrypto.h>
+#include <media/MediaBufferHolder.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/MediaSource.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -739,7 +740,8 @@
             if (mIsVideo) {
                 // video encoder will release MediaBuffer when done
                 // with underlying data.
-                inbuf->setMediaBufferBase(mbuf);
+                inbuf->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mbuf));
+                mbuf->release();
             } else {
                 mbuf->release();
             }
diff --git a/media/libstagefright/codec2/SimpleC2Component.cpp b/media/libstagefright/codec2/SimpleC2Component.cpp
index 4d75a31..c3ae00e 100644
--- a/media/libstagefright/codec2/SimpleC2Component.cpp
+++ b/media/libstagefright/codec2/SimpleC2Component.cpp
@@ -342,7 +342,7 @@
             return;
         }
     }
-    if (work->worklets_processed != 0u) {
+    if (work->workletsProcessed != 0u) {
         Mutexed<ExecState>::Locked state(mExecState);
         ALOGV("returning this work");
         state->mListener->onWorkDone_nb(shared_from_this(), vec(work));
@@ -351,7 +351,7 @@
         std::unique_ptr<C2Work> unexpected;
         {
             Mutexed<PendingWork>::Locked pending(mPendingWork);
-            uint64_t frameIndex = work->input.ordinal.frame_index;
+            uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
             if (pending->count(frameIndex) != 0) {
                 unexpected = std::move(pending->at(frameIndex));
                 pending->erase(frameIndex);
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index cd90978..2ca8222 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -679,14 +679,14 @@
      *
      * \param size    number of bytes to share
      * \param fence   fence to be used for the section
-     * \param blocks  list where the blocks of the section are appended to
+     * \param blocks  vector where the blocks of the section are appended to
      *
      * \retval C2_OK            the portion was successfully shared
      * \retval C2_NO_MEMORY     not enough memory to share the portion
      * \retval C2_TIMED_OUT     the operation timed out (unexpected)
      * \retval C2_CORRUPTED     some unknown error prevented sharing the data (unexpected)
      */
-    c2_status_t share(size_t size, C2Fence fence, std::list<C2ConstLinearBlock> &blocks);
+    c2_status_t share(size_t size, C2Fence fence, std::vector<C2ConstLinearBlock> &blocks);
 
     /**
      * Returns the beginning offset of this segment from the start of this circular block.
@@ -1203,14 +1203,14 @@
      * \return a constant list of const linear blocks of this buffer.
      * \retval empty list if this buffer does not contain linear block(s).
      */
-    const std::list<C2ConstLinearBlock> linearBlocks() const;
+    const std::vector<C2ConstLinearBlock> linearBlocks() const;
 
     /**
      * Gets the graphic blocks of this buffer.
      * \return a constant list of const graphic blocks of this buffer.
      * \retval empty list if this buffer does not contain graphic block(s).
      */
-    const std::list<C2ConstGraphicBlock> graphicBlocks() const;
+    const std::vector<C2ConstGraphicBlock> graphicBlocks() const;
 
 private:
     class Impl;
@@ -1218,8 +1218,8 @@
 
 protected:
     // no public constructor
-    explicit C2BufferData(const std::list<C2ConstLinearBlock> &blocks);
-    explicit C2BufferData(const std::list<C2ConstGraphicBlock> &blocks);
+    explicit C2BufferData(const std::vector<C2ConstLinearBlock> &blocks);
+    explicit C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks);
 };
 
 /**
@@ -1301,7 +1301,7 @@
      *
      * \return a constant list of info objects associated with this buffer.
      */
-    const std::list<std::shared_ptr<const C2Info>> infos() const;
+    const std::vector<std::shared_ptr<const C2Info>> info() const;
 
     /**
      * Attaches (or updates) an (existing) metadata for this buffer.
@@ -1328,8 +1328,8 @@
 
 protected:
     // no public constructor
-    explicit C2Buffer(const std::list<C2ConstLinearBlock> &blocks);
-    explicit C2Buffer(const std::list<C2ConstGraphicBlock> &blocks);
+    explicit C2Buffer(const std::vector<C2ConstLinearBlock> &blocks);
+    explicit C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks);
 
 private:
     class Impl;
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index a2168a0..e023db4 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -682,7 +682,7 @@
      */
     virtual c2_status_t reset() { return C2_OK; }
 
-    virtual c2_status_t parseFrame(C2BufferPack &frame);
+    virtual c2_status_t parseFrame(C2FrameData &frame);
 
     virtual ~C2FrameInfoParser() = default;
 };
diff --git a/media/libstagefright/codec2/include/C2Param.h b/media/libstagefright/codec2/include/C2Param.h
index 0540155..e2df62d 100644
--- a/media/libstagefright/codec2/include/C2Param.h
+++ b/media/libstagefright/codec2/include/C2Param.h
@@ -721,6 +721,10 @@
 
     DEFINE_OTHER_COMPARISON_OPERATORS(C2ParamField)
 
+protected:
+    inline C2ParamField(C2Param::Index index, uint32_t offset, uint32_t size)
+        : _mIndex(index), _mFieldId(offset, size) {}
+
 private:
     friend struct _C2ParamInspector;
 
@@ -729,6 +733,17 @@
 };
 
 /**
+ * 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 {
diff --git a/media/libstagefright/codec2/include/C2Work.h b/media/libstagefright/codec2/include/C2Work.h
index 105cf81..58a9174 100644
--- a/media/libstagefright/codec2/include/C2Work.h
+++ b/media/libstagefright/codec2/include/C2Work.h
@@ -83,32 +83,64 @@
     kParamIndexWorkOrdinal,
 };
 
+/**
+ * Information for ordering work items on a component port.
+ */
 struct C2WorkOrdinalStruct {
-    uint64_t timestamp;
-    uint64_t frame_index;    // submission ordinal on the initial component
-    uint64_t custom_ordinal; // can be given by the component, e.g. decode order
+//public:
+    c2_cntr64_t timestamp;     /** frame timestamp in microseconds */
+    c2_cntr64_t frameIndex;    /** submission ordinal on the initial component */
+    c2_cntr64_t customOrdinal; /** can be given by the component, e.g. decode order */
 
     DEFINE_AND_DESCRIBE_C2STRUCT(WorkOrdinal)
     C2FIELD(timestamp, "timestamp")
-    C2FIELD(frame_index, "frame-index")
-    C2FIELD(custom_ordinal, "custom-ordinal")
+    C2FIELD(frameIndex, "frame-index")
+    C2FIELD(customOrdinal, "custom-ordinal")
 };
 
-struct C2BufferPack {
+/**
+ * This structure represents a Codec 2.0 frame with its metadata.
+ *
+ * A frame basically consists of an ordered sets of buffers, configuration changes and info buffers
+ * along with some non-configuration metadata.
+ */
+struct C2FrameData {
 //public:
     enum flags_t : uint32_t {
-        FLAG_CODEC_CONFIG  = (1 << 0),
-        FLAG_DROP_FRAME    = (1 << 1),
-        FLAG_END_OF_STREAM = (1 << 2),
+        /**
+         * For input frames: no output frame shall be generated when processing this frame, but
+         * metadata shall still be processed.
+         * For output frames: this frame shall be discarded and but metadata is still valid.
+         */
+        FLAG_DROP_FRAME    = (1 << 0),
+        /**
+         * This frame is the last frame of the current stream. Further frames are part of a new
+         * stream.
+         */
+        FLAG_END_OF_STREAM = (1 << 1),
+        /**
+         * This frame shall be discarded with its metadata.
+         * This flag is only set by components - e.g. as a response to the flush command.
+         */
+        FLAG_DISCARD_FRAME = (1 << 2),
+        /**
+         * This frame contains only codec-specific configuration data, and no actual access unit.
+         *
+         * \deprecated pass codec configuration with using the \todo codec-specific configuration
+         * info together with the access unit.
+         */
+        FLAG_CODEC_CONFIG  = (1u << 31),
     };
 
+    /**
+     * Frame flags */
     flags_t  flags;
     C2WorkOrdinalStruct ordinal;
     std::vector<std::shared_ptr<C2Buffer>> buffers;
     //< for initial work item, these may also come from the parser - if provided
     //< for output buffers, these are the responses to requestedInfos
-    std::list<std::unique_ptr<C2Info>>       infos;
-    std::list<std::shared_ptr<C2InfoBuffer>> infoBuffers;
+    std::vector<std::unique_ptr<C2Param>>      configUpdate;
+    std::vector<std::shared_ptr<C2InfoBuffer>> infoBuffers;
 };
 
 struct C2Worklet {
@@ -116,59 +148,61 @@
     // IN
     c2_node_id_t component;
 
-    std::list<std::unique_ptr<C2Param>> tunings; //< tunings to be applied before processing this
-                                                 // worklet
-    std::list<C2Param::Type> requestedInfos;
-    std::vector<std::shared_ptr<C2BlockPool>> allocators; //< This vector shall be the same size as
-                                                          //< output.buffers. \deprecated
+    /** Configuration changes to be applied before processing this worklet. */
+    std::vector<std::unique_ptr<C2Tuning>> tunings;
+    std::vector<std::unique_ptr<C2SettingResult>> failures;
 
     // OUT
-    C2BufferPack output;
-    std::list<std::unique_ptr<C2SettingResult>> failures;
+    C2FrameData output;
 };
 
 /**
+ * Information about partial work-chains not part of the current work items.
+ *
+ * To be defined later.
+ */
+struct C2WorkChainInfo;
+
+/**
  * This structure holds information about all a single work item.
  *
  * This structure shall be passed by the client to the component for the first worklet. As such,
  * worklets must not be empty. The ownership of this object is passed.
- *
- * input:
- *      The input data to be processed. This is provided by the client with ownership. When the work
- *      is returned, the input buffer-pack's buffer vector shall contain nullptrs.
- *
- * worklets:
- *      The chain of components and associated allocators, tunings and info requests that the data
- *      must pass through. If this has more than a single element, the tunnels between successive
- *      components of the worklet chain must have been (successfully) pre-registered at the time
- *      the work is submitted. Allocating the output buffers in the worklets is the responsibility
- *      of each component. Upon work submission, each output buffer-pack shall be an appropriately
- *      sized vector containing nullptrs. When the work is completed/returned to the client,
- *
- * worklets_processed:
- *      It shall be initialized to 0 by the client when the work is submitted.
- *      It shall contain the number of worklets that were successfully processed when the work is
- *      returned. If this is less then the number of worklets, result must not be success.
- *      It must be in the range of [0, worklets.size()].
- *
- * result:
- *      The final outcome of the work. If 0 when work is returned, it is assumed that all worklets
- *      have been processed.
  */
 struct C2Work {
 //public:
-    // pre-chain infos (for portions of a tunneling chain that happend before this work-chain for
-    // this work item - due to framework facilitated (non-tunneled) work-chaining)
-    std::list<std::pair<std::unique_ptr<C2PortMimeConfig>, std::unique_ptr<C2Info>>> preChainInfos;
-    std::list<std::pair<std::unique_ptr<C2PortMimeConfig>, std::unique_ptr<C2Buffer>>> preChainInfoBlobs;
+    /// additional work chain info not part of this work
+    std::shared_ptr<C2WorkChainInfo> chainInfo;
 
-    C2BufferPack input;
+    /// The input data to be processed as part of this work/work-chain. This is provided by the
+    /// client with ownership. When the work is returned (via onWorkDone), the input buffer-pack's
+    /// buffer vector shall contain nullptrs.
+    C2FrameData input;
+
+    /// The chain of components, tunings (including output buffer pool IDs) and info requests that the
+    /// data must pass through. If this has more than a single element, the tunnels between successive
+    /// components of the worklet chain must have been (successfully) pre-registered at the time that
+    /// the work is submitted. Allocating the output buffers in the worklets is the responsibility of
+    /// each component. Upon work submission, each output buffer-pack shall be an appropriately sized
+    /// vector containing nullptrs. When the work is completed/returned to the client, output buffers
+    /// pointers from all but the final worklet shall be nullptrs.
     std::list<std::unique_ptr<C2Worklet>> worklets;
 
-    uint32_t worklets_processed;
+    /// Number of worklets successfully processed in this chain. This shall be initialized to 0 by the
+    /// client when the work is submitted. It shall contain the number of worklets that were
+    /// successfully processed when the work is returned to the client. If this is less then the number
+    /// of worklets, result must not be success. It must be in the range of [0, worklets.size()].
+    uint32_t workletsProcessed;
+
+    /// The final outcome of the work (corresponding to the current workletsProcessed). If 0 when
+    /// work is returned, it is assumed that all worklets have been processed.
     c2_status_t result;
 };
 
+/**
+ * Information about a future work to be submitted to the component. The information is used to
+ * reserve the work for work ordering purposes.
+ */
 struct C2WorkOutline {
 //public:
     C2WorkOrdinalStruct ordinal;
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index f6e6478..a310717 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -359,14 +359,14 @@
 
 class BufferData : public C2BufferData {
 public:
-    explicit BufferData(const std::list<C2ConstLinearBlock> &blocks) : C2BufferData(blocks) {}
-    explicit BufferData(const std::list<C2ConstGraphicBlock> &blocks) : C2BufferData(blocks) {}
+    explicit BufferData(const std::vector<C2ConstLinearBlock> &blocks) : C2BufferData(blocks) {}
+    explicit BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : C2BufferData(blocks) {}
 };
 
 class Buffer : public C2Buffer {
 public:
-    explicit Buffer(const std::list<C2ConstLinearBlock> &blocks) : C2Buffer(blocks) {}
-    explicit Buffer(const std::list<C2ConstGraphicBlock> &blocks) : C2Buffer(blocks) {}
+    explicit Buffer(const std::vector<C2ConstLinearBlock> &blocks) : C2Buffer(blocks) {}
+    explicit Buffer(const std::vector<C2ConstGraphicBlock> &blocks) : C2Buffer(blocks) {}
 };
 
 TEST_F(C2BufferTest, BufferDataTest) {
@@ -487,45 +487,45 @@
     std::shared_ptr<C2Info> info1(new C2Number1Info(1));
     std::shared_ptr<C2Info> info2(new C2Number2Info(2));
     buffer.reset(new Buffer( { block->share(0, kCapacity, C2Fence()) }));
-    EXPECT_TRUE(buffer->infos().empty());
+    EXPECT_TRUE(buffer->info().empty());
     EXPECT_FALSE(buffer->hasInfo(info1->type()));
     EXPECT_FALSE(buffer->hasInfo(info2->type()));
 
     ASSERT_EQ(C2_OK, buffer->setInfo(info1));
-    EXPECT_EQ(1u, buffer->infos().size());
-    EXPECT_EQ(*info1, *buffer->infos().front());
+    EXPECT_EQ(1u, buffer->info().size());
+    EXPECT_EQ(*info1, *buffer->info().front());
     EXPECT_TRUE(buffer->hasInfo(info1->type()));
     EXPECT_FALSE(buffer->hasInfo(info2->type()));
 
     ASSERT_EQ(C2_OK, buffer->setInfo(info2));
-    EXPECT_EQ(2u, buffer->infos().size());
+    EXPECT_EQ(2u, buffer->info().size());
     EXPECT_TRUE(buffer->hasInfo(info1->type()));
     EXPECT_TRUE(buffer->hasInfo(info2->type()));
 
     std::shared_ptr<C2Info> removed = buffer->removeInfo(info1->type());
     ASSERT_TRUE(removed);
     EXPECT_EQ(*removed, *info1);
-    EXPECT_EQ(1u, buffer->infos().size());
-    EXPECT_EQ(*info2, *buffer->infos().front());
+    EXPECT_EQ(1u, buffer->info().size());
+    EXPECT_EQ(*info2, *buffer->info().front());
     EXPECT_FALSE(buffer->hasInfo(info1->type()));
     EXPECT_TRUE(buffer->hasInfo(info2->type()));
 
     removed = buffer->removeInfo(info1->type());
     ASSERT_FALSE(removed);
-    EXPECT_EQ(1u, buffer->infos().size());
+    EXPECT_EQ(1u, buffer->info().size());
     EXPECT_FALSE(buffer->hasInfo(info1->type()));
     EXPECT_TRUE(buffer->hasInfo(info2->type()));
 
     std::shared_ptr<C2Info> info3(new C2Number2Info(3));
     ASSERT_EQ(C2_OK, buffer->setInfo(info3));
-    EXPECT_EQ(1u, buffer->infos().size());
+    EXPECT_EQ(1u, buffer->info().size());
     EXPECT_FALSE(buffer->hasInfo(info1->type()));
     EXPECT_TRUE(buffer->hasInfo(info2->type()));
 
     removed = buffer->removeInfo(info2->type());
     ASSERT_TRUE(removed);
     EXPECT_EQ(*info3, *removed);
-    EXPECT_TRUE(buffer->infos().empty());
+    EXPECT_TRUE(buffer->info().empty());
     EXPECT_FALSE(buffer->hasInfo(info1->type()));
     EXPECT_FALSE(buffer->hasInfo(info2->type()));
 }
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 65a271e..4ab3e05 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -602,44 +602,44 @@
 
 class C2BufferData::Impl {
 public:
-    explicit Impl(const std::list<C2ConstLinearBlock> &blocks)
+    explicit Impl(const std::vector<C2ConstLinearBlock> &blocks)
         : mType(blocks.size() == 1 ? LINEAR : LINEAR_CHUNKS),
           mLinearBlocks(blocks) {
     }
 
-    explicit Impl(const std::list<C2ConstGraphicBlock> &blocks)
+    explicit Impl(const std::vector<C2ConstGraphicBlock> &blocks)
         : mType(blocks.size() == 1 ? GRAPHIC : GRAPHIC_CHUNKS),
           mGraphicBlocks(blocks) {
     }
 
     Type type() const { return mType; }
-    const std::list<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
-    const std::list<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
+    const std::vector<C2ConstLinearBlock> &linearBlocks() const { return mLinearBlocks; }
+    const std::vector<C2ConstGraphicBlock> &graphicBlocks() const { return mGraphicBlocks; }
 
 private:
     Type mType;
-    std::list<C2ConstLinearBlock> mLinearBlocks;
-    std::list<C2ConstGraphicBlock> mGraphicBlocks;
+    std::vector<C2ConstLinearBlock> mLinearBlocks;
+    std::vector<C2ConstGraphicBlock> mGraphicBlocks;
 };
 
-C2BufferData::C2BufferData(const std::list<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
-C2BufferData::C2BufferData(const std::list<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
+C2BufferData::C2BufferData(const std::vector<C2ConstLinearBlock> &blocks) : mImpl(new Impl(blocks)) {}
+C2BufferData::C2BufferData(const std::vector<C2ConstGraphicBlock> &blocks) : mImpl(new Impl(blocks)) {}
 
 C2BufferData::Type C2BufferData::type() const { return mImpl->type(); }
 
-const std::list<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
+const std::vector<C2ConstLinearBlock> C2BufferData::linearBlocks() const {
     return mImpl->linearBlocks();
 }
 
-const std::list<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
+const std::vector<C2ConstGraphicBlock> C2BufferData::graphicBlocks() const {
     return mImpl->graphicBlocks();
 }
 
 class C2Buffer::Impl {
 public:
-    Impl(C2Buffer *thiz, const std::list<C2ConstLinearBlock> &blocks)
+    Impl(C2Buffer *thiz, const std::vector<C2ConstLinearBlock> &blocks)
         : mThis(thiz), mData(blocks) {}
-    Impl(C2Buffer *thiz, const std::list<C2ConstGraphicBlock> &blocks)
+    Impl(C2Buffer *thiz, const std::vector<C2ConstGraphicBlock> &blocks)
         : mThis(thiz), mData(blocks) {}
 
     ~Impl() {
@@ -676,8 +676,8 @@
         return C2_OK;
     }
 
-    std::list<std::shared_ptr<const C2Info>> infos() const {
-        std::list<std::shared_ptr<const C2Info>> result(mInfos.size());
+    std::vector<std::shared_ptr<const C2Info>> info() const {
+        std::vector<std::shared_ptr<const C2Info>> result(mInfos.size());
         std::transform(
                 mInfos.begin(), mInfos.end(), result.begin(),
                 [] (const auto &elem) { return elem.second; });
@@ -712,10 +712,10 @@
     std::list<std::pair<OnDestroyNotify, void *>> mNotify;
 };
 
-C2Buffer::C2Buffer(const std::list<C2ConstLinearBlock> &blocks)
+C2Buffer::C2Buffer(const std::vector<C2ConstLinearBlock> &blocks)
     : mImpl(new Impl(this, blocks)) {}
 
-C2Buffer::C2Buffer(const std::list<C2ConstGraphicBlock> &blocks)
+C2Buffer::C2Buffer(const std::vector<C2ConstGraphicBlock> &blocks)
     : mImpl(new Impl(this, blocks)) {}
 
 const C2BufferData C2Buffer::data() const { return mImpl->data(); }
@@ -728,8 +728,8 @@
     return mImpl->unregisterOnDestroyNotify(onDestroyNotify, arg);
 }
 
-const std::list<std::shared_ptr<const C2Info>> C2Buffer::infos() const {
-    return mImpl->infos();
+const std::vector<std::shared_ptr<const C2Info>> C2Buffer::info() const {
+    return mImpl->info();
 }
 
 c2_status_t C2Buffer::setInfo(const std::shared_ptr<C2Info> &info) {
diff --git a/media/libstagefright/codecs/aacdec/C2SoftAac.cpp b/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
index 390f36c..5ddfc14 100644
--- a/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
+++ b/media/libstagefright/codecs/aacdec/C2SoftAac.cpp
@@ -316,9 +316,9 @@
             work->worklets.front()->output.buffers.clear();
             work->worklets.front()->output.buffers.push_back(buffer);
             work->worklets.front()->output.ordinal = work->input.ordinal;
-            work->worklets_processed = 1u;
+            work->workletsProcessed = 1u;
         };
-        if (work && work->input.ordinal.frame_index == outInfo.frameIndex) {
+        if (work && work->input.ordinal.frameIndex == c2_cntr64_t(outInfo.frameIndex)) {
             fillWork(work);
         } else {
             finish(outInfo.frameIndex, fillWork);
@@ -332,7 +332,7 @@
 void C2SoftAac::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
-    work->worklets_processed = 0u;
+    work->workletsProcessed = 0u;
     if (mSignalledError) {
         return;
     }
@@ -346,8 +346,8 @@
     size_t offset = 0u;
     size_t size = view.capacity();
 
-    bool eos = (work->input.flags & C2BufferPack::FLAG_END_OF_STREAM) != 0;
-    bool codecConfig = (work->input.flags & C2BufferPack::FLAG_CODEC_CONFIG) != 0;
+    bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+    bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
 
     //TODO
 #if 0
@@ -381,8 +381,8 @@
     }
 
     Info inInfo;
-    inInfo.frameIndex = work->input.ordinal.frame_index;
-    inInfo.timestamp = work->input.ordinal.timestamp;
+    inInfo.frameIndex = work->input.ordinal.frameIndex.peeku();
+    inInfo.timestamp = work->input.ordinal.timestamp.peeku();
     inInfo.bufferSize = size;
     inInfo.decodedSizes.clear();
     while (size > 0u) {
@@ -604,13 +604,13 @@
             work->worklets.front()->output.buffers.clear();
             work->worklets.front()->output.buffers.emplace_back(nullptr);
             work->worklets.front()->output.ordinal = work->input.ordinal;
-            work->worklets_processed = 1u;
+            work->workletsProcessed = 1u;
         };
         while (mBuffersInfo.size() > 1u) {
             finish(mBuffersInfo.front().frameIndex, fillEmptyWork);
             mBuffersInfo.pop_front();
         }
-        if (work->worklets_processed == 0u) {
+        if (work->workletsProcessed == 0u) {
             fillEmptyWork(work);
         }
         mBuffersInfo.clear();
diff --git a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
index 94308c4..7bce21d 100644
--- a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
+++ b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.cpp
@@ -176,12 +176,12 @@
 void C2SoftAacEnc::process(
         const std::unique_ptr<C2Work> &work,
         const std::shared_ptr<C2BlockPool> &pool) {
-    work->worklets_processed = 0u;
+    work->workletsProcessed = 0u;
 
     if (mSignalledError) {
         return;
     }
-    bool eos = (work->input.flags & C2BufferPack::FLAG_END_OF_STREAM) != 0;
+    bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
 
     if (!mSentCodecSpecificData) {
         // The very first thing we want to output is the codec specific
@@ -215,7 +215,7 @@
 #if defined(LOG_NDEBUG) && !LOG_NDEBUG
         hexdump(csd->m.value, csd->flexCount());
 #endif
-        work->worklets.front()->output.infos.push_back(std::move(csd));
+        work->worklets.front()->output.configUpdate.push_back(std::move(csd));
 
         mOutBufferSize = encInfo.maxOutBufBytes;
         mNumBytesPerInputFrame = encInfo.frameLength * mNumChannels * sizeof(int16_t);
@@ -225,7 +225,7 @@
     }
 
     C2ReadView view = work->input.buffers[0]->data().linearBlocks().front().map().get();
-    uint64_t timestamp = mInputTimeUs;
+    uint64_t timestamp = mInputTimeUs.peeku();
 
     size_t numFrames = (view.capacity() + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
             / mNumBytesPerInputFrame;
@@ -336,11 +336,11 @@
     }
 
     work->worklets.front()->output.flags =
-        (C2BufferPack::flags_t)(eos ? C2BufferPack::FLAG_END_OF_STREAM : 0);
+        (C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0);
     work->worklets.front()->output.buffers.clear();
     work->worklets.front()->output.ordinal = work->input.ordinal;
     work->worklets.front()->output.ordinal.timestamp = timestamp;
-    work->worklets_processed = 1u;
+    work->workletsProcessed = 1u;
     if (nOutputBytes) {
         work->worklets.front()->output.buffers.push_back(
                 createLinearBuffer(block, 0, nOutputBytes));
@@ -350,7 +350,7 @@
 
 #if 0
     ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
-          nOutputBytes, mInputTimeUs, outHeader->nFlags);
+          nOutputBytes, mInputTimeUs.peekll(), outHeader->nFlags);
 
     hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
 #endif
diff --git a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.h b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.h
index 947c960..c9f440f 100644
--- a/media/libstagefright/codecs/aacenc/C2SoftAacEnc.h
+++ b/media/libstagefright/codecs/aacenc/C2SoftAacEnc.h
@@ -57,7 +57,7 @@
 
     bool mSentCodecSpecificData;
     size_t mInputSize;
-    int64_t mInputTimeUs;
+    c2_cntr64_t mInputTimeUs;
 
     bool mSignalledError;
 
diff --git a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
index 0da9cc7..cc12d3c 100644
--- a/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
+++ b/media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp
@@ -206,14 +206,14 @@
 
 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
     uint32_t flags = 0;
-    if ((work->input.flags & C2BufferPack::FLAG_END_OF_STREAM)) {
-        flags |= C2BufferPack::FLAG_END_OF_STREAM;
+    if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM)) {
+        flags |= C2FrameData::FLAG_END_OF_STREAM;
     }
-    work->worklets.front()->output.flags = (C2BufferPack::flags_t)flags;
+    work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
     work->worklets.front()->output.buffers.clear();
     work->worklets.front()->output.buffers.emplace_back(nullptr);
     work->worklets.front()->output.ordinal = work->input.ordinal;
-    work->worklets_processed = 1u;
+    work->workletsProcessed = 1u;
 }
 
 }  // namespace
@@ -1061,17 +1061,17 @@
     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mAllocatedBlock));
     auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
         uint32_t flags = 0;
-        if (work->input.flags & C2BufferPack::FLAG_END_OF_STREAM) {
-            flags |= C2BufferPack::FLAG_END_OF_STREAM;
+        if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+            flags |= C2FrameData::FLAG_END_OF_STREAM;
             ALOGV("EOS");
         }
-        work->worklets.front()->output.flags = (C2BufferPack::flags_t)flags;
+        work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
         work->worklets.front()->output.buffers.clear();
         work->worklets.front()->output.buffers.push_back(buffer);
         work->worklets.front()->output.ordinal = work->input.ordinal;
-        work->worklets_processed = 1u;
+        work->workletsProcessed = 1u;
     };
-    if (work && index == work->input.ordinal.frame_index) {
+    if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
         fillWork(work);
     } else {
         finish(index, fillWork);
@@ -1084,25 +1084,25 @@
     bool eos = false;
 
     work->result = C2_OK;
-    work->worklets_processed = 0u;
+    work->workletsProcessed = 0u;
 
     const C2ConstLinearBlock &buffer =
         work->input.buffers[0]->data().linearBlocks().front();
     if (buffer.capacity() == 0) {
-        ALOGV("empty input: %llu", (long long)work->input.ordinal.frame_index);
+        ALOGV("empty input: %llu", work->input.ordinal.frameIndex.peekull());
         // TODO: result?
         fillEmptyWork(work);
-        if ((work->input.flags & C2BufferPack::FLAG_END_OF_STREAM)) {
+        if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM)) {
             eos = true;
         }
         return;
-    } else if (work->input.flags & C2BufferPack::FLAG_END_OF_STREAM) {
-        ALOGV("input EOS: %llu", (long long)work->input.ordinal.frame_index);
+    } else if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+        ALOGV("input EOS: %llu", work->input.ordinal.frameIndex.peekull());
         eos = true;
     }
 
     C2ReadView input = work->input.buffers[0]->data().linearBlocks().front().map().get();
-    uint32_t workIndex = work->input.ordinal.frame_index & 0xFFFFFFFF;
+    uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
     size_t inOffset = 0u;
 
     while (inOffset < input.capacity()) {
@@ -1266,7 +1266,7 @@
     }
 
     if (drainMode == DRAIN_COMPONENT_WITH_EOS
-            && work && work->worklets_processed == 0u) {
+            && work && work->workletsProcessed == 0u) {
         fillEmptyWork(work);
     }
 
diff --git a/media/libstagefright/codecs/cmds/Android.bp b/media/libstagefright/codecs/cmds/Android.bp
index 40f1a3d..6dba0a3 100644
--- a/media/libstagefright/codecs/cmds/Android.bp
+++ b/media/libstagefright/codecs/cmds/Android.bp
@@ -13,6 +13,7 @@
         "libcutils",
         "libgui",
         "liblog",
+        "libmediaextractor",
         "libstagefright",
         "libstagefright_codec2",
         "libstagefright_codec2_vndk",
diff --git a/media/libstagefright/codecs/cmds/codec2.cpp b/media/libstagefright/codecs/cmds/codec2.cpp
index 78fb527..ec05d7a 100644
--- a/media/libstagefright/codecs/cmds/codec2.cpp
+++ b/media/libstagefright/codecs/cmds/codec2.cpp
@@ -247,7 +247,7 @@
             }
             int slot;
             sp<Fence> fence;
-            ALOGV("Render: Frame #%" PRId64, work->worklets.front()->output.ordinal.frame_index);
+            ALOGV("Render: Frame #%lld", work->worklets.front()->output.ordinal.frameIndex.peekll());
             const std::shared_ptr<C2Buffer> &output = work->worklets.front()->output.buffers[0];
             if (output) {
                 const C2ConstGraphicBlock &block = output->data().graphicBlocks().front();
@@ -266,7 +266,7 @@
                 status_t err = igbp->attachBuffer(&slot, buffer);
 
                 IGraphicBufferProducer::QueueBufferInput qbi(
-                        work->worklets.front()->output.ordinal.timestamp * 1000ll,
+                        (work->worklets.front()->output.ordinal.timestamp * 1000ll).peekll(),
                         false,
                         HAL_DATASPACE_UNKNOWN,
                         Rect(block.width(), block.height()),
@@ -338,9 +338,9 @@
                 mQueueCondition.wait_for(l, 100ms);
             }
         }
-        work->input.flags = (C2BufferPack::flags_t)0;
+        work->input.flags = (C2FrameData::flags_t)0;
         work->input.ordinal.timestamp = timestamp;
-        work->input.ordinal.frame_index = numFrames;
+        work->input.ordinal.frameIndex = numFrames;
 
         std::shared_ptr<C2LinearBlock> block;
         mLinearPool->fetchLinearBlock(
diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp
index 804046a..c8965d9 100644
--- a/media/libstagefright/foundation/ABuffer.cpp
+++ b/media/libstagefright/foundation/ABuffer.cpp
@@ -19,13 +19,11 @@
 #include "ADebug.h"
 #include "ALooper.h"
 #include "AMessage.h"
-#include "MediaBufferBase.h"
 
 namespace android {
 
 ABuffer::ABuffer(size_t capacity)
-    : mMediaBufferBase(NULL),
-      mRangeOffset(0),
+    : mRangeOffset(0),
       mInt32Data(0),
       mOwnsData(true) {
     mData = malloc(capacity);
@@ -39,8 +37,7 @@
 }
 
 ABuffer::ABuffer(void *data, size_t capacity)
-    : mMediaBufferBase(NULL),
-      mData(data),
+    : mData(data),
       mCapacity(capacity),
       mRangeOffset(0),
       mRangeLength(capacity),
@@ -66,8 +63,6 @@
             mData = NULL;
         }
     }
-
-    setMediaBufferBase(NULL);
 }
 
 void ABuffer::setRange(size_t offset, size_t size) {
@@ -85,19 +80,5 @@
     return mMeta;
 }
 
-MediaBufferBase *ABuffer::getMediaBufferBase() {
-    if (mMediaBufferBase != NULL) {
-        mMediaBufferBase->add_ref();
-    }
-    return mMediaBufferBase;
-}
-
-void ABuffer::setMediaBufferBase(MediaBufferBase *mediaBuffer) {
-    if (mMediaBufferBase != NULL) {
-        mMediaBufferBase->release();
-    }
-    mMediaBufferBase = mediaBuffer;
-}
-
 }  // namespace android
 
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 4dfe5e5..2258e2c 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -62,8 +62,6 @@
         "AStringUtils.cpp",
         "ByteUtils.cpp",
         "ColorUtils.cpp",
-        "MediaBuffer.cpp",
-        "MediaBufferGroup.cpp",
         "MediaDefs.cpp",
         "MediaKeys.cpp",
         "MetaData.cpp",
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h
index ef11434..8fe9f8d 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ABuffer.h
@@ -27,7 +27,6 @@
 namespace android {
 
 struct AMessage;
-class MediaBufferBase;
 
 struct ABuffer : public RefBase {
     explicit ABuffer(size_t capacity);
@@ -49,17 +48,12 @@
 
     sp<AMessage> meta();
 
-    MediaBufferBase *getMediaBufferBase();
-    void setMediaBufferBase(MediaBufferBase *mediaBuffer);
-
 protected:
     virtual ~ABuffer();
 
 private:
     sp<AMessage> mMeta;
 
-    MediaBufferBase *mMediaBufferBase;
-
     void *mData;
     size_t mCapacity;
     size_t mRangeOffset;
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h
deleted file mode 100644
index 99418fb..0000000
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaBufferBase.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_BUFFER_BASE_H_
-
-#define MEDIA_BUFFER_BASE_H_
-
-namespace android {
-
-class MediaBufferBase {
-public:
-    MediaBufferBase() {}
-
-    virtual void release() = 0;
-    virtual void add_ref() = 0;
-
-protected:
-    virtual ~MediaBufferBase() {}
-
-private:
-    MediaBufferBase(const MediaBufferBase &);
-    MediaBufferBase &operator=(const MediaBufferBase &);
-};
-
-}  // namespace android
-
-#endif  // MEDIA_BUFFER_BASE_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaBuffer.h b/media/libstagefright/include/media/stagefright/MediaBuffer.h
new file mode 120000
index 0000000..1d49c1a
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaBuffer.h
@@ -0,0 +1 @@
+../../../../libmediaextractor/include/media/stagefright/MediaBuffer.h
\ No newline at end of file
diff --git a/media/libstagefright/include/media/stagefright/MediaBufferGroup.h b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h
new file mode 120000
index 0000000..009b3d9
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/MediaBufferGroup.h
@@ -0,0 +1 @@
+../../../../libmediaextractor/include/media/stagefright/MediaBufferGroup.h
\ No newline at end of file
diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp
index 35119c2..e67a949 100644
--- a/media/libstagefright/tests/Android.bp
+++ b/media/libstagefright/tests/Android.bp
@@ -15,6 +15,7 @@
         "libcutils",
         "libgui",
         "libmedia",
+        "libmediaextractor",
         "libstagefright",
         "libstagefright_foundation",
         "libstagefright_omx",
diff --git a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
index f159398..59d8366 100644
--- a/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaBrowser2Impl.java
@@ -61,6 +61,31 @@
         }
     }
 
+    @Override
+    public void subscribe_impl(String parentId, Bundle options) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void unsubscribe_impl(String parentId, Bundle options) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void getItem_impl(String mediaId) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void getChildren_impl(String parentId, int page, int pageSize, Bundle options) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void search_impl(String query, int page, int pageSize, Bundle extras) {
+        // TODO(jaewan): Implement
+    }
+
     public void onGetRootResult(
             final Bundle rootHints, final String rootMediaId, final Bundle rootExtra) {
         getCallbackExecutor().execute(() -> {
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 08a7165..ac3f311 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -16,12 +16,15 @@
 
 package com.android.media;
 
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.media.IMediaSession2;
 import android.media.IMediaSession2Callback;
+import android.media.MediaController2.PlaybackInfo;
+import android.media.MediaItem2;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
@@ -29,14 +32,19 @@
 import android.media.MediaController2;
 import android.media.MediaController2.ControllerCallback;
 import android.media.MediaPlayerBase;
+import android.media.MediaSession2.PlaylistParam;
 import android.media.MediaSessionService2;
+import android.media.PlaybackState2;
+import android.media.Rating2;
 import android.media.SessionToken;
 import android.media.session.PlaybackState;
 import android.media.update.MediaController2Provider;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ResultReceiver;
 import android.support.annotation.GuardedBy;
 import android.util.Log;
 
@@ -257,69 +265,128 @@
         }
     }
 
+    //////////////////////////////////////////////////////////////////////////////////////
+    // TODO(jaewan): Implement follows
+    //////////////////////////////////////////////////////////////////////////////////////
     @Override
-    public PlaybackState getPlaybackState_impl() {
-        final IMediaSession2 binder = mSessionBinder;
-        if (binder != null) {
-            try {
-                return binder.getPlaybackState();
-            } catch (RemoteException e) {
-                Log.w(TAG, "Cannot connect to the service or the session is gone", e);
-            }
-        } else {
-            Log.w(TAG, "Session isn't active", new IllegalStateException());
-        }
-        // TODO(jaewan): What to return for error case?
+    public PendingIntent getSessionActivity_impl() {
+        // TODO(jaewan): Implement
         return null;
     }
 
     @Override
-    public void addPlaybackListener_impl(
-            MediaPlayerBase.PlaybackListener listener, Handler handler) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener shouldn't be null");
-        }
-        if (handler == null) {
-            throw new IllegalArgumentException("handler shouldn't be null");
-        }
-        boolean registerCallback;
-        synchronized (mLock) {
-            if (PlaybackListenerHolder.contains(mPlaybackListeners, listener)) {
-                throw new IllegalArgumentException("listener is already added. Ignoring.");
-            }
-            registerCallback = mPlaybackListeners.isEmpty();
-            mPlaybackListeners.add(new PlaybackListenerHolder(listener, handler));
-        }
-        if (registerCallback) {
-            registerCallbackForPlaybackNotLocked();
-        }
+    public int getRatingType_impl() {
+        // TODO(jaewan): Implement
+        return 0;
     }
 
     @Override
-    public void removePlaybackListener_impl(MediaPlayerBase.PlaybackListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener shouldn't be null");
-        }
-        boolean unregisterCallback;
-        synchronized (mLock) {
-            int idx = PlaybackListenerHolder.indexOf(mPlaybackListeners, listener);
-            if (idx >= 0) {
-                mPlaybackListeners.get(idx).removeCallbacksAndMessages(null);
-                mPlaybackListeners.remove(idx);
-            }
-            unregisterCallback = mPlaybackListeners.isEmpty();
-        }
-        if (unregisterCallback) {
-            final IMediaSession2 binder = mSessionBinder;
-            if (binder != null) {
-                // Lazy unregister
-                try {
-                    binder.unregisterCallback(mSessionCallbackStub, CALLBACK_FLAG_PLAYBACK);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Cannot connect to the service or the session is gone", e);
-                }
-            }
-        }
+    public void setVolumeTo_impl(int value, int flags) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void adjustVolume_impl(int direction, int flags) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public PlaybackInfo getPlaybackInfo_impl() {
+        // TODO(jaewan): Implement
+        return null;
+    }
+
+    @Override
+    public void prepareFromUri_impl(Uri uri, Bundle extras) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void prepareFromSearch_impl(String query, Bundle extras) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void prepareMediaId_impl(String mediaId, Bundle extras) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void playFromSearch_impl(String query, Bundle extras) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void playFromUri_impl(String uri, Bundle extras) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void playFromMediaId_impl(String mediaId, Bundle extras) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void setRating_impl(Rating2 rating) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void sendCustomCommand_impl(Command command, Bundle args, ResultReceiver cb) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public List<MediaItem2> getPlaylist_impl() {
+        // TODO(jaewan): Implement
+        return null;
+    }
+
+    @Override
+    public void prepare_impl() {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void fastForward_impl() {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void rewind_impl() {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void seekTo_impl(long pos) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void setCurrentPlaylistItem_impl(int index) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public PlaybackState2 getPlaybackState_impl() {
+        // TODO(jaewan): Implement
+        return null;
+    }
+
+    @Override
+    public void removePlaylistItem_impl(MediaItem2 index) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void addPlaylistItem_impl(int index, MediaItem2 item) {
+    // TODO(jaewan): Implement
+    }
+
+    @Override
+    public PlaylistParam getPlaylistParam_impl() {
+        // TODO(jaewan): Implement
+        return null;
     }
 
     ///////////////////////////////////////////////////
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index 430ab4c..b177dda 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -16,12 +16,20 @@
 
 package com.android.media;
 
+import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.media.MediaLibraryService2;
 import android.media.MediaLibraryService2.MediaLibrarySession;
+import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
+import android.media.MediaPlayerBase;
 import android.media.MediaSession2;
+import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
+import android.media.VolumeProvider;
 import android.media.update.MediaLibraryService2Provider;
+import android.os.Bundle;
 
 public class MediaLibraryService2Impl extends MediaSessionService2Impl implements
         MediaLibraryService2Provider {
@@ -51,4 +59,31 @@
         serviceIntent.setAction(MediaLibraryService2.SERVICE_INTERFACE);
         return serviceIntent;
     }
+
+    public static class MediaLibrarySessionImpl extends MediaSession2Impl
+            implements MediaLibrarySessionProvider {
+        private final MediaLibrarySession mInstance;
+        private final MediaLibrarySessionCallback mCallback;
+
+        public MediaLibrarySessionImpl(MediaLibrarySession instance, Context context,
+                MediaPlayerBase player, String id,
+                MediaLibrarySessionCallback callback, VolumeProvider volumeProvider, int ratingType,
+                PendingIntent sessionActivity) {
+            super(instance, context, player, id, callback, volumeProvider, ratingType,
+                    sessionActivity);
+            mInstance = instance;
+            mCallback = callback;
+        }
+
+        @Override
+        public void notifyChildrenChanged_impl(ControllerInfo controller, String parentId,
+                Bundle options) {
+            // TODO(jaewan): Implements
+        }
+
+        @Override
+        public void notifyChildrenChanged_impl(String parentId, Bundle options) {
+            // TODO(jaewan): Implements
+        }
+    }
 }
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 19ea1b2..2e71641 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -17,24 +17,32 @@
 package com.android.media;
 
 import android.Manifest.permission;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.media.AudioAttributes;
 import android.media.IMediaSession2Callback;
-import android.media.MediaController2;
+import android.media.MediaItem2;
 import android.media.MediaPlayerBase;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Builder;
+import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
+import android.media.MediaSession2.CommandGroup;
 import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.PlaylistParam;
 import android.media.MediaSession2.SessionCallback;
 import android.media.SessionToken;
+import android.media.VolumeProvider;
 import android.media.session.MediaSessionManager;
 import android.media.session.PlaybackState;
 import android.media.update.MediaSession2Provider;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.ResultReceiver;
 import android.util.Log;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -60,16 +68,21 @@
 
     /**
      * Can be only called by the {@link Builder#build()}.
-     *
+     * 
      * @param instance
      * @param context
      * @param player
      * @param id
      * @param callback
+     * @param volumeProvider
+     * @param ratingType
+     * @param sessionActivity
      */
     public MediaSession2Impl(MediaSession2 instance, Context context, MediaPlayerBase player,
-            String id, SessionCallback callback) {
+            String id, SessionCallback callback, VolumeProvider volumeProvider, int ratingType,
+            PendingIntent sessionActivity) {
         mInstance = instance;
+        // TODO(jaewan): Keep other params.
 
         // Argument checks are done by builder already.
         // Initialize finals first.
@@ -102,7 +115,7 @@
     //               setPlayer(null). Token can be available when player is null, and
     //               controller can also attach to session.
     @Override
-    public void setPlayer_impl(MediaPlayerBase player) throws IllegalArgumentException {
+    public void setPlayer_impl(MediaPlayerBase player, VolumeProvider volumeProvider) throws IllegalArgumentException {
         ensureCallingThread();
         if (player == null) {
             throw new IllegalArgumentException("player shouldn't be null");
@@ -156,6 +169,16 @@
     }
 
     @Override
+    public void setAudioAttributes_impl(AudioAttributes attributes) {
+        // implement
+    }
+
+    @Override
+    public void setAudioFocusRequest_impl(int focusGain) {
+        // implement
+    }
+
+    @Override
     public void play_impl() {
         ensureCallingThread();
         ensurePlayer();
@@ -191,43 +214,6 @@
     }
 
     @Override
-    public PlaybackState getPlaybackState_impl() {
-        ensureCallingThread();
-        ensurePlayer();
-        return mPlayer.getPlaybackState();
-    }
-
-    @Override
-    public void addPlaybackListener_impl(
-            MediaPlayerBase.PlaybackListener listener, Handler handler) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener shouldn't be null");
-        }
-        if (handler == null) {
-            throw new IllegalArgumentException("handler shouldn't be null");
-        }
-        ensureCallingThread();
-        if (PlaybackListenerHolder.contains(mListeners, listener)) {
-            Log.w(TAG, "listener is already added. Ignoring.");
-            return;
-        }
-        mListeners.add(new PlaybackListenerHolder(listener, handler));
-    }
-
-    @Override
-    public void removePlaybackListener_impl(MediaPlayerBase.PlaybackListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener shouldn't be null");
-        }
-        ensureCallingThread();
-        int idx = PlaybackListenerHolder.indexOf(mListeners, listener);
-        if (idx >= 0) {
-            mListeners.get(idx).removeCallbacksAndMessages(null);
-            mListeners.remove(idx);
-        }
-    }
-
-    @Override
     public void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout) {
         ensureCallingThread();
         if (controller == null) {
@@ -239,6 +225,65 @@
         mSessionStub.notifyCustomLayoutNotLocked(controller, layout);
     }
 
+    //////////////////////////////////////////////////////////////////////////////////////
+    // TODO(jaewan): Implement follows
+    //////////////////////////////////////////////////////////////////////////////////////
+    @Override
+    public void setPlayer_impl(MediaPlayerBase player) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void notifyMetadataChanged_impl() {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
+            ResultReceiver receiver) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void sendCustomCommand_impl(Command command, Bundle args) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void setPlaylist_impl(List<MediaItem2> playlist, PlaylistParam param) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void prepare_impl() {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void fastForward_impl() {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void rewind_impl() {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void seekTo_impl(long pos) {
+        // TODO(jaewan): Implement
+    }
+
+    @Override
+    public void setCurrentPlaylistItem_impl(int index) {
+        // TODO(jaewan): Implement
+    }
+
     ///////////////////////////////////////////////////
     // Protected or private methods
     ///////////////////////////////////////////////////
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index f2772ed..3f7a1b1 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.media.IMediaSession2;
 import android.media.IMediaSession2Callback;
+import android.media.MediaLibraryService2.BrowserRoot;
 import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
 import android.media.MediaSession2;
 import android.media.MediaSession2.Command;
@@ -36,7 +37,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
-import android.service.media.MediaBrowserService.BrowserRoot;
 import android.support.annotation.GuardedBy;
 import android.util.ArrayMap;
 import android.util.Log;
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 07b565e..43acaf9 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -16,6 +16,7 @@
 
 package com.android.media.update;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
@@ -23,6 +24,8 @@
 import android.media.MediaBrowser2.BrowserCallback;
 import android.media.MediaController2;
 import android.media.MediaLibraryService2;
+import android.media.MediaLibraryService2.MediaLibrarySession;
+import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
 import android.media.MediaPlayerBase;
 import android.media.MediaSession2;
 import android.media.MediaSession2.ControllerInfo;
@@ -30,9 +33,11 @@
 import android.media.MediaSessionService2;
 import android.media.IMediaSession2Callback;
 import android.media.SessionToken;
+import android.media.VolumeProvider;
 import android.media.update.MediaBrowser2Provider;
 import android.media.update.MediaControlView2Provider;
 import android.media.update.MediaController2Provider;
+import android.media.update.MediaLibraryService2Provider.MediaLibrarySessionProvider;
 import android.media.update.MediaSession2Provider;
 import android.media.update.MediaSessionService2Provider;
 import android.media.update.VideoView2Provider;
@@ -46,6 +51,7 @@
 import com.android.media.MediaBrowser2Impl;
 import com.android.media.MediaController2Impl;
 import com.android.media.MediaLibraryService2Impl;
+import com.android.media.MediaLibraryService2Impl.MediaLibrarySessionImpl;
 import com.android.media.MediaSession2Impl;
 import com.android.media.MediaSessionService2Impl;
 import com.android.widget.MediaControlView2Impl;
@@ -75,8 +81,11 @@
 
     @Override
     public MediaSession2Provider createMediaSession2(MediaSession2 instance, Context context,
-            MediaPlayerBase player, String id, SessionCallback callback) {
-        return new MediaSession2Impl(instance, context, player, id, callback);
+            MediaPlayerBase player, String id, SessionCallback callback,
+            VolumeProvider volumeProvider, int ratingType,
+            PendingIntent sessionActivity) {
+        return new MediaSession2Impl(instance, context, player, id, callback,
+                volumeProvider, ratingType, sessionActivity);
     }
 
     @Override
@@ -100,6 +109,15 @@
     }
 
     @Override
+    public MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(
+            MediaLibrarySession instance, Context context, MediaPlayerBase player, String id,
+            MediaLibrarySessionCallback callback, VolumeProvider volumeProvider, int ratingType,
+            PendingIntent sessionActivity) {
+        return new MediaLibrarySessionImpl(instance, context, player, id, callback, volumeProvider,
+                ratingType, sessionActivity);
+    }
+
+    @Override
     public MediaControlView2Provider createMediaControlView2(
             MediaControlView2 instance, ViewProvider superProvider) {
         return new MediaControlView2Impl(instance, superProvider);
diff --git a/packages/MediaComponents/test/src/android/media/MediaController2Test.java b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
index ac0bd73..f99935a 100644
--- a/packages/MediaComponents/test/src/android/media/MediaController2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaController2Test.java
@@ -144,6 +144,8 @@
 
     @Test
     public void testGetPlaybackState() throws InterruptedException {
+        // TODO(jaewan): add equivalent test later
+        /*
         final CountDownLatch latch = new CountDownLatch(1);
         final MediaPlayerBase.PlaybackListener listener = (state) -> {
             assertEquals(PlaybackState.STATE_BUFFERING, state.getState());
@@ -155,8 +157,11 @@
         mPlayer.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_BUFFERING));
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
         assertEquals(PlaybackState.STATE_BUFFERING, mController.getPlaybackState().getState());
+        */
     }
 
+    // TODO(jaewan): add equivalent test later
+    /*
     @Test
     public void testAddPlaybackListener() throws InterruptedException {
         final CountDownLatch latch = new CountDownLatch(2);
@@ -192,6 +197,7 @@
         mPlayer.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_PLAYING));
         assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
+    */
 
     @Test
     public void testControllerCallback_onConnected() throws InterruptedException {
@@ -273,9 +279,6 @@
             });
             final MediaController2 controller = createController(mSession.getToken());
             testHandler.post(() -> {
-                controller.addPlaybackListener((state) -> {
-                    // no-op. Just to set a binder call path from session to controller.
-                }, sessionHandler);
                 final PlaybackState state = createPlaybackState(PlaybackState.STATE_ERROR);
                 for (int i = 0; i < 100; i++) {
                     // triggers call from session to controller.
@@ -360,6 +363,8 @@
         assertTrue(mPlayer.mPlayCalled);
 
         // Test command from session service to controller
+        // TODO(jaewan): Add equivalent tests again
+        /*
         final CountDownLatch latch = new CountDownLatch(1);
         mController.addPlaybackListener((state) -> {
             assertNotNull(state);
@@ -369,6 +374,7 @@
         mPlayer.notifyPlaybackState(
                 TestUtils.createPlaybackState(PlaybackState.STATE_REWINDING));
         assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        */
     }
 
     @Test
@@ -467,10 +473,13 @@
             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);
         mPlayer.notifyPlaybackState(TestUtils.createPlaybackState(PlaybackState.STATE_BUFFERING));
         assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         mController.removePlaybackListener(playbackListener);
+        */
     }
 
     // TODO(jaewan): Add  test for service connect rejection, when we differentiate session
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index c5408e8..7b58f0e 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -139,6 +139,8 @@
 
     @Test
     public void testPlaybackStateChangedListener() throws InterruptedException {
+        // TODO(jaewan): Add equivalent tests again
+        /*
         final CountDownLatch latch = new CountDownLatch(2);
         final MockPlayer player = new MockPlayer(0);
         final PlaybackListener listener = (state) -> {
@@ -164,10 +166,13 @@
         });
         player.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_PAUSED));
         assertTrue(latch.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 BadPlayer player = new BadPlayer(0);
         sHandler.postAndSync(() -> {
@@ -181,6 +186,7 @@
         });
         player.notifyPlaybackState(createPlaybackState(PlaybackState.STATE_PAUSED));
         assertFalse(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        */
     }
 
     private static class BadPlayer extends MockPlayer {
diff --git a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
index 7a16127..acf733f 100644
--- a/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
+++ b/packages/MediaComponents/test/src/android/media/MockMediaLibraryService2.java
@@ -24,7 +24,6 @@
 import android.media.TestUtils.SyncHandler;
 import android.os.Bundle;
 import android.os.Process;
-import android.service.media.MediaBrowserService.BrowserRoot;
 
 import javax.annotation.concurrent.GuardedBy;
 
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e058dc8..7343601 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2939,7 +2939,7 @@
                 sinkDeviceDesc->toAudioPortConfig(&newPatch.sinks[i], &patch->sinks[i]);
 
                 // create a software bridge in PatchPanel if:
-                // - source and sink devices are on differnt HW modules OR
+                // - source and sink devices are on different HW modules OR
                 // - audio HAL version is < 3.0
                 if (!srcDeviceDesc->hasSameHwModuleAs(sinkDeviceDesc) ||
                         (srcDeviceDesc->mModule->getHalVersionMajor() < 3)) {
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 8e5b260..97eaf77 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -1,5 +1,28 @@
 LOCAL_PATH := $(call my-dir)
 
+_software_codecs := \
+    libstagefright_soft_aacdec \
+    libstagefright_soft_aacenc \
+    libstagefright_soft_amrdec \
+    libstagefright_soft_amrnbenc \
+    libstagefright_soft_amrwbenc \
+    libstagefright_soft_avcdec \
+    libstagefright_soft_avcenc \
+    libstagefright_soft_flacdec \
+    libstagefright_soft_flacenc \
+    libstagefright_soft_g711dec \
+    libstagefright_soft_gsmdec \
+    libstagefright_soft_hevcdec \
+    libstagefright_soft_mp3dec \
+    libstagefright_soft_mpeg2dec \
+    libstagefright_soft_mpeg4dec \
+    libstagefright_soft_mpeg4enc \
+    libstagefright_soft_opusdec \
+    libstagefright_soft_rawdec \
+    libstagefright_soft_vorbisdec \
+    libstagefright_soft_vpxdec \
+    libstagefright_soft_vpxenc \
+
 # service executable
 include $(CLEAR_VARS)
 # seccomp is not required for coverage build.
@@ -27,6 +50,15 @@
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_VENDOR_MODULE := true
 LOCAL_32_BIT_ONLY := true
+# Since this is 32-bit-only module, only 32-bit version of the codecs are installed.
+# TODO(b/72343507): eliminate the need for manually adding .vendor suffix. This should be done
+# by the build system.
+LOCAL_REQUIRED_MODULES := \
+$(foreach codec,$(_software_codecs),\
+  $(eval _vendor_suffix := $(if $(BOARD_VNDK_VERSION),.vendor))\
+  $(codec)$(_vendor_suffix)\
+)
+_software_codecs :=
 LOCAL_INIT_RC := android.hardware.media.omx@1.0-service.rc
 
 include $(BUILD_EXECUTABLE)