Merge "Convert clearkey plugin to HIDL"
diff --git a/include/media/DataSourceBase.h b/include/media/DataSourceBase.h
new file mode 120000
index 0000000..54c8047
--- /dev/null
+++ b/include/media/DataSourceBase.h
@@ -0,0 +1 @@
+../../media/libmediaextractor/include/media/DataSourceBase.h
\ No newline at end of file
diff --git a/include/media/MicrophoneInfo.h b/include/media/MicrophoneInfo.h
index b0199d4..2287aca 100644
--- a/include/media/MicrophoneInfo.h
+++ b/include/media/MicrophoneInfo.h
@@ -42,7 +42,7 @@
     MicrophoneInfo(audio_microphone_characteristic_t& characteristic) {
         mDeviceId = String16(&characteristic.device_id[0]);
         mPortId = characteristic.id;
-        mType = characteristic.type;
+        mType = characteristic.device;
         mAddress = String16(&characteristic.address[0]);
         mDeviceLocation = characteristic.location;
         mDeviceGroup = characteristic.group;
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 6f28374..1614ca4 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -19,7 +19,7 @@
 #include <utils/Log.h>
 
 #include "AACExtractor.h"
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -35,7 +35,7 @@
 
 class AACSource : public MediaSourceBase {
 public:
-    AACSource(const sp<DataSource> &source,
+    AACSource(DataSourceBase *source,
               const sp<MetaData> &meta,
               const Vector<uint64_t> &offset_vector,
               int64_t frame_duration_us);
@@ -53,7 +53,7 @@
 
 private:
     static const size_t kMaxFrameSize;
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<MetaData> mMeta;
 
     off64_t mOffset;
@@ -91,7 +91,7 @@
 // The returned value is the AAC frame size with the ADTS header length (regardless of
 //     the presence of the CRC).
 // If headerSize is non-NULL, it will be used to return the size of the header of this ADTS frame.
-static size_t getAdtsFrameLength(const sp<DataSource> &source, off64_t offset, size_t* headerSize) {
+static size_t getAdtsFrameLength(DataSourceBase *source, off64_t offset, size_t* headerSize) {
 
     const size_t kAdtsHeaderLengthNoCrc = 7;
     const size_t kAdtsHeaderLengthWithCrc = 9;
@@ -132,7 +132,7 @@
 }
 
 AACExtractor::AACExtractor(
-        const sp<DataSource> &source, const sp<AMessage> &_meta)
+        DataSourceBase *source, const sp<AMessage> &_meta)
     : mDataSource(source),
       mInitCheck(NO_INIT),
       mFrameDurationUs(0) {
@@ -229,7 +229,7 @@
 const size_t AACSource::kMaxFrameSize = 8192;
 
 AACSource::AACSource(
-        const sp<DataSource> &source, const sp<MetaData> &meta,
+        DataSourceBase *source, const sp<MetaData> &meta,
         const Vector<uint64_t> &offset_vector,
         int64_t frame_duration_us)
     : mDataSource(source),
@@ -332,13 +332,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 static MediaExtractor* CreateExtractor(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         const sp<AMessage>& meta) {
     return new AACExtractor(source, meta);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *meta) {
     off64_t pos = 0;
 
diff --git a/media/extractors/aac/AACExtractor.h b/media/extractors/aac/AACExtractor.h
index 33fbba7..e99699c 100644
--- a/media/extractors/aac/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -29,7 +29,7 @@
 
 class AACExtractor : public MediaExtractor {
 public:
-    AACExtractor(const sp<DataSource> &source, const sp<AMessage> &meta);
+    AACExtractor(DataSourceBase *source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -42,7 +42,7 @@
     virtual ~AACExtractor();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<MetaData> mMeta;
     status_t mInitCheck;
 
@@ -54,7 +54,7 @@
 };
 
 bool SniffAAC(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index 10be50c..547e3f5 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -20,7 +20,7 @@
 
 #include "AMRExtractor.h"
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -33,7 +33,7 @@
 
 class AMRSource : public MediaSourceBase {
 public:
-    AMRSource(const sp<DataSource> &source,
+    AMRSource(DataSourceBase *source,
               const sp<MetaData> &meta,
               bool isWide,
               const off64_t *offset_table,
@@ -51,7 +51,7 @@
     virtual ~AMRSource();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<MetaData> mMeta;
     bool mIsWide;
 
@@ -97,7 +97,7 @@
     return frameSize;
 }
 
-static status_t getFrameSizeByOffset(const sp<DataSource> &source,
+static status_t getFrameSizeByOffset(DataSourceBase *source,
         off64_t offset, bool isWide, size_t *frameSize) {
     uint8_t header;
     ssize_t count = source->readAt(offset, &header, 1);
@@ -116,7 +116,7 @@
     return OK;
 }
 
-AMRExtractor::AMRExtractor(const sp<DataSource> &source)
+AMRExtractor::AMRExtractor(DataSourceBase *source)
     : mDataSource(source),
       mInitCheck(NO_INIT),
       mOffsetTableLength(0) {
@@ -206,7 +206,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 AMRSource::AMRSource(
-        const sp<DataSource> &source, const sp<MetaData> &meta,
+        DataSourceBase *source, const sp<MetaData> &meta,
         bool isWide, const off64_t *offset_table, size_t offset_table_length)
     : mDataSource(source),
       mMeta(meta),
@@ -339,7 +339,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffAMR(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *) {
     char header[9];
 
@@ -372,13 +372,13 @@
         1,
         "AMR Extractor",
         [](
-                const sp<DataSource> &source,
+                DataSourceBase *source,
                 String8 *mimeType,
                 float *confidence,
                 sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
             if (SniffAMR(source, mimeType, confidence, meta)) {
                 return [](
-                        const sp<DataSource> &source,
+                        DataSourceBase *source,
                         const sp<AMessage>& meta __unused) -> MediaExtractor* {
                     return new AMRExtractor(source);};
             }
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index 56883e3..d6d49f2 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -29,7 +29,7 @@
 
 class AMRExtractor : public MediaExtractor {
 public:
-    explicit AMRExtractor(const sp<DataSource> &source);
+    explicit AMRExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -42,7 +42,7 @@
     virtual ~AMRExtractor();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<MetaData> mMeta;
     status_t mInitCheck;
     bool mIsWide;
@@ -55,7 +55,7 @@
 };
 
 bool SniffAMR(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index ba28e86..8dbb5a1 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -22,7 +22,7 @@
 // libFLAC parser
 #include "FLAC/stream_decoder.h"
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -165,7 +165,7 @@
 
 public:
     FLACSource(
-            const sp<DataSource> &dataSource,
+            DataSourceBase *dataSource,
             const sp<MetaData> &trackMetadata);
 
     virtual status_t start(MetaData *params);
@@ -179,7 +179,7 @@
     virtual ~FLACSource();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<MetaData> mTrackMetadata;
     sp<FLACParser> mParser;
     bool mInitCheck;
@@ -203,7 +203,7 @@
     };
 
     explicit FLACParser(
-        const sp<DataSource> &dataSource,
+        DataSourceBase *dataSource,
         // If metadata pointers aren't provided, we don't fill them
         const sp<MetaData> &fileMetadata = 0,
         const sp<MetaData> &trackMetadata = 0);
@@ -243,7 +243,7 @@
     virtual ~FLACParser();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<MetaData> mFileMetadata;
     sp<MetaData> mTrackMetadata;
     bool mInitCheck;
@@ -612,7 +612,7 @@
 // FLACParser
 
 FLACParser::FLACParser(
-        const sp<DataSource> &dataSource,
+        DataSourceBase *dataSource,
         const sp<MetaData> &fileMetadata,
         const sp<MetaData> &trackMetadata)
     : mDataSource(dataSource),
@@ -833,7 +833,7 @@
 // FLACsource
 
 FLACSource::FLACSource(
-        const sp<DataSource> &dataSource,
+        DataSourceBase *dataSource,
         const sp<MetaData> &trackMetadata)
     : mDataSource(dataSource),
       mTrackMetadata(trackMetadata),
@@ -918,7 +918,7 @@
 // FLACExtractor
 
 FLACExtractor::FLACExtractor(
-        const sp<DataSource> &dataSource)
+        DataSourceBase *dataSource)
     : mDataSource(dataSource),
       mInitCheck(false)
 {
@@ -969,7 +969,7 @@
 // Sniffer
 
 bool SniffFLAC(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *)
 {
     // first 4 is the signature word
@@ -1000,13 +1000,13 @@
             1,
             "FLAC Extractor",
             [](
-                    const sp<DataSource> &source,
+                    DataSourceBase *source,
                     String8 *mimeType,
                     float *confidence,
                     sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
                 if (SniffFLAC(source, mimeType, confidence, meta)) {
                     return [](
-                            const sp<DataSource> &source,
+                            DataSourceBase *source,
                             const sp<AMessage>& meta __unused) -> MediaExtractor* {
                         return new FLACExtractor(source);};
                 }
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 2e7ee3b..ef07212 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -17,7 +17,7 @@
 #ifndef FLAC_EXTRACTOR_H_
 #define FLAC_EXTRACTOR_H_
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaExtractor.h>
 #include <utils/String8.h>
 
@@ -28,8 +28,7 @@
 class FLACExtractor : public MediaExtractor {
 
 public:
-    // Extractor assumes ownership of source
-    explicit FLACExtractor(const sp<DataSource> &source);
+    explicit FLACExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -42,7 +41,7 @@
     virtual ~FLACExtractor();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<FLACParser> mParser;
     status_t mInitCheck;
     sp<MetaData> mFileMetadata;
@@ -57,7 +56,7 @@
 
 };
 
-bool SniffFLAC(const sp<DataSource> &source, String8 *mimeType,
+bool SniffFLAC(DataSourceBase *source, String8 *mimeType,
         float *confidence, sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 18b1d23..711c6a5 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -141,7 +141,7 @@
 
 // MidiEngine
 
-MidiEngine::MidiEngine(const sp<DataSource> &dataSource,
+MidiEngine::MidiEngine(DataSourceBase *dataSource,
         const sp<MetaData> &fileMetadata,
         const sp<MetaData> &trackMetadata) :
             mGroup(NULL),
@@ -261,7 +261,7 @@
 // MidiExtractor
 
 MidiExtractor::MidiExtractor(
-        const sp<DataSource> &dataSource)
+        DataSourceBase *dataSource)
     : mDataSource(dataSource),
       mInitCheck(false)
 {
@@ -308,7 +308,7 @@
 // Sniffer
 
 bool SniffMidi(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *)
 {
     sp<MidiEngine> p = new MidiEngine(source, NULL, NULL);
@@ -333,13 +333,13 @@
         1,
         "MIDI Extractor",
         [](
-                const sp<DataSource> &source,
+                DataSourceBase *source,
                 String8 *mimeType,
                 float *confidence,
                 sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
             if (SniffMidi(source, mimeType, confidence, meta)) {
                 return [](
-                        const sp<DataSource> &source,
+                        DataSourceBase *source,
                         const sp<AMessage>& meta __unused) -> MediaExtractor* {
                     return new MidiExtractor(source);};
             }
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 87e4654..91efd06 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -17,7 +17,7 @@
 #ifndef MIDI_EXTRACTOR_H_
 #define MIDI_EXTRACTOR_H_
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaExtractor.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -29,7 +29,7 @@
 
 class MidiEngine : public RefBase {
 public:
-    MidiEngine(const sp<DataSource> &dataSource,
+    MidiEngine(DataSourceBase *dataSource,
             const sp<MetaData> &fileMetadata,
             const sp<MetaData> &trackMetadata);
     ~MidiEngine();
@@ -52,8 +52,7 @@
 class MidiExtractor : public MediaExtractor {
 
 public:
-    // Extractor assumes ownership of source
-    explicit MidiExtractor(const sp<DataSource> &source);
+    explicit MidiExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -66,7 +65,7 @@
     virtual ~MidiExtractor();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     status_t mInitCheck;
     sp<MetaData> mFileMetadata;
 
@@ -88,7 +87,7 @@
 
 };
 
-bool SniffMidi(const sp<DataSource> &source, String8 *mimeType,
+bool SniffMidi(DataSourceBase *source, String8 *mimeType,
         float *confidence, sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 6df0012..f61f7c7 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -21,7 +21,7 @@
 #include "FLACDecoder.h"
 #include "MatroskaExtractor.h"
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AUtils.h>
@@ -40,8 +40,8 @@
 
 namespace android {
 
-struct DataSourceReader : public mkvparser::IMkvReader {
-    explicit DataSourceReader(const sp<DataSource> &source)
+struct DataSourceBaseReader : public mkvparser::IMkvReader {
+    explicit DataSourceBaseReader(DataSourceBase *source)
         : mSource(source) {
     }
 
@@ -83,10 +83,10 @@
     }
 
 private:
-    sp<DataSource> mSource;
+    DataSourceBase *mSource;
 
-    DataSourceReader(const DataSourceReader &);
-    DataSourceReader &operator=(const DataSourceReader &);
+    DataSourceBaseReader(const DataSourceBaseReader &);
+    DataSourceBaseReader &operator=(const DataSourceBaseReader &);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -852,9 +852,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-MatroskaExtractor::MatroskaExtractor(const sp<DataSource> &source)
+MatroskaExtractor::MatroskaExtractor(DataSourceBase *source)
     : mDataSource(source),
-      mReader(new DataSourceReader(mDataSource)),
+      mReader(new DataSourceBaseReader(mDataSource)),
       mSegment(NULL),
       mExtractedThumbnails(false),
       mIsWebm(false),
@@ -862,8 +862,8 @@
     off64_t size;
     mIsLiveStreaming =
         (mDataSource->flags()
-            & (DataSource::kWantsPrefetching
-                | DataSource::kIsCachingDataSource))
+            & (DataSourceBase::kWantsPrefetching
+                | DataSourceBase::kIsCachingDataSource))
         && mDataSource->getSize(&size) != OK;
 
     mkvparser::EBMLHeader ebmlHeader;
@@ -1548,9 +1548,9 @@
 }
 
 bool SniffMatroska(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *) {
-    DataSourceReader reader(source);
+    DataSourceBaseReader reader(source);
     mkvparser::EBMLHeader ebmlHeader;
     long long pos;
     if (ebmlHeader.Parse(&reader, pos) < 0) {
@@ -1574,13 +1574,13 @@
         1,
         "Matroska Extractor",
         [](
-                const sp<DataSource> &source,
+                DataSourceBase *source,
                 String8 *mimeType,
                 float *confidence,
                 sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
             if (SniffMatroska(source, mimeType, confidence, meta)) {
                 return [](
-                        const sp<DataSource> &source,
+                        DataSourceBase *source,
                         const sp<AMessage>& meta __unused) -> MediaExtractor* {
                     return new MatroskaExtractor(source);};
             }
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 54419bf..095452b 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -30,11 +30,11 @@
 class String8;
 
 class MetaData;
-struct DataSourceReader;
+struct DataSourceBaseReader;
 struct MatroskaSource;
 
 struct MatroskaExtractor : public MediaExtractor {
-    explicit MatroskaExtractor(const sp<DataSource> &source);
+    explicit MatroskaExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
 
@@ -76,8 +76,8 @@
     Mutex mLock;
     Vector<TrackInfo> mTracks;
 
-    sp<DataSource> mDataSource;
-    DataSourceReader *mReader;
+    DataSourceBase *mDataSource;
+    DataSourceBaseReader *mReader;
     mkvparser::Segment *mSegment;
     bool mExtractedThumbnails;
     bool mIsLiveStreaming;
@@ -96,7 +96,7 @@
 };
 
 bool SniffMatroska(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index 7e27fd8..25d4deb 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -24,7 +24,7 @@
 #include "VBRISeeker.h"
 #include "XINGSeeker.h"
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -46,7 +46,7 @@
 static const uint32_t kMask = 0xfffe0c00;
 
 static bool Resync(
-        const sp<DataSource> &source, uint32_t match_header,
+        DataSourceBase *source, uint32_t match_header,
         off64_t *inout_pos, off64_t *post_id3_pos, uint32_t *out_header) {
     if (post_id3_pos != NULL) {
         *post_id3_pos = 0;
@@ -212,7 +212,7 @@
 class MP3Source : public MediaSourceBase {
 public:
     MP3Source(
-            const sp<MetaData> &meta, const sp<DataSource> &source,
+            const sp<MetaData> &meta, DataSourceBase *source,
             off64_t first_frame_pos, uint32_t fixed_header,
             const sp<MP3Seeker> &seeker);
 
@@ -230,7 +230,7 @@
 private:
     static const size_t kMaxFrameSize;
     sp<MetaData> mMeta;
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     off64_t mFirstFramePos;
     uint32_t mFixedHeader;
     off64_t mCurrentPos;
@@ -247,7 +247,7 @@
 };
 
 MP3Extractor::MP3Extractor(
-        const sp<DataSource> &source, const sp<AMessage> &meta)
+        DataSourceBase *source, const sp<AMessage> &meta)
     : mInitCheck(NO_INIT),
       mDataSource(source),
       mFirstFramePos(-1),
@@ -436,7 +436,7 @@
 // Set our max frame size to the nearest power of 2 above this size (aka, 4kB)
 const size_t MP3Source::kMaxFrameSize = (1 << 12); /* 4096 bytes */
 MP3Source::MP3Source(
-        const sp<MetaData> &meta, const sp<DataSource> &source,
+        const sp<MetaData> &meta, DataSourceBase *source,
         off64_t first_frame_pos, uint32_t fixed_header,
         const sp<MP3Seeker> &seeker)
     : mMeta(meta),
@@ -667,13 +667,13 @@
 }
 
 static MediaExtractor* CreateExtractor(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         const sp<AMessage>& meta) {
     return new MP3Extractor(source, meta);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        const sp<DataSource> &source, String8 *mimeType,
+        DataSourceBase *source, String8 *mimeType,
         float *confidence, sp<AMessage> *meta) {
     off64_t pos = 0;
     off64_t post_id3_pos;
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 3b3387d..6257112 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -24,14 +24,13 @@
 namespace android {
 
 struct AMessage;
-class DataSource;
+class DataSourceBase;
 struct MP3Seeker;
 class String8;
 
 class MP3Extractor : public MediaExtractor {
 public:
-    // Extractor assumes ownership of "source".
-    MP3Extractor(const sp<DataSource> &source, const sp<AMessage> &meta);
+    MP3Extractor(DataSourceBase *source, const sp<AMessage> &meta);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -43,7 +42,7 @@
 private:
     status_t mInitCheck;
 
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     off64_t mFirstFramePos;
     sp<MetaData> mMeta;
     uint32_t mFixedHeader;
@@ -54,7 +53,7 @@
 };
 
 bool SniffMP3(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *meta);
 
 }  // namespace android
diff --git a/media/extractors/mp3/VBRISeeker.cpp b/media/extractors/mp3/VBRISeeker.cpp
index e7db6fd..51c5d1f 100644
--- a/media/extractors/mp3/VBRISeeker.cpp
+++ b/media/extractors/mp3/VBRISeeker.cpp
@@ -27,7 +27,7 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 
 namespace android {
 
@@ -37,7 +37,7 @@
 
 // static
 sp<VBRISeeker> VBRISeeker::CreateFromSource(
-        const sp<DataSource> &source, off64_t post_id3_pos) {
+        DataSourceBase *source, off64_t post_id3_pos) {
     off64_t pos = post_id3_pos;
 
     uint8_t header[4];
diff --git a/media/extractors/mp3/VBRISeeker.h b/media/extractors/mp3/VBRISeeker.h
index 87258b0..e46af36 100644
--- a/media/extractors/mp3/VBRISeeker.h
+++ b/media/extractors/mp3/VBRISeeker.h
@@ -24,11 +24,11 @@
 
 namespace android {
 
-class DataSource;
+class DataSourceBase;
 
 struct VBRISeeker : public MP3Seeker {
     static sp<VBRISeeker> CreateFromSource(
-            const sp<DataSource> &source, off64_t post_id3_pos);
+            DataSourceBase *source, off64_t post_id3_pos);
 
     virtual bool getDuration(int64_t *durationUs);
     virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
diff --git a/media/extractors/mp3/XINGSeeker.cpp b/media/extractors/mp3/XINGSeeker.cpp
index fa59701..adfa8d2 100644
--- a/media/extractors/mp3/XINGSeeker.cpp
+++ b/media/extractors/mp3/XINGSeeker.cpp
@@ -21,7 +21,7 @@
 #include <media/stagefright/foundation/avc_utils.h>
 
 #include <media/stagefright/foundation/ByteUtils.h>
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 
 namespace android {
 
@@ -77,7 +77,7 @@
 
 // static
 sp<XINGSeeker> XINGSeeker::CreateFromSource(
-        const sp<DataSource> &source, off64_t first_frame_pos) {
+        DataSourceBase *source, off64_t first_frame_pos) {
     sp<XINGSeeker> seeker = new XINGSeeker;
 
     seeker->mFirstFramePos = first_frame_pos;
diff --git a/media/extractors/mp3/XINGSeeker.h b/media/extractors/mp3/XINGSeeker.h
index 37077c4..db847bc 100644
--- a/media/extractors/mp3/XINGSeeker.h
+++ b/media/extractors/mp3/XINGSeeker.h
@@ -22,11 +22,11 @@
 
 namespace android {
 
-class DataSource;
+class DataSourceBase;
 
 struct XINGSeeker : public MP3Seeker {
     static sp<XINGSeeker> CreateFromSource(
-            const sp<DataSource> &source, off64_t first_frame_pos);
+            DataSourceBase *source, off64_t first_frame_pos);
 
     virtual bool getDuration(int64_t *durationUs);
     virtual bool getOffsetForTime(int64_t *timeUs, off64_t *pos);
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 85c66b2..cef5f4a 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "ItemTable"
 
 #include <ItemTable.h>
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -87,7 +87,7 @@
 
 struct Box {
 protected:
-    Box(const sp<DataSource> source, uint32_t type) :
+    Box(DataSourceBase *source, uint32_t type) :
         mDataSource(source), mType(type) {}
 
     virtual ~Box() {}
@@ -99,14 +99,14 @@
 
     inline uint32_t type() const { return mType; }
 
-    inline sp<DataSource> source() const { return mDataSource; }
+    inline DataSourceBase *source() const { return mDataSource; }
 
     status_t parseChunk(off64_t *offset);
 
     status_t parseChunks(off64_t offset, size_t size);
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     uint32_t mType;
 };
 
@@ -181,7 +181,7 @@
 
 struct FullBox : public Box {
 protected:
-    FullBox(const sp<DataSource> source, uint32_t type) :
+    FullBox(DataSourceBase *source, uint32_t type) :
         Box(source, type), mVersion(0), mFlags(0) {}
 
     inline uint8_t version() const { return mVersion; }
@@ -216,7 +216,7 @@
 //
 
 struct PitmBox : public FullBox {
-    PitmBox(const sp<DataSource> source) :
+    PitmBox(DataSourceBase *source) :
         FullBox(source, FOURCC('p', 'i', 't', 'm')) {}
 
     status_t parse(off64_t offset, size_t size, uint32_t *primaryItemId);
@@ -296,7 +296,7 @@
 };
 
 struct IlocBox : public FullBox {
-    IlocBox(const sp<DataSource> source, KeyedVector<uint32_t, ItemLoc> *itemLocs) :
+    IlocBox(DataSourceBase *source, KeyedVector<uint32_t, ItemLoc> *itemLocs) :
         FullBox(source, FOURCC('i', 'l', 'o', 'c')),
         mItemLocs(itemLocs), mHasConstructMethod1(false) {}
 
@@ -466,7 +466,7 @@
 //
 
 struct ItemReference : public Box, public RefBase {
-    ItemReference(const sp<DataSource> source, uint32_t type, uint32_t itemIdSize) :
+    ItemReference(DataSourceBase *source, uint32_t type, uint32_t itemIdSize) :
         Box(source, type), mItemId(0), mRefIdSize(itemIdSize) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -575,7 +575,7 @@
 }
 
 struct IrefBox : public FullBox {
-    IrefBox(const sp<DataSource> source, Vector<sp<ItemReference> > *itemRefs) :
+    IrefBox(DataSourceBase *source, Vector<sp<ItemReference> > *itemRefs) :
         FullBox(source, FOURCC('i', 'r', 'e', 'f')), mRefIdSize(0), mItemRefs(itemRefs) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -637,7 +637,7 @@
 };
 
 struct IspeBox : public FullBox, public ItemProperty {
-    IspeBox(const sp<DataSource> source) :
+    IspeBox(DataSourceBase *source) :
         FullBox(source, FOURCC('i', 's', 'p', 'e')), mWidth(0), mHeight(0) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -673,7 +673,7 @@
 }
 
 struct HvccBox : public Box, public ItemProperty {
-    HvccBox(const sp<DataSource> source) :
+    HvccBox(DataSourceBase *source) :
         Box(source, FOURCC('h', 'v', 'c', 'C')) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -706,7 +706,7 @@
 }
 
 struct IrotBox : public Box, public ItemProperty {
-    IrotBox(const sp<DataSource> source) :
+    IrotBox(DataSourceBase *source) :
         Box(source, FOURCC('i', 'r', 'o', 't')), mAngle(0) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -735,7 +735,7 @@
 }
 
 struct ColrBox : public Box, public ItemProperty {
-    ColrBox(const sp<DataSource> source) :
+    ColrBox(DataSourceBase *source) :
         Box(source, FOURCC('c', 'o', 'l', 'r')) {}
 
     status_t parse(off64_t offset, size_t size) override;
@@ -783,7 +783,7 @@
 }
 
 struct IpmaBox : public FullBox {
-    IpmaBox(const sp<DataSource> source, Vector<AssociationEntry> *associations) :
+    IpmaBox(DataSourceBase *source, Vector<AssociationEntry> *associations) :
         FullBox(source, FOURCC('i', 'p', 'm', 'a')), mAssociations(associations) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -857,7 +857,7 @@
 }
 
 struct IpcoBox : public Box {
-    IpcoBox(const sp<DataSource> source, Vector<sp<ItemProperty> > *properties) :
+    IpcoBox(DataSourceBase *source, Vector<sp<ItemProperty> > *properties) :
         Box(source, FOURCC('i', 'p', 'c', 'o')), mItemProperties(properties) {}
 
     status_t parse(off64_t offset, size_t size);
@@ -914,7 +914,7 @@
 }
 
 struct IprpBox : public Box {
-    IprpBox(const sp<DataSource> source,
+    IprpBox(DataSourceBase *source,
             Vector<sp<ItemProperty> > *properties,
             Vector<AssociationEntry> *associations) :
         Box(source, FOURCC('i', 'p', 'r', 'p')),
@@ -971,7 +971,7 @@
 };
 
 struct InfeBox : public FullBox {
-    InfeBox(const sp<DataSource> source) :
+    InfeBox(DataSourceBase *source) :
         FullBox(source, FOURCC('i', 'n', 'f', 'e')) {}
 
     status_t parse(off64_t offset, size_t size, ItemInfo *itemInfo);
@@ -1075,7 +1075,7 @@
 }
 
 struct IinfBox : public FullBox {
-    IinfBox(const sp<DataSource> source, Vector<ItemInfo> *itemInfos) :
+    IinfBox(DataSourceBase *source, Vector<ItemInfo> *itemInfos) :
         FullBox(source, FOURCC('i', 'i', 'n', 'f')),
         mItemInfos(itemInfos), mHasGrids(false) {}
 
@@ -1144,7 +1144,7 @@
 
 //////////////////////////////////////////////////////////////////
 
-ItemTable::ItemTable(const sp<DataSource> &source)
+ItemTable::ItemTable(DataSourceBase *source)
     : mDataSource(source),
       mPrimaryItemId(0),
       mIdatOffset(0),
diff --git a/media/extractors/mp4/ItemTable.h b/media/extractors/mp4/ItemTable.h
index 3d2e2ae..f4a69cc 100644
--- a/media/extractors/mp4/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -25,7 +25,7 @@
 
 namespace android {
 
-class DataSource;
+class DataSourceBase;
 class MetaData;
 
 namespace heif {
@@ -44,7 +44,7 @@
 
 class ItemTable : public RefBase {
 public:
-    explicit ItemTable(const sp<DataSource> &source);
+    explicit ItemTable(DataSourceBase *source);
 
     status_t parse(uint32_t type, off64_t offset, size_t size);
 
@@ -60,7 +60,7 @@
     ~ItemTable();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
 
     KeyedVector<uint32_t, ItemLoc> mItemLocs;
     Vector<ItemInfo> mItemInfos;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 9f21db6..30dda13 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -69,7 +69,7 @@
 public:
     // Caller retains ownership of both "dataSource" and "sampleTable".
     MPEG4Source(const sp<MetaData> &format,
-                const sp<DataSource> &dataSource,
+                DataSourceBase *dataSource,
                 int32_t timeScale,
                 const sp<SampleTable> &sampleTable,
                 Vector<SidxEntry> &sidx,
@@ -93,7 +93,7 @@
     Mutex mLock;
 
     sp<MetaData> mFormat;
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     int32_t mTimescale;
     sp<SampleTable> mSampleTable;
     uint32_t mCurrentSampleIndex;
@@ -186,47 +186,51 @@
 // all remaining requests to the wrapped datasource.
 // This is used to cache the full sampletable metadata for a single track,
 // possibly wrapping multiple times to cover all tracks, i.e.
-// Each MPEG4DataSource caches the sampletable metadata for a single track.
+// Each CachedRangedDataSource caches the sampletable metadata for a single track.
 
-struct MPEG4DataSource : public DataSource {
-    explicit MPEG4DataSource(const sp<DataSource> &source);
+struct CachedRangedDataSource : public DataSourceBase {
+    explicit CachedRangedDataSource(DataSourceBase *source);
+    virtual ~CachedRangedDataSource();
 
     virtual status_t initCheck() const;
     virtual ssize_t readAt(off64_t offset, void *data, size_t size);
     virtual status_t getSize(off64_t *size);
     virtual uint32_t flags();
 
-    status_t setCachedRange(off64_t offset, size_t size);
+    status_t setCachedRange(off64_t offset, size_t size, bool assumeSourceOwnershipOnSuccess);
 
-protected:
-    virtual ~MPEG4DataSource();
 
 private:
     Mutex mLock;
 
-    sp<DataSource> mSource;
+    DataSourceBase *mSource;
+    bool mOwnsDataSource;
     off64_t mCachedOffset;
     size_t mCachedSize;
     uint8_t *mCache;
 
     void clearCache();
 
-    MPEG4DataSource(const MPEG4DataSource &);
-    MPEG4DataSource &operator=(const MPEG4DataSource &);
+    CachedRangedDataSource(const CachedRangedDataSource &);
+    CachedRangedDataSource &operator=(const CachedRangedDataSource &);
 };
 
-MPEG4DataSource::MPEG4DataSource(const sp<DataSource> &source)
+CachedRangedDataSource::CachedRangedDataSource(DataSourceBase *source)
     : mSource(source),
+      mOwnsDataSource(false),
       mCachedOffset(0),
       mCachedSize(0),
       mCache(NULL) {
 }
 
-MPEG4DataSource::~MPEG4DataSource() {
+CachedRangedDataSource::~CachedRangedDataSource() {
     clearCache();
+    if (mOwnsDataSource) {
+        delete (CachedRangedDataSource*)mSource;
+    }
 }
 
-void MPEG4DataSource::clearCache() {
+void CachedRangedDataSource::clearCache() {
     if (mCache) {
         free(mCache);
         mCache = NULL;
@@ -236,11 +240,11 @@
     mCachedSize = 0;
 }
 
-status_t MPEG4DataSource::initCheck() const {
+status_t CachedRangedDataSource::initCheck() const {
     return mSource->initCheck();
 }
 
-ssize_t MPEG4DataSource::readAt(off64_t offset, void *data, size_t size) {
+ssize_t CachedRangedDataSource::readAt(off64_t offset, void *data, size_t size) {
     Mutex::Autolock autoLock(mLock);
 
     if (isInRange(mCachedOffset, mCachedSize, offset, size)) {
@@ -251,15 +255,17 @@
     return mSource->readAt(offset, data, size);
 }
 
-status_t MPEG4DataSource::getSize(off64_t *size) {
+status_t CachedRangedDataSource::getSize(off64_t *size) {
     return mSource->getSize(size);
 }
 
-uint32_t MPEG4DataSource::flags() {
+uint32_t CachedRangedDataSource::flags() {
     return mSource->flags();
 }
 
-status_t MPEG4DataSource::setCachedRange(off64_t offset, size_t size) {
+status_t CachedRangedDataSource::setCachedRange(off64_t offset,
+        size_t size,
+        bool assumeSourceOwnershipOnSuccess) {
     Mutex::Autolock autoLock(mLock);
 
     clearCache();
@@ -280,7 +286,7 @@
 
         return ERROR_IO;
     }
-
+    mOwnsDataSource = assumeSourceOwnershipOnSuccess;
     return OK;
 }
 
@@ -334,11 +340,12 @@
     return false;
 }
 
-MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source, const char *mime)
+MPEG4Extractor::MPEG4Extractor(DataSourceBase *source, const char *mime)
     : mMoofOffset(0),
       mMoofFound(false),
       mMdatFound(false),
       mDataSource(source),
+      mCachedSource(NULL),
       mInitCheck(NO_INIT),
       mHeaderTimescale(0),
       mIsQT(false),
@@ -354,10 +361,6 @@
 }
 
 MPEG4Extractor::~MPEG4Extractor() {
-    release();
-}
-
-void MPEG4Extractor::release() {
     Track *track = mFirstTrack;
     while (track) {
         Track *next = track->next;
@@ -381,10 +384,7 @@
     }
     mPssh.clear();
 
-    if (mDataSource != NULL) {
-        mDataSource->close();
-        mDataSource.clear();
-    }
+    delete mCachedSource;
 }
 
 uint32_t MPEG4Extractor::flags() const {
@@ -692,14 +692,14 @@
 
 // Reads an encoded integer 7 bits at a time until it encounters the high bit clear.
 static int32_t readSize(off64_t offset,
-        const sp<DataSource> &DataSource, uint8_t *numOfBytes) {
+        DataSourceBase *DataSourceBase, uint8_t *numOfBytes) {
     uint32_t size = 0;
     uint8_t data;
     bool moreData = true;
     *numOfBytes = 0;
 
     while (moreData) {
-        if (DataSource->readAt(offset, &data, 1) < 1) {
+        if (DataSourceBase->readAt(offset, &data, 1) < 1) {
             return -1;
         }
         offset ++;
@@ -1045,13 +1045,17 @@
                 ALOGV("sampleTable chunk is %" PRIu64 " bytes long.", chunk_size);
 
                 if (mDataSource->flags()
-                        & (DataSource::kWantsPrefetching
-                            | DataSource::kIsCachingDataSource)) {
-                    sp<MPEG4DataSource> cachedSource =
-                        new MPEG4DataSource(mDataSource);
+                        & (DataSourceBase::kWantsPrefetching
+                            | DataSourceBase::kIsCachingDataSource)) {
+                    CachedRangedDataSource *cachedSource =
+                        new CachedRangedDataSource(mDataSource);
 
-                    if (cachedSource->setCachedRange(*offset, chunk_size) == OK) {
-                        mDataSource = cachedSource;
+                    if (cachedSource->setCachedRange(
+                            *offset, chunk_size,
+                            mCachedSource != NULL /* assume ownership on success */) == OK) {
+                        mDataSource = mCachedSource = cachedSource;
+                    } else {
+                        delete cachedSource;
                     }
                 }
 
@@ -3890,7 +3894,7 @@
 
 MPEG4Source::MPEG4Source(
         const sp<MetaData> &format,
-        const sp<DataSource> &dataSource,
+        DataSourceBase *dataSource,
         int32_t timeScale,
         const sp<SampleTable> &sampleTable,
         Vector<SidxEntry> &sidx,
@@ -5379,7 +5383,7 @@
 }
 
 static bool LegacySniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+        DataSourceBase *source, String8 *mimeType, float *confidence) {
     uint8_t header[8];
 
     ssize_t n = source->readAt(4, header, sizeof(header));
@@ -5446,7 +5450,7 @@
 // (end of the 'moov' atom) and report it to the caller as part of
 // the metadata.
 static bool BetterSniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *meta) {
     // We scan up to 128 bytes to identify this file as an MP4.
     static const off64_t kMaxScanOffset = 128ll;
@@ -5563,13 +5567,13 @@
 }
 
 static MediaExtractor* CreateExtractor(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         const sp<AMessage>& meta __unused) {
     return new MPEG4Extractor(source);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         String8 *mimeType,
         float *confidence,
         sp<AMessage> *meta) {
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index e947b87..644c430 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -20,7 +20,7 @@
 
 #include <arpa/inet.h>
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaExtractor.h>
 #include <media/stagefright/foundation/AString.h>
 #include <utils/List.h>
@@ -29,7 +29,8 @@
 
 namespace android {
 struct AMessage;
-class DataSource;
+class DataSourceBase;
+struct CachedRangedDataSource;
 class SampleTable;
 class String8;
 namespace heif {
@@ -52,8 +53,7 @@
 
 class MPEG4Extractor : public MediaExtractor {
 public:
-    // Extractor assumes ownership of "source".
-    explicit MPEG4Extractor(const sp<DataSource> &source, const char *mime = NULL);
+    explicit MPEG4Extractor(DataSourceBase *source, const char *mime = NULL);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -62,7 +62,6 @@
     virtual sp<MetaData> getMetaData();
     virtual uint32_t flags() const;
     virtual const char * name() { return "MPEG4Extractor"; }
-    virtual void release();
 
     // for DRM
     virtual char* getDrmTrackInfo(size_t trackID, int *len);
@@ -98,7 +97,8 @@
 
     Vector<Trex> mTrex;
 
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
+    CachedRangedDataSource *mCachedSource;
     status_t mInitCheck;
     uint32_t mHeaderTimescale;
     bool mIsQT;
@@ -160,7 +160,7 @@
 };
 
 bool SniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index c194397..93ee7c6 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -22,7 +22,7 @@
 
 #include <arpa/inet.h>
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 378d63a..81c353e 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -25,7 +25,7 @@
 
 #include <arpa/inet.h>
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 
@@ -114,7 +114,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-SampleTable::SampleTable(const sp<DataSource> &source)
+SampleTable::SampleTable(DataSourceBase *source)
     : mDataSource(source),
       mChunkOffsetOffset(-1),
       mChunkOffsetType(0),
diff --git a/media/extractors/mp4/SampleTable.h b/media/extractors/mp4/SampleTable.h
index 466e26b..e4e974b 100644
--- a/media/extractors/mp4/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -27,12 +27,12 @@
 
 namespace android {
 
-class DataSource;
+class DataSourceBase;
 struct SampleIterator;
 
 class SampleTable : public RefBase {
 public:
-    explicit SampleTable(const sp<DataSource> &source);
+    explicit SampleTable(DataSourceBase *source);
 
     bool isValid() const;
 
@@ -99,7 +99,7 @@
     // Limit the total size of all internal tables to 200MiB.
     static const size_t kMaxTotalSize = 200 * (1 << 20);
 
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     Mutex mLock;
 
     off64_t mChunkOffsetOffset;
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index d5682e9..443d685 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -34,18 +34,18 @@
         1,
         "MPEG2-PS/TS Extractor",
         [](
-                const sp<DataSource> &source,
+                DataSourceBase *source,
                 String8 *mimeType,
                 float *confidence,
                 sp<AMessage> *meta __unused) -> MediaExtractor::CreatorFunc {
             if (SniffMPEG2TS(source, mimeType, confidence, meta)) {
                 return [](
-                        const sp<DataSource> &source,
+                        DataSourceBase *source,
                         const sp<AMessage>& meta __unused) -> MediaExtractor* {
                     return new MPEG2TSExtractor(source);};
             } else if (SniffMPEG2PS(source, mimeType, confidence, meta)) {
                         return [](
-                                const sp<DataSource> &source,
+                                DataSourceBase *source,
                                 const sp<AMessage>& meta __unused) -> MediaExtractor* {
                             return new MPEG2PSExtractor(source);};
             }
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 0978387..697e44f 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -23,7 +23,7 @@
 #include "mpeg2ts/AnotherPacketSource.h"
 #include "mpeg2ts/ESQueue.h"
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -94,7 +94,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-MPEG2PSExtractor::MPEG2PSExtractor(const sp<DataSource> &source)
+MPEG2PSExtractor::MPEG2PSExtractor(DataSourceBase *source)
     : mDataSource(source),
       mOffset(0),
       mFinalResult(OK),
@@ -751,7 +751,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffMPEG2PS(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *) {
     uint8_t header[5];
     if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
index f8a97ef..adf719a 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -31,7 +31,7 @@
 class String8;
 
 struct MPEG2PSExtractor : public MediaExtractor {
-    explicit MPEG2PSExtractor(const sp<DataSource> &source);
+    explicit MPEG2PSExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -50,7 +50,7 @@
     struct WrappedTrack;
 
     mutable Mutex mLock;
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
 
     off64_t mOffset;
     status_t mFinalResult;
@@ -72,7 +72,7 @@
 };
 
 bool SniffMPEG2PS(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index b24e8db..6d0b1cc 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -22,7 +22,7 @@
 
 #include "MPEG2TSExtractor.h"
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/IStreamSource.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -121,7 +121,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source)
+MPEG2TSExtractor::MPEG2TSExtractor(DataSourceBase *source)
     : mDataSource(source),
       mParser(new ATSParser),
       mLastSyncEvent(0),
@@ -367,7 +367,7 @@
 }
 
 status_t MPEG2TSExtractor::estimateDurationsFromTimesUsAtEnd()  {
-    if (!(mDataSource->flags() & DataSource::kIsLocalFileSource)) {
+    if (!(mDataSource->flags() & DataSourceBase::kIsLocalFileSource)) {
         return ERROR_UNSUPPORTED;
     }
 
@@ -646,7 +646,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool SniffMPEG2TS(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *) {
     for (int i = 0; i < 5; ++i) {
         char header;
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index 362f016..57cb675 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -32,12 +32,12 @@
 struct AMessage;
 struct AnotherPacketSource;
 struct ATSParser;
-class DataSource;
+class DataSourceBase;
 struct MPEG2TSSource;
 class String8;
 
 struct MPEG2TSExtractor : public MediaExtractor {
-    explicit MPEG2TSExtractor(const sp<DataSource> &source);
+    explicit MPEG2TSExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -55,7 +55,7 @@
 
     mutable Mutex mLock;
 
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
 
     sp<ATSParser> mParser;
 
@@ -79,9 +79,9 @@
     // Try to feed more data from source to parser.
     // |isInit| means this function is called inside init(). This is a signal to
     // save SyncEvent so that init() can add SyncPoint after it updates |mSourceImpls|.
-    // This function returns OK if expected amount of data is fed from DataSource to
+    // This function returns OK if expected amount of data is fed from DataSourceBase to
     // parser and is successfully parsed. Otherwise, various error codes could be
-    // returned, e.g., ERROR_END_OF_STREAM, or no data availalbe from DataSource, or
+    // returned, e.g., ERROR_END_OF_STREAM, or no data availalbe from DataSourceBase, or
     // the data has syntax error during parsing, etc.
     status_t feedMore(bool isInit = false);
     status_t seek(int64_t seekTimeUs,
@@ -100,7 +100,7 @@
 };
 
 bool SniffMPEG2TS(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index f62ec47..1d04bed 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -21,7 +21,7 @@
 #include "OggExtractor.h"
 
 #include <cutils/properties.h>
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -69,7 +69,7 @@
 
 struct MyOggExtractor {
     MyOggExtractor(
-            const sp<DataSource> &source,
+            DataSourceBase *source,
             const char *mimeType,
             size_t numHeaders,
             int64_t seekPreRollUs);
@@ -105,7 +105,7 @@
         int64_t mTimeUs;
     };
 
-    sp<DataSource> mSource;
+    DataSourceBase *mSource;
     off64_t mOffset;
     Page mCurrentPage;
     uint64_t mCurGranulePosition;
@@ -164,7 +164,7 @@
 };
 
 struct MyVorbisExtractor : public MyOggExtractor {
-    explicit MyVorbisExtractor(const sp<DataSource> &source)
+    explicit MyVorbisExtractor(DataSourceBase *source)
         : MyOggExtractor(source,
                 MEDIA_MIMETYPE_AUDIO_VORBIS,
                 /* numHeaders */ 3,
@@ -192,7 +192,7 @@
     static const int32_t kOpusSampleRate = 48000;
     static const int64_t kOpusSeekPreRollUs = 80000; // 80 ms
 
-    explicit MyOpusExtractor(const sp<DataSource> &source)
+    explicit MyOpusExtractor(DataSourceBase *source)
         : MyOggExtractor(source, MEDIA_MIMETYPE_AUDIO_OPUS, /*numHeaders*/ 2, kOpusSeekPreRollUs),
           mChannelCount(0),
           mCodecDelay(0),
@@ -294,7 +294,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 MyOggExtractor::MyOggExtractor(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         const char *mimeType,
         size_t numHeaders,
         int64_t seekPreRollUs)
@@ -852,7 +852,7 @@
 
     off64_t size;
     uint64_t lastGranulePosition;
-    if (!(mSource->flags() & DataSource::kIsCachingDataSource)
+    if (!(mSource->flags() & DataSourceBase::kIsCachingDataSource)
             && mSource->getSize(&size) == OK
             && findPrevGranulePosition(size, &lastGranulePosition) == OK) {
         // Let's assume it's cheap to seek to the end.
@@ -1315,7 +1315,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-OggExtractor::OggExtractor(const sp<DataSource> &source)
+OggExtractor::OggExtractor(DataSourceBase *source)
     : mDataSource(source),
       mInitCheck(NO_INIT),
       mImpl(NULL) {
@@ -1370,13 +1370,13 @@
 }
 
 static MediaExtractor* CreateExtractor(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         const sp<AMessage>& meta __unused) {
     return new OggExtractor(source);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         String8 *mimeType,
         float *confidence,
         sp<AMessage> *) {
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index 126428c..c9c37eb 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -24,14 +24,14 @@
 namespace android {
 
 struct AMessage;
-class DataSource;
+class DataSourceBase;
 class String8;
 
 struct MyOggExtractor;
 struct OggSource;
 
 struct OggExtractor : public MediaExtractor {
-    explicit OggExtractor(const sp<DataSource> &source);
+    explicit OggExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -46,7 +46,7 @@
 private:
     friend struct OggSource;
 
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     status_t mInitCheck;
 
     MyOggExtractor *mImpl;
@@ -56,7 +56,7 @@
 };
 
 bool SniffOgg(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        DataSourceBase *source, String8 *mimeType, float *confidence,
         sp<AMessage> *);
 
 }  // namespace android
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index cf22c66..105a37f 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -21,7 +21,7 @@
 #include "WAVExtractor.h"
 
 #include <audio_utils/primitives.h>
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/MediaSourceBase.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -57,7 +57,7 @@
 
 struct WAVSource : public MediaSourceBase {
     WAVSource(
-            const sp<DataSource> &dataSource,
+            DataSourceBase *dataSource,
             const sp<MetaData> &meta,
             uint16_t waveFormat,
             int32_t bitsPerSample,
@@ -78,7 +78,7 @@
 private:
     static const size_t kMaxFrameSize;
 
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     sp<MetaData> mMeta;
     uint16_t mWaveFormat;
     int32_t mSampleRate;
@@ -94,7 +94,7 @@
     WAVSource &operator=(const WAVSource &);
 };
 
-WAVExtractor::WAVExtractor(const sp<DataSource> &source)
+WAVExtractor::WAVExtractor(DataSourceBase *source)
     : mDataSource(source),
       mValidFormat(false),
       mChannelMask(CHANNEL_MASK_USE_CHANNEL_ORDER) {
@@ -348,7 +348,7 @@
 const size_t WAVSource::kMaxFrameSize = 32768;
 
 WAVSource::WAVSource(
-        const sp<DataSource> &dataSource,
+        DataSourceBase *dataSource,
         const sp<MetaData> &meta,
         uint16_t waveFormat,
         int32_t bitsPerSample,
@@ -545,13 +545,13 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 static MediaExtractor* CreateExtractor(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         const sp<AMessage>& meta __unused) {
     return new WAVExtractor(source);
 }
 
 static MediaExtractor::CreatorFunc Sniff(
-        const sp<DataSource> &source,
+        DataSourceBase *source,
         String8 *mimeType,
         float *confidence,
         sp<AMessage> *) {
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index 47c3c40..67661ed 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -24,13 +24,12 @@
 namespace android {
 
 struct AMessage;
-class DataSource;
+class DataSourceBase;
 class String8;
 
 class WAVExtractor : public MediaExtractor {
 public:
-    // Extractor assumes ownership of "source".
-    explicit WAVExtractor(const sp<DataSource> &source);
+    explicit WAVExtractor(DataSourceBase *source);
 
     virtual size_t countTracks();
     virtual MediaSourceBase *getTrack(size_t index);
@@ -42,7 +41,7 @@
     virtual ~WAVExtractor();
 
 private:
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     status_t mInitCheck;
     bool mValidFormat;
     uint16_t mWaveFormat;
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 1377005..3ac519b 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -254,6 +254,7 @@
 
     srcs: [
         "BufferingSettings.cpp",
+        "DataSourceDesc.cpp",
         "IDataSource.cpp",
         "IMediaExtractor.cpp",
         "IMediaExtractorService.cpp",
diff --git a/media/libmedia/DataSourceDesc.cpp b/media/libmedia/DataSourceDesc.cpp
new file mode 100644
index 0000000..b7ccbce
--- /dev/null
+++ b/media/libmedia/DataSourceDesc.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DataSourceDesc"
+
+#include <media/DataSource.h>
+#include <media/DataSourceDesc.h>
+#include <media/MediaHTTPService.h>
+
+namespace android {
+
+static const int64_t kLongMax = 0x7ffffffffffffffL;
+
+DataSourceDesc::DataSourceDesc()
+    : mType(TYPE_NONE),
+      mFDOffset(0),
+      mFDLength(kLongMax),
+      mId(0),
+      mStartPositionMs(0),
+      mEndPositionMs(0) {
+}
+
+}  // namespace android
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index a8a7b82..51ccb5a 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -39,8 +39,7 @@
     SETMEDIACAS,
     SETUID,
     NAME,
-    GETMETRICS,
-    RELEASE,
+    GETMETRICS
 };
 
 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
@@ -140,13 +139,6 @@
         ALOGV("name NOT IMPLEMENTED");
         return NULL;
     }
-
-    virtual void release() {
-        ALOGV("release");
-        Parcel data, reply;
-        data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
-        remote()->transact(RELEASE, data, &reply);
-    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
@@ -224,12 +216,6 @@
             reply->writeInt32(setMediaCas(casToken));
             return OK;
         }
-        case RELEASE: {
-            ALOGV("release");
-            CHECK_INTERFACE(IMediaExtractor, data, reply);
-            release();
-            return OK;
-        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/MediaPlayer2Manager.cpp b/media/libmedia/MediaPlayer2Manager.cpp
index aefb91c..76b4c0b 100644
--- a/media/libmedia/MediaPlayer2Manager.cpp
+++ b/media/libmedia/MediaPlayer2Manager.cpp
@@ -45,6 +45,7 @@
 #include <utils/Vector.h>
 
 #include <media/AudioPolicyHelper.h>
+#include <media/DataSourceDesc.h>
 #include <media/MediaHTTPService.h>
 #include <media/MediaPlayer2EngineClient.h>
 #include <media/MediaPlayer2Interface.h>
@@ -247,13 +248,6 @@
 
 MediaPlayer2Manager gMediaPlayer2Manager;
 
-static bool checkPermission(const char* permissionString) {
-    if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
-    bool ok = checkCallingPermission(String16(permissionString));
-    if (!ok) ALOGE("Request requires %s", permissionString);
-    return ok;
-}
-
 // TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
 /* static */ int MediaPlayer2Manager::AudioOutput::mMinBufferCount = 4;
 /* static */ bool MediaPlayer2Manager::AudioOutput::mIsOnEmulator = false;
@@ -284,6 +278,10 @@
     sp<Client> c = new Client(
             mPid, connId, client, audioSessionId, mUid);
 
+    if (!c->init()) {
+        return NULL;
+    }
+
     ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, mPid, mUid);
 
     wp<Client> w = c;
@@ -514,6 +512,25 @@
 #endif
 }
 
+bool MediaPlayer2Manager::Client::init() {
+    sp<MediaPlayer2Interface> p = new NuPlayer2Driver(mPid);
+    status_t init_result = p->initCheck();
+    if (init_result != NO_ERROR) {
+        ALOGE("Failed to create player object, initCheck failed(%d)", init_result);
+        return false;
+    }
+
+    p->setNotifyCallback(this, notify);
+    p->setUID(mUid);
+    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
+    mAudioOutput = new AudioOutput(mAudioSessionId, mUid,
+            mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
+    p->setAudioSink(mAudioOutput);
+
+    mPlayer = p;
+    return true;
+}
+
 MediaPlayer2Manager::Client::~Client()
 {
     ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
@@ -560,26 +577,6 @@
     IPCThreadState::self()->flushCommands();
 }
 
-sp<MediaPlayer2Interface> MediaPlayer2Manager::Client::createPlayer() {
-    sp<MediaPlayer2Interface> p = getPlayer();
-    if (p == NULL) {
-        p = new NuPlayer2Driver(mPid);
-        status_t init_result = p->initCheck();
-        if (init_result == NO_ERROR) {
-            p->setNotifyCallback(this, notify);
-        } else {
-            ALOGE("Failed to create player, initCheck failed(res = %d)", init_result);
-            p.clear();
-        }
-    }
-
-    if (p != NULL) {
-        p->setUID(mUid);
-    }
-
-    return p;
-}
-
 void MediaPlayer2Manager::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
         audio_io_handle_t audioIo,
         audio_port_handle_t deviceId) {
@@ -591,30 +588,20 @@
     }
 }
 
-sp<MediaPlayer2Interface> MediaPlayer2Manager::Client::setDataSource_pre() {
-    sp<MediaPlayer2Interface> p = createPlayer();
+status_t MediaPlayer2Manager::Client::setDataSource(
+        const sp<DataSourceDesc> &dsd) {
+    sp<MediaPlayer2Interface> p = getPlayer();
     if (p == NULL) {
-        return p;
+        return NO_INIT;
     }
 
-    Mutex::Autolock lock(mLock);
+    if (dsd == NULL) {
+        return BAD_VALUE;
+    }
 
-    mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
-
-    mAudioOutput = new AudioOutput(mAudioSessionId, mUid,
-            mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
-    p->setAudioSink(mAudioOutput);
-
-    return p;
-}
-
-status_t MediaPlayer2Manager::Client::setDataSource_post(
-        const sp<MediaPlayer2Interface>& p,
-        status_t status)
-{
-    ALOGV(" setDataSource");
+    status_t status = p->setDataSource(dsd);
     if (status != OK) {
-        ALOGE("  error: %d", status);
+        ALOGE("setDataSource error: %d", status);
         return status;
     }
 
@@ -626,102 +613,9 @@
         }
     }
 
-    if (status == OK) {
-        Mutex::Autolock lock(mLock);
-        mPlayer = p;
-    }
     return status;
 }
 
-status_t MediaPlayer2Manager::Client::setDataSource(
-        const sp<MediaHTTPService> &httpService,
-        const char *url,
-        const KeyedVector<String8, String8> *headers)
-{
-    ALOGV("setDataSource(%s)", url);
-    if (url == NULL)
-        return UNKNOWN_ERROR;
-
-    if ((strncmp(url, "http://", 7) == 0) ||
-        (strncmp(url, "https://", 8) == 0) ||
-        (strncmp(url, "rtsp://", 7) == 0)) {
-        if (!checkPermission("android.permission.INTERNET")) {
-            return PERMISSION_DENIED;
-        }
-    }
-
-    if (strncmp(url, "content://", 10) == 0) {
-        ALOGE("setDataSource: content scheme is not supported here");
-        mStatus = UNKNOWN_ERROR;
-        return mStatus;
-    } else {
-        sp<MediaPlayer2Interface> p = setDataSource_pre();
-        if (p == NULL) {
-            return NO_INIT;
-        }
-
-        return mStatus =
-                setDataSource_post(
-                p, p->setDataSource(httpService, url, headers));
-    }
-}
-
-status_t MediaPlayer2Manager::Client::setDataSource(int fd, int64_t offset, int64_t length)
-{
-    ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
-            fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
-    struct stat sb;
-    int ret = fstat(fd, &sb);
-    if (ret != 0) {
-        ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
-        return UNKNOWN_ERROR;
-    }
-
-    ALOGV("st_dev  = %llu", static_cast<unsigned long long>(sb.st_dev));
-    ALOGV("st_mode = %u", sb.st_mode);
-    ALOGV("st_uid  = %lu", static_cast<unsigned long>(sb.st_uid));
-    ALOGV("st_gid  = %lu", static_cast<unsigned long>(sb.st_gid));
-    ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));
-
-    if (offset >= sb.st_size) {
-        ALOGE("offset error");
-        return UNKNOWN_ERROR;
-    }
-    if (offset + length > sb.st_size) {
-        length = sb.st_size - offset;
-        ALOGV("calculated length = %lld", (long long)length);
-    }
-
-    sp<MediaPlayer2Interface> p = setDataSource_pre();
-    if (p == NULL) {
-        return NO_INIT;
-    }
-
-    // now set data source
-    return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
-}
-
-status_t MediaPlayer2Manager::Client::setDataSource(
-        const sp<IStreamSource> &source) {
-    sp<MediaPlayer2Interface> p = setDataSource_pre();
-    if (p == NULL) {
-        return NO_INIT;
-    }
-
-    // now set data source
-    return mStatus = setDataSource_post(p, p->setDataSource(source));
-}
-
-status_t MediaPlayer2Manager::Client::setDataSource(
-        const sp<DataSource> &source) {
-    sp<MediaPlayer2Interface> p = setDataSource_pre();
-    if (p == NULL) {
-        return NO_INIT;
-    }
-    // now set data source
-    return mStatus = setDataSource_post(p, p->setDataSource(source));
-}
-
 void MediaPlayer2Manager::Client::disconnectNativeWindow_l() {
     if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
         status_t err = native_window_api_disconnect(
@@ -1187,13 +1081,8 @@
         ALOGV("[%d] setRetransmitEndpoint = <none>", mConnId);
     }
 
-    sp<MediaPlayer2Interface> p = getPlayer();
-
     // Right now, the only valid time to set a retransmit endpoint is before
-    // player selection has been made (since the presence or absence of a
-    // retransmit endpoint is going to determine which player is selected during
-    // setDataSource).
-    if (p != 0) return INVALID_OPERATION;
+    // setDataSource.
 
     if (NULL != endpoint) {
         Mutex::Autolock lock(mLock);
diff --git a/media/libmedia/MediaPlayer2Manager.h b/media/libmedia/MediaPlayer2Manager.h
index 20cc735..cdbbc70 100644
--- a/media/libmedia/MediaPlayer2Manager.h
+++ b/media/libmedia/MediaPlayer2Manager.h
@@ -287,22 +287,7 @@
                                         const sp<media::VolumeShaper::Operation>& operation) override;
         virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
 
-        sp<MediaPlayer2Interface>    createPlayer();
-
-        virtual status_t        setDataSource(
-                        const sp<MediaHTTPService> &httpService,
-                        const char *url,
-                        const KeyedVector<String8, String8> *headers);
-
-        virtual status_t        setDataSource(int fd, int64_t offset, int64_t length);
-
-        virtual status_t        setDataSource(const sp<IStreamSource> &source);
-        virtual status_t        setDataSource(const sp<DataSource> &source);
-
-
-        sp<MediaPlayer2Interface>    setDataSource_pre();
-        status_t                setDataSource_post(const sp<MediaPlayer2Interface>& p,
-                                                   status_t status);
+        virtual status_t        setDataSource(const sp<DataSourceDesc> &dsd);
 
         static  void            notify(const wp<MediaPlayer2Engine> &listener, int msg,
                                        int ext1, int ext2, const Parcel *obj);
@@ -343,6 +328,7 @@
                                        uid_t uid);
                                 Client();
         virtual                 ~Client();
+        bool init();
 
                 void            deletePlayer();
 
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index 4e5d67f..0896e75 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -47,7 +47,7 @@
     mLength = size;
 }
 
-MidiIoWrapper::MidiIoWrapper(const sp<DataSource> &source) {
+MidiIoWrapper::MidiIoWrapper(DataSourceBase *source) {
     ALOGV("MidiIoWrapper(DataSource)");
     mFd = -1;
     mDataSource = source;
diff --git a/media/libmedia/include/media/DataSourceDesc.h b/media/libmedia/include/media/DataSourceDesc.h
new file mode 100644
index 0000000..c190261
--- /dev/null
+++ b/media/libmedia/include/media/DataSourceDesc.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_DATASOURCEDESC_H
+#define ANDROID_DATASOURCEDESC_H
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class DataSource;
+struct MediaHTTPService;
+
+// A binder interface for implementing a stagefright DataSource remotely.
+struct DataSourceDesc : public RefBase {
+public:
+    enum {
+        /* No data source has been set yet */
+        TYPE_NONE     = 0,
+        /* data source is type of MediaDataSource */
+        TYPE_CALLBACK = 1,
+        /* data source is type of FileDescriptor */
+        TYPE_FD       = 2,
+        /* data source is type of Url */
+        TYPE_URL      = 3,
+    };
+
+    DataSourceDesc();
+
+    int mType;
+
+    sp<MediaHTTPService> mHttpService;
+    String8 mUrl;
+    KeyedVector<String8, String8> mHeaders;
+
+    int mFD;
+    int64_t mFDOffset;
+    int64_t mFDLength;
+
+    sp<DataSource> mCallbackSource;
+
+    int64_t mId;
+    int64_t mStartPositionMs;
+    int64_t mEndPositionMs;
+
+private:
+    DISALLOW_EVIL_CONSTRUCTORS(DataSourceDesc);
+};
+
+}; // namespace android
+
+#endif // ANDROID_DATASOURCEDESC_H
diff --git a/media/libmedia/include/media/IMediaExtractor.h b/media/libmedia/include/media/IMediaExtractor.h
index 44f8c1d..9899429 100644
--- a/media/libmedia/include/media/IMediaExtractor.h
+++ b/media/libmedia/include/media/IMediaExtractor.h
@@ -68,8 +68,6 @@
     virtual void setUID(uid_t uid)  = 0;
 
     virtual const char * name() = 0;
-
-    virtual void release() = 0;
 };
 
 
diff --git a/media/libmedia/include/media/MediaPlayer2Engine.h b/media/libmedia/include/media/MediaPlayer2Engine.h
index 00f5fb1..29df2d6 100644
--- a/media/libmedia/include/media/MediaPlayer2Engine.h
+++ b/media/libmedia/include/media/MediaPlayer2Engine.h
@@ -36,6 +36,7 @@
 struct AudioPlaybackRate;
 struct BufferingSettings;
 class DataSource;
+struct DataSourceDesc;
 struct IStreamSource;
 struct MediaHTTPService;
 class Parcel;
@@ -47,14 +48,7 @@
 public:
     virtual void            disconnect() = 0;
 
-    virtual status_t        setDataSource(
-            const sp<MediaHTTPService> &httpService,
-            const char *url,
-            const KeyedVector<String8, String8>* headers) = 0;
-
-    virtual status_t        setDataSource(int fd, int64_t offset, int64_t length) = 0;
-    virtual status_t        setDataSource(const sp<IStreamSource>& source) = 0;
-    virtual status_t        setDataSource(const sp<DataSource>& source) = 0;
+    virtual status_t        setDataSource(const sp<DataSourceDesc>& source) = 0;
     virtual status_t        setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
     virtual status_t        getBufferingSettings(
                                     BufferingSettings* buffering /* nonnull */) = 0;
diff --git a/media/libmedia/include/media/MediaPlayer2Interface.h b/media/libmedia/include/media/MediaPlayer2Interface.h
index 699618e..c2cc6e6 100644
--- a/media/libmedia/include/media/MediaPlayer2Interface.h
+++ b/media/libmedia/include/media/MediaPlayer2Interface.h
@@ -41,6 +41,7 @@
 namespace android {
 
 class DataSource;
+struct DataSourceDesc;
 struct MediaHTTPService;
 class Parcel;
 struct ANativeWindowWrapper;
@@ -158,18 +159,7 @@
 
     virtual void        setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
 
-    virtual status_t    setDataSource(
-            const sp<MediaHTTPService> &httpService,
-            const char *url,
-            const KeyedVector<String8, String8> *headers = NULL) = 0;
-
-    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
-
-    virtual status_t    setDataSource(const sp<IStreamSource>& /* source */) {
-        return INVALID_OPERATION;
-    }
-
-    virtual status_t    setDataSource(const sp<DataSource>& /* source */) {
+    virtual status_t    setDataSource(const sp<DataSourceDesc>& /* dsd */) {
         return INVALID_OPERATION;
     }
 
diff --git a/media/libmedia/include/media/MidiIoWrapper.h b/media/libmedia/include/media/MidiIoWrapper.h
index 2754b2c..a27b410 100644
--- a/media/libmedia/include/media/MidiIoWrapper.h
+++ b/media/libmedia/include/media/MidiIoWrapper.h
@@ -19,7 +19,7 @@
 
 #include <libsonivox/eas_types.h>
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 
 namespace android {
 
@@ -27,7 +27,7 @@
 public:
     MidiIoWrapper(const char *path);
     MidiIoWrapper(int fd, off64_t offset, int64_t size);
-    MidiIoWrapper(const sp<DataSource> &source);
+    MidiIoWrapper(DataSourceBase *source);
 
     ~MidiIoWrapper();
 
@@ -40,7 +40,7 @@
     int mFd;
     off64_t mBase;
     int64_t  mLength;
-    sp<DataSource> mDataSource;
+    DataSourceBase *mDataSource;
     EAS_FILE mEasFile;
 };
 
diff --git a/media/libmedia/include/media/mediaplayer2.h b/media/libmedia/include/media/mediaplayer2.h
index c96765f..f2fc901 100644
--- a/media/libmedia/include/media/mediaplayer2.h
+++ b/media/libmedia/include/media/mediaplayer2.h
@@ -36,6 +36,7 @@
 struct AVSyncSettings;
 struct ANativeWindowWrapper;
 class DataSource;
+struct DataSourceDesc;
 struct MediaHTTPService;
 
 enum media2_event_type {
@@ -202,13 +203,7 @@
     ~MediaPlayer2();
             void            disconnect();
 
-            status_t        setDataSource(
-                    const sp<MediaHTTPService> &httpService,
-                    const char *url,
-                    const KeyedVector<String8, String8> *headers);
-
-            status_t        setDataSource(int fd, int64_t offset, int64_t length);
-            status_t        setDataSource(const sp<DataSource> &source);
+            status_t        setDataSource(const sp<DataSourceDesc> &dsd);
             status_t        setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww);
             status_t        setListener(const sp<MediaPlayer2Listener>& listener);
             status_t        getBufferingSettings(BufferingSettings* buffering /* nonnull */);
diff --git a/media/libmedia/mediaplayer2.cpp b/media/libmedia/mediaplayer2.cpp
index 5c34d4a..ba24da7 100644
--- a/media/libmedia/mediaplayer2.cpp
+++ b/media/libmedia/mediaplayer2.cpp
@@ -34,6 +34,7 @@
 #include <media/AudioSystem.h>
 #include <media/AVSyncSettings.h>
 #include <media/DataSource.h>
+#include <media/DataSourceDesc.h>
 #include <media/MediaAnalyticsItem.h>
 #include <media/NdkWrapper.h>
 
@@ -153,43 +154,16 @@
     return err;
 }
 
-status_t MediaPlayer2::setDataSource(
-        const sp<MediaHTTPService> &httpService,
-        const char *url, const KeyedVector<String8, String8> *headers)
+status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd)
 {
-    ALOGV("setDataSource(%s)", url);
-    status_t err = BAD_VALUE;
-    if (url != NULL) {
-        sp<MediaPlayer2Engine> player(MediaPlayer2Manager::get().create(this, mAudioSessionId));
-        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
-            (NO_ERROR != player->setDataSource(httpService, url, headers))) {
-            player.clear();
-        }
-        err = attachNewPlayer(player);
+    if (dsd == NULL) {
+        return BAD_VALUE;
     }
-    return err;
-}
-
-status_t MediaPlayer2::setDataSource(int fd, int64_t offset, int64_t length)
-{
-    ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
+    ALOGV("setDataSource type(%d)", dsd->mType);
     status_t err = UNKNOWN_ERROR;
     sp<MediaPlayer2Engine> player(MediaPlayer2Manager::get().create(this, mAudioSessionId));
     if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
-        (NO_ERROR != player->setDataSource(fd, offset, length))) {
-        player.clear();
-    }
-    err = attachNewPlayer(player);
-    return err;
-}
-
-status_t MediaPlayer2::setDataSource(const sp<DataSource> &source)
-{
-    ALOGV("setDataSource(DataSource)");
-    status_t err = UNKNOWN_ERROR;
-    sp<MediaPlayer2Engine> player(MediaPlayer2Manager::get().create(this, mAudioSessionId));
-    if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
-        (NO_ERROR != player->setDataSource(source))) {
+        (NO_ERROR != player->setDataSource(dsd))) {
         player.clear();
     }
     err = attachNewPlayer(player);
diff --git a/media/libmedia/nuplayer2/NuPlayer2.cpp b/media/libmedia/nuplayer2/NuPlayer2.cpp
index 2c7f416..35e20e8 100644
--- a/media/libmedia/nuplayer2/NuPlayer2.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2.cpp
@@ -43,6 +43,7 @@
 #include <media/AudioParameter.h>
 #include <media/AudioResamplerPublic.h>
 #include <media/AVSyncSettings.h>
+#include <media/DataSourceDesc.h>
 #include <media/MediaCodecBuffer.h>
 #include <media/NdkWrapper.h>
 
@@ -258,16 +259,6 @@
     mDriver = driver;
 }
 
-void NuPlayer2::setDataSourceAsync(const sp<IStreamSource> &source) {
-    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
-
-    sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
-
-    msg->setObject("source", new StreamingSource(notify, source));
-    msg->post();
-    mDataSourceType = DATA_SOURCE_TYPE_STREAM;
-}
-
 static bool IsHTTPLiveURL(const char *url) {
     if (!strncasecmp("http://", url, 7)
             || !strncasecmp("https://", url, 8)
@@ -285,93 +276,102 @@
     return false;
 }
 
-void NuPlayer2::setDataSourceAsync(
-        const sp<MediaHTTPService> &httpService,
-        const char *url,
-        const KeyedVector<String8, String8> *headers) {
-
+void NuPlayer2::setDataSourceAsync(const sp<DataSourceDesc> &dsd) {
     sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
-    size_t len = strlen(url);
-
     sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
-
     sp<Source> source;
-    if (IsHTTPLiveURL(url)) {
-        source = new HTTPLiveSource(notify, httpService, url, headers);
-        ALOGV("setDataSourceAsync HTTPLiveSource %s", url);
-        mDataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
-    } else if (!strncasecmp(url, "rtsp://", 7)) {
-        source = new RTSPSource(
-                notify, httpService, url, headers, mUIDValid, mUID);
-        ALOGV("setDataSourceAsync RTSPSource %s", url);
-        mDataSourceType = DATA_SOURCE_TYPE_RTSP;
-    } else if ((!strncasecmp(url, "http://", 7)
-                || !strncasecmp(url, "https://", 8))
-                    && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
-                    || strstr(url, ".sdp?"))) {
-        source = new RTSPSource(
-                notify, httpService, url, headers, mUIDValid, mUID, true);
-        ALOGV("setDataSourceAsync RTSPSource http/https/.sdp %s", url);
-        mDataSourceType = DATA_SOURCE_TYPE_RTSP;
-    } else {
-        ALOGV("setDataSourceAsync GenericSource %s", url);
 
-        sp<GenericSource> genericSource =
-                new GenericSource(notify, mUIDValid, mUID, mMediaClock);
+    switch (dsd->mType) {
+        case DataSourceDesc::TYPE_URL:
+        {
+            const char *url = dsd->mUrl.c_str();
+            size_t len = strlen(url);
 
-        status_t err = genericSource->setDataSource(httpService, url, headers);
+            const sp<MediaHTTPService> &httpService = dsd->mHttpService;
+            KeyedVector<String8, String8> *headers = &(dsd->mHeaders);
 
-        if (err == OK) {
-            source = genericSource;
-        } else {
-            ALOGE("Failed to set data source!");
+            if (IsHTTPLiveURL(url)) {
+                source = new HTTPLiveSource(notify, httpService, url, headers);
+                ALOGV("setDataSourceAsync HTTPLiveSource %s", url);
+                mDataSourceType = DATA_SOURCE_TYPE_HTTP_LIVE;
+            } else if (!strncasecmp(url, "rtsp://", 7)) {
+                source = new RTSPSource(
+                        notify, httpService, url, headers, mUIDValid, mUID);
+                ALOGV("setDataSourceAsync RTSPSource %s", url);
+                mDataSourceType = DATA_SOURCE_TYPE_RTSP;
+            } else if ((!strncasecmp(url, "http://", 7)
+                        || !strncasecmp(url, "https://", 8))
+                            && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4]))
+                            || strstr(url, ".sdp?"))) {
+                source = new RTSPSource(
+                        notify, httpService, url, headers, mUIDValid, mUID, true);
+                ALOGV("setDataSourceAsync RTSPSource http/https/.sdp %s", url);
+                mDataSourceType = DATA_SOURCE_TYPE_RTSP;
+            } else {
+                ALOGV("setDataSourceAsync GenericSource %s", url);
+
+                sp<GenericSource> genericSource =
+                        new GenericSource(notify, mUIDValid, mUID, mMediaClock);
+
+                status_t err = genericSource->setDataSource(httpService, url, headers);
+
+                if (err == OK) {
+                    source = genericSource;
+                } else {
+                    ALOGE("Failed to set data source!");
+                }
+
+                // regardless of success/failure
+                mDataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
+            }
+            break;
         }
 
-        // regardless of success/failure
-        mDataSourceType = DATA_SOURCE_TYPE_GENERIC_URL;
-    }
-    msg->setObject("source", source);
-    msg->post();
-}
+        case DataSourceDesc::TYPE_FD:
+        {
+            sp<GenericSource> genericSource =
+                    new GenericSource(notify, mUIDValid, mUID, mMediaClock);
 
-void NuPlayer2::setDataSourceAsync(int fd, int64_t offset, int64_t length) {
-    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
+            ALOGV("setDataSourceAsync fd %d/%lld/%lld source: %p",
+                  dsd->mFD, (long long)dsd->mFDOffset, (long long)dsd->mFDLength, source.get());
 
-    sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
+            status_t err = genericSource->setDataSource(dsd->mFD, dsd->mFDOffset, dsd->mFDLength);
 
-    sp<GenericSource> source =
-            new GenericSource(notify, mUIDValid, mUID, mMediaClock);
+            if (err != OK) {
+                ALOGE("Failed to set data source!");
+                source = NULL;
+            } else {
+                source = genericSource;
+            }
 
-    ALOGV("setDataSourceAsync fd %d/%lld/%lld source: %p",
-            fd, (long long)offset, (long long)length, source.get());
+            mDataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
+            break;
+        }
 
-    status_t err = source->setDataSource(fd, offset, length);
+        case DataSourceDesc::TYPE_CALLBACK:
+        {
+            sp<GenericSource> genericSource =
+                    new GenericSource(notify, mUIDValid, mUID, mMediaClock);
+            status_t err = genericSource->setDataSource(dsd->mCallbackSource);
 
-    if (err != OK) {
-        ALOGE("Failed to set data source!");
-        source = NULL;
+            if (err != OK) {
+                ALOGE("Failed to set data source!");
+                source = NULL;
+            } else {
+                source = genericSource;
+            }
+
+            mDataSourceType = DATA_SOURCE_TYPE_MEDIA;
+            break;
+        }
+
+        default:
+            ALOGE("invalid data source type!");
+            break;
     }
 
     msg->setObject("source", source);
     msg->post();
-    mDataSourceType = DATA_SOURCE_TYPE_GENERIC_FD;
-}
-
-void NuPlayer2::setDataSourceAsync(const sp<DataSource> &dataSource) {
-    sp<AMessage> msg = new AMessage(kWhatSetDataSource, this);
-    sp<AMessage> notify = new AMessage(kWhatSourceNotify, this);
-
-    sp<GenericSource> source = new GenericSource(notify, mUIDValid, mUID, mMediaClock);
-    status_t err = source->setDataSource(dataSource);
-
-    if (err != OK) {
-        ALOGE("Failed to set data source!");
-        source = NULL;
-    }
-
-    msg->setObject("source", source);
-    msg->post();
-    mDataSourceType = DATA_SOURCE_TYPE_MEDIA;
 }
 
 status_t NuPlayer2::getBufferingSettings(
diff --git a/media/libmedia/nuplayer2/NuPlayer2.h b/media/libmedia/nuplayer2/NuPlayer2.h
index 23c4fdf..0764ec3 100644
--- a/media/libmedia/nuplayer2/NuPlayer2.h
+++ b/media/libmedia/nuplayer2/NuPlayer2.h
@@ -30,6 +30,7 @@
 struct ANativeWindowWrapper;
 struct AudioPlaybackRate;
 struct AVSyncSettings;
+struct DataSourceDesc;
 class IDataSource;
 struct MediaClock;
 struct MediaHTTPService;
@@ -43,16 +44,7 @@
 
     void setDriver(const wp<NuPlayer2Driver> &driver);
 
-    void setDataSourceAsync(const sp<IStreamSource> &source);
-
-    void setDataSourceAsync(
-            const sp<MediaHTTPService> &httpService,
-            const char *url,
-            const KeyedVector<String8, String8> *headers);
-
-    void setDataSourceAsync(int fd, int64_t offset, int64_t length);
-
-    void setDataSourceAsync(const sp<DataSource> &source);
+    void setDataSourceAsync(const sp<DataSourceDesc> &dsd);
 
     status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
     status_t setBufferingSettings(const BufferingSettings& buffering);
diff --git a/media/libmedia/nuplayer2/NuPlayer2DecoderBase.cpp b/media/libmedia/nuplayer2/NuPlayer2DecoderBase.cpp
index 4d80912..9c1988f 100644
--- a/media/libmedia/nuplayer2/NuPlayer2DecoderBase.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2DecoderBase.cpp
@@ -39,7 +39,9 @@
     // are blocking, but NuPlayer2 needs asynchronous operations.
     mDecoderLooper = new ALooper;
     mDecoderLooper->setName("NPDecoder");
-    mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+    mDecoderLooper->start(false, /* runOnCallingThread */
+                          true,  /* canCallJava */
+                          ANDROID_PRIORITY_AUDIO);
 }
 
 NuPlayer2::DecoderBase::~DecoderBase() {
diff --git a/media/libmedia/nuplayer2/NuPlayer2Driver.cpp b/media/libmedia/nuplayer2/NuPlayer2Driver.cpp
index e48acea..6137fd1 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmedia/nuplayer2/NuPlayer2Driver.cpp
@@ -175,67 +175,7 @@
     return OK;
 }
 
-status_t NuPlayer2Driver::setDataSource(
-        const sp<MediaHTTPService> &httpService,
-        const char *url,
-        const KeyedVector<String8, String8> *headers) {
-    ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
-    Mutex::Autolock autoLock(mLock);
-
-    if (mState != STATE_IDLE) {
-        return INVALID_OPERATION;
-    }
-
-    mState = STATE_SET_DATASOURCE_PENDING;
-
-    mPlayer->setDataSourceAsync(httpService, url, headers);
-
-    while (mState == STATE_SET_DATASOURCE_PENDING) {
-        mCondition.wait(mLock);
-    }
-
-    return mAsyncResult;
-}
-
-status_t NuPlayer2Driver::setDataSource(int fd, int64_t offset, int64_t length) {
-    ALOGV("setDataSource(%p) file(%d)", this, fd);
-    Mutex::Autolock autoLock(mLock);
-
-    if (mState != STATE_IDLE) {
-        return INVALID_OPERATION;
-    }
-
-    mState = STATE_SET_DATASOURCE_PENDING;
-
-    mPlayer->setDataSourceAsync(fd, offset, length);
-
-    while (mState == STATE_SET_DATASOURCE_PENDING) {
-        mCondition.wait(mLock);
-    }
-
-    return mAsyncResult;
-}
-
-status_t NuPlayer2Driver::setDataSource(const sp<IStreamSource> &source) {
-    ALOGV("setDataSource(%p) stream source", this);
-    Mutex::Autolock autoLock(mLock);
-
-    if (mState != STATE_IDLE) {
-        return INVALID_OPERATION;
-    }
-
-    mState = STATE_SET_DATASOURCE_PENDING;
-
-    mPlayer->setDataSourceAsync(source);
-
-    while (mState == STATE_SET_DATASOURCE_PENDING) {
-        mCondition.wait(mLock);
-    }
-
-    return mAsyncResult;
-}
-
-status_t NuPlayer2Driver::setDataSource(const sp<DataSource> &source) {
+status_t NuPlayer2Driver::setDataSource(const sp<DataSourceDesc> &dsd) {
     ALOGV("setDataSource(%p) callback source", this);
     Mutex::Autolock autoLock(mLock);
 
@@ -245,7 +185,7 @@
 
     mState = STATE_SET_DATASOURCE_PENDING;
 
-    mPlayer->setDataSourceAsync(source);
+    mPlayer->setDataSourceAsync(dsd);
 
     while (mState == STATE_SET_DATASOURCE_PENDING) {
         mCondition.wait(mLock);
diff --git a/media/libmedia/nuplayer2/NuPlayer2Driver.h b/media/libmedia/nuplayer2/NuPlayer2Driver.h
index 7bbb367..55fc9ef 100644
--- a/media/libmedia/nuplayer2/NuPlayer2Driver.h
+++ b/media/libmedia/nuplayer2/NuPlayer2Driver.h
@@ -32,16 +32,7 @@
 
     virtual status_t setUID(uid_t uid);
 
-    virtual status_t setDataSource(
-            const sp<MediaHTTPService> &httpService,
-            const char *url,
-            const KeyedVector<String8, String8> *headers);
-
-    virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
-
-    virtual status_t setDataSource(const sp<IStreamSource> &source);
-
-    virtual status_t setDataSource(const sp<DataSource>& dataSource);
+    virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
 
     virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper> &nww);
 
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 4071fba..8f4ba70 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -23,7 +23,7 @@
     ],
 
     srcs: [
-        "DataSource.cpp",
+        "DataSourceBase.cpp",
         "MediaBuffer.cpp",
         "MediaBufferGroup.cpp",
         "MediaSourceBase.cpp",
diff --git a/media/libmediaextractor/DataSource.cpp b/media/libmediaextractor/DataSourceBase.cpp
similarity index 77%
rename from media/libmediaextractor/DataSource.cpp
rename to media/libmediaextractor/DataSourceBase.cpp
index 72959c6..d3af4eb 100644
--- a/media/libmediaextractor/DataSource.cpp
+++ b/media/libmediaextractor/DataSourceBase.cpp
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 //#define LOG_NDEBUG 0
-#define LOG_TAG "DataSource"
+#define LOG_TAG "DataSourceBase"
 
-#include <media/DataSource.h>
+#include <media/DataSourceBase.h>
 #include <media/stagefright/foundation/ByteUtils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/String8.h>
 
 namespace android {
 
-bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
+bool DataSourceBase::getUInt16(off64_t offset, uint16_t *x) {
     *x = 0;
 
     uint8_t byte[2];
@@ -36,7 +36,7 @@
     return true;
 }
 
-bool DataSource::getUInt24(off64_t offset, uint32_t *x) {
+bool DataSourceBase::getUInt24(off64_t offset, uint32_t *x) {
     *x = 0;
 
     uint8_t byte[3];
@@ -49,7 +49,7 @@
     return true;
 }
 
-bool DataSource::getUInt32(off64_t offset, uint32_t *x) {
+bool DataSourceBase::getUInt32(off64_t offset, uint32_t *x) {
     *x = 0;
 
     uint32_t tmp;
@@ -62,7 +62,7 @@
     return true;
 }
 
-bool DataSource::getUInt64(off64_t offset, uint64_t *x) {
+bool DataSourceBase::getUInt64(off64_t offset, uint64_t *x) {
     *x = 0;
 
     uint64_t tmp;
@@ -75,7 +75,7 @@
     return true;
 }
 
-bool DataSource::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
+bool DataSourceBase::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
     if (size == 2) {
         return getUInt16(offset, x);
     }
@@ -89,7 +89,7 @@
     return false;
 }
 
-bool DataSource::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
+bool DataSourceBase::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
     if (size == 4) {
         return getUInt32(offset, x);
     }
@@ -103,7 +103,7 @@
     return false;
 }
 
-bool DataSource::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
+bool DataSourceBase::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
     if (size == 8) {
         return getUInt64(offset, x);
     }
@@ -117,13 +117,13 @@
     return false;
 }
 
-status_t DataSource::getSize(off64_t *size) {
+status_t DataSourceBase::getSize(off64_t *size) {
     *size = 0;
 
     return ERROR_UNSUPPORTED;
 }
 
-String8 DataSource::getMIMEType() const {
+String8 DataSourceBase::getMIMEType() const {
     return String8("application/octet-stream");
 }
 
diff --git a/media/libmediaextractor/include/media/DataSource.h b/media/libmediaextractor/include/media/DataSource.h
index 9f00e0a..a066183 100644
--- a/media/libmediaextractor/include/media/DataSource.h
+++ b/media/libmediaextractor/include/media/DataSource.h
@@ -20,75 +20,21 @@
 
 #include <sys/types.h>
 #include <media/stagefright/MediaErrors.h>
+#include <media/DataSourceBase.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/threads.h>
 #include <drm/DrmManagerClient.h>
 
+
 namespace android {
 
 class String8;
 
-class DataSource : public RefBase {
+class DataSource : public DataSourceBase, public virtual RefBase {
 public:
-    enum Flags {
-        kWantsPrefetching      = 1,
-        kStreamedFromLocalHost = 2,
-        kIsCachingDataSource   = 4,
-        kIsHTTPBasedSource     = 8,
-        kIsLocalFileSource     = 16,
-    };
-
     DataSource() {}
 
-    virtual status_t initCheck() const = 0;
-
-    // Returns the number of bytes read, or -1 on failure. It's not an error if
-    // this returns zero; it just means the given offset is equal to, or
-    // beyond, the end of the source.
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
-
-    // Convenience methods:
-    bool getUInt16(off64_t offset, uint16_t *x);
-    bool getUInt24(off64_t offset, uint32_t *x); // 3 byte int, returned as a 32-bit int
-    bool getUInt32(off64_t offset, uint32_t *x);
-    bool getUInt64(off64_t offset, uint64_t *x);
-
-    // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
-    bool getUInt16Var(off64_t offset, uint16_t *x, size_t size);
-    bool getUInt32Var(off64_t offset, uint32_t *x, size_t size);
-    bool getUInt64Var(off64_t offset, uint64_t *x, size_t size);
-
-    // May return ERROR_UNSUPPORTED.
-    virtual status_t getSize(off64_t *size);
-
-    virtual uint32_t flags() {
-        return 0;
-    }
-
-    virtual String8 toString() {
-        return String8("<unspecified>");
-    }
-
-    virtual status_t reconnectAtOffset(off64_t /*offset*/) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-
-    // for DRM
-    virtual sp<DecryptHandle> DrmInitialization(const char * /*mime*/ = NULL) {
-        return NULL;
-    }
-
-    virtual String8 getUri() {
-        return String8();
-    }
-
-    virtual String8 getMIMEType() const;
-
-    virtual void close() {};
-
 protected:
     virtual ~DataSource() {}
 
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libmediaextractor/include/media/DataSourceBase.h
new file mode 100644
index 0000000..f964137
--- /dev/null
+++ b/media/libmediaextractor/include/media/DataSourceBase.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DATA_SOURCE_BASE_H_
+
+#define DATA_SOURCE_BASE_H_
+
+#include <sys/types.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+#include <drm/DrmManagerClient.h>
+
+namespace android {
+
+class String8;
+
+class DataSourceBase {
+public:
+    enum Flags {
+        kWantsPrefetching      = 1,
+        kStreamedFromLocalHost = 2,
+        kIsCachingDataSource   = 4,
+        kIsHTTPBasedSource     = 8,
+        kIsLocalFileSource     = 16,
+    };
+
+    DataSourceBase() {}
+
+    virtual status_t initCheck() const = 0;
+
+    // Returns the number of bytes read, or -1 on failure. It's not an error if
+    // this returns zero; it just means the given offset is equal to, or
+    // beyond, the end of the source.
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
+
+    // Convenience methods:
+    bool getUInt16(off64_t offset, uint16_t *x);
+    bool getUInt24(off64_t offset, uint32_t *x); // 3 byte int, returned as a 32-bit int
+    bool getUInt32(off64_t offset, uint32_t *x);
+    bool getUInt64(off64_t offset, uint64_t *x);
+
+    // read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
+    bool getUInt16Var(off64_t offset, uint16_t *x, size_t size);
+    bool getUInt32Var(off64_t offset, uint32_t *x, size_t size);
+    bool getUInt64Var(off64_t offset, uint64_t *x, size_t size);
+
+    // Reads in "count" entries of type T into vector *x.
+    // Returns true if "count" entries can be read.
+    // If fewer than "count" entries can be read, return false. In this case,
+    // the output vector *x will still have those entries that were read. Call
+    // x->size() to obtain the number of entries read.
+    // The optional parameter chunkSize specifies how many entries should be
+    // read from the data source at one time into a temporary buffer. Increasing
+    // chunkSize can improve the performance at the cost of extra memory usage.
+    // The default value for chunkSize is set to read at least 4k bytes at a
+    // time, depending on sizeof(T).
+    template <typename T>
+    bool getVector(off64_t offset, Vector<T>* x, size_t count,
+                   size_t chunkSize = (4095 / sizeof(T)) + 1);
+
+    // May return ERROR_UNSUPPORTED.
+    virtual status_t getSize(off64_t *size);
+
+    virtual uint32_t flags() {
+        return 0;
+    }
+
+    virtual String8 toString() {
+        return String8("<unspecified>");
+    }
+
+    virtual status_t reconnectAtOffset(off64_t /*offset*/) {
+        return ERROR_UNSUPPORTED;
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    // for DRM
+    virtual sp<DecryptHandle> DrmInitialization(const char * /*mime*/ = NULL) {
+        return NULL;
+    }
+
+    virtual String8 getUri() {
+        return String8();
+    }
+
+    virtual String8 getMIMEType() const;
+
+    virtual void close() {};
+
+protected:
+    virtual ~DataSourceBase() {}
+
+private:
+    DataSourceBase(const DataSourceBase &);
+    DataSourceBase &operator=(const DataSourceBase &);
+};
+
+template <typename T>
+bool DataSourceBase::getVector(off64_t offset, Vector<T>* x, size_t count,
+                           size_t chunkSize)
+{
+    x->clear();
+    if (chunkSize == 0) {
+        return false;
+    }
+    if (count == 0) {
+        return true;
+    }
+
+    T tmp[chunkSize];
+    ssize_t numBytesRead;
+    size_t numBytesPerChunk = chunkSize * sizeof(T);
+    size_t i;
+
+    for (i = 0; i + chunkSize < count; i += chunkSize) {
+        // This loops is executed when more than chunkSize records need to be
+        // read.
+        numBytesRead = this->readAt(offset, (void*)&tmp, numBytesPerChunk);
+        if (numBytesRead == -1) { // If readAt() returns -1, there is an error.
+            return false;
+        }
+        if (static_cast<size_t>(numBytesRead) < numBytesPerChunk) {
+            // This case is triggered when the stream ends before the whole
+            // chunk is read.
+            x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
+            return false;
+        }
+        x->appendArray(tmp, chunkSize);
+        offset += numBytesPerChunk;
+    }
+
+    // There are (count - i) more records to read.
+    // Right now, (count - i) <= chunkSize.
+    // We do the same thing as above, but with chunkSize replaced by count - i.
+    numBytesRead = this->readAt(offset, (void*)&tmp, (count - i) * sizeof(T));
+    if (numBytesRead == -1) {
+        return false;
+    }
+    x->appendArray(tmp, (size_t)numBytesRead / sizeof(T));
+    return x->size() == count;
+}
+
+}  // namespace android
+
+#endif  // DATA_SOURCE_BASE_H_
diff --git a/media/libmediaextractor/include/media/MediaExtractor.h b/media/libmediaextractor/include/media/MediaExtractor.h
index 27581f3..60495ec 100644
--- a/media/libmediaextractor/include/media/MediaExtractor.h
+++ b/media/libmediaextractor/include/media/MediaExtractor.h
@@ -27,7 +27,7 @@
 
 namespace android {
 
-class DataSource;
+class DataSourceBase;
 class MetaData;
 class String8;
 struct AMessage;
@@ -87,15 +87,14 @@
 
     virtual const char * name() { return "<unspecified>"; }
 
-    virtual void release() {}
     typedef MediaExtractor* (*CreatorFunc)(
-            const sp<DataSource> &source, const sp<AMessage> &meta);
+            DataSourceBase *source, const sp<AMessage> &meta);
 
     // The sniffer can optionally fill in "meta" with an AMessage containing
     // a dictionary of values that helps the corresponding extractor initialize
     // its state without duplicating effort already exerted by the sniffer.
     typedef CreatorFunc (*SnifferFunc)(
-            const sp<DataSource> &source, String8 *mimeType,
+            DataSourceBase *source, String8 *mimeType,
             float *confidence, sp<AMessage> *meta);
 
     typedef struct {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 329b901..5240f7b 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -137,6 +137,8 @@
         "libRScpp",
         "libhidlbase",
         "libhidlmemory",
+        // TODO: Remove libv4l2_c2_componentstore.
+        "libv4l2_c2componentstore",
         "libziparchive",
         "android.hidl.allocator@1.0",
         "android.hardware.cas.native@1.0",
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index 9fb6d34..bd2443d 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -64,28 +64,51 @@
     return ICrypto::kDestinationTypeNativeHandle;
 }
 
-// Codec2Buffer
+// LinearBlockBuffer
 
 // static
-sp<Codec2Buffer> Codec2Buffer::allocate(
+sp<LinearBlockBuffer> LinearBlockBuffer::allocate(
         const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
     C2WriteView writeView(block->map().get());
     if (writeView.error() != C2_OK) {
         return nullptr;
     }
-    return new Codec2Buffer(format, new ABuffer(writeView.base(), writeView.capacity()), block);
+    return new LinearBlockBuffer(format, std::move(writeView), block);
 }
 
-C2ConstLinearBlock Codec2Buffer::share() {
+C2ConstLinearBlock LinearBlockBuffer::share() {
     return mBlock->share(offset(), size(), C2Fence());
 }
 
-Codec2Buffer::Codec2Buffer(
+LinearBlockBuffer::LinearBlockBuffer(
         const sp<AMessage> &format,
-        const sp<ABuffer> &buffer,
+        C2WriteView&& writeView,
         const std::shared_ptr<C2LinearBlock> &block)
-    : MediaCodecBuffer(format, buffer),
+    : MediaCodecBuffer(format, new ABuffer(writeView.data(), writeView.size())),
+      mWriteView(writeView),
       mBlock(block) {
 }
 
+// ConstLinearBlockBuffer
+
+// static
+sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::allocate(
+        const sp<AMessage> &format, const C2ConstLinearBlock &block) {
+    C2ReadView readView(block.map().get());
+    if (readView.error() != C2_OK) {
+        return nullptr;
+    }
+    return new ConstLinearBlockBuffer(format, std::move(readView));
+}
+
+ConstLinearBlockBuffer::ConstLinearBlockBuffer(
+        const sp<AMessage> &format,
+        C2ReadView&& readView)
+    : MediaCodecBuffer(format, new ABuffer(
+            // NOTE: ABuffer only takes non-const pointer but this data is
+            //       supposed to be read-only.
+            const_cast<uint8_t *>(readView.data()), readView.capacity())),
+      mReadView(readView) {
+}
+
 }  // namespace android
diff --git a/media/libstagefright/CCodec.cpp b/media/libstagefright/CCodec.cpp
index 1e0a53f..84e98f8 100644
--- a/media/libstagefright/CCodec.cpp
+++ b/media/libstagefright/CCodec.cpp
@@ -16,11 +16,13 @@
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "CCodec"
+#include <cutils/properties.h>
 #include <utils/Log.h>
 
 #include <thread>
 
 #include <C2PlatformSupport.h>
+#include <C2V4l2Support.h>
 
 #include <gui/Surface.h>
 #include <media/stagefright/BufferProducerWrapper.h>
@@ -187,7 +189,14 @@
     std::shared_ptr<C2Component> comp;
     c2_status_t err = GetCodec2PlatformComponentStore()->createComponent(
             componentName.c_str(), &comp);
+    static bool v4l2Enabled =
+            property_get_bool("debug.stagefright.ccodec_v4l2", false);
+    if (err != C2_OK && v4l2Enabled) {
+        err = GetCodec2VDAComponentStore()->createComponent(
+                componentName.c_str(), &comp);
+    }
     if (err != C2_OK) {
+        ALOGE("Failed Create component: %s", componentName.c_str());
         Mutexed<State>::Locked state(mState);
         state->set(RELEASED);
         state.unlock();
@@ -195,6 +204,7 @@
         state.lock();
         return;
     }
+    ALOGV("Success Create component: %s", componentName.c_str());
     comp->setListener_vb(mListener, C2_MAY_BLOCK);
     {
         Mutexed<State>::Locked state(mState);
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 04f7593..ca4ddc8 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -249,7 +249,7 @@
     return std::distance(buffers->begin(), it);
 }
 
-sp<Codec2Buffer> allocateLinearBuffer(
+sp<LinearBlockBuffer> allocateLinearBuffer(
         const std::shared_ptr<C2BlockPool> &pool,
         const sp<AMessage> &format,
         size_t size,
@@ -264,7 +264,7 @@
         return nullptr;
     }
 
-    return Codec2Buffer::allocate(format, block);
+    return LinearBlockBuffer::allocate(format, block);
 }
 
 class Buffer1D : public C2Buffer {
@@ -283,7 +283,7 @@
 
     void add(
             size_t index,
-            const sp<Codec2Buffer> &clientBuffer,
+            const sp<LinearBlockBuffer> &clientBuffer,
             bool available) {
         if (mBufferArray.size() <= index) {
             // TODO: make this more efficient
@@ -340,7 +340,7 @@
 
 private:
     struct Entry {
-        sp<Codec2Buffer> clientBuffer;
+        sp<LinearBlockBuffer> clientBuffer;
         std::weak_ptr<C2Buffer> compBuffer;
         bool available;
     };
@@ -354,7 +354,7 @@
 
     bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
         *buffer = nullptr;
-        ssize_t ret = findBufferSlot<wp<Codec2Buffer>>(
+        ssize_t ret = findBufferSlot<wp<LinearBlockBuffer>>(
                 &mBuffers, kMinBufferArraySize,
                 [] (const auto &elem) { return elem.promote() == nullptr; });
         if (ret < 0) {
@@ -363,7 +363,7 @@
         // TODO: proper max input size and usage
         // TODO: read usage from intf
         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
-        sp<Codec2Buffer> newBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
+        sp<LinearBlockBuffer> newBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
         if (newBuffer == nullptr) {
             return false;
         }
@@ -378,7 +378,7 @@
         if (it == mBuffers.end()) {
             return nullptr;
         }
-        sp<Codec2Buffer> codecBuffer = it->promote();
+        sp<LinearBlockBuffer> codecBuffer = it->promote();
         // We got sp<> reference from the caller so this should never happen..
         CHECK(codecBuffer != nullptr);
         return std::make_shared<Buffer1D>(codecBuffer->share());
@@ -394,7 +394,7 @@
         const size_t size = std::max(kMinBufferArraySize, mBuffers.size());
         mBuffers.resize(size);
         for (size_t i = 0; i < size; ++i) {
-            sp<Codec2Buffer> clientBuffer = mBuffers[i].promote();
+            sp<LinearBlockBuffer> clientBuffer = mBuffers[i].promote();
             bool available = false;
             if (clientBuffer == nullptr) {
                 // TODO: proper max input size
@@ -414,7 +414,7 @@
 private:
     // Buffers we passed to the client. The index of a buffer matches what
     // was passed in BufferCallback::onInputBufferAvailable().
-    std::vector<wp<Codec2Buffer>> mBuffers;
+    std::vector<wp<LinearBlockBuffer>> mBuffers;
 };
 
 class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
@@ -617,9 +617,7 @@
         if (ret < 0) {
             return false;
         }
-        sp<MediaCodecBuffer> newBuffer = new MediaCodecBuffer(
-                mFormat,
-                convert(buffer));
+        sp<MediaCodecBuffer> newBuffer = convert(buffer);
         mBuffers[ret] = { newBuffer, buffer };
         *index = ret;
         *codecBuffer = newBuffer;
@@ -669,7 +667,7 @@
         // track of the flushed work.
     }
 
-    virtual sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) = 0;
+    virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) = 0;
 
 protected:
     struct BufferInfo {
@@ -687,9 +685,9 @@
 public:
     using FlexOutputBuffers::FlexOutputBuffers;
 
-    virtual sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
+    virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
         if (buffer == nullptr) {
-            return new ABuffer(nullptr, 0);
+            return new MediaCodecBuffer(mFormat, new ABuffer(nullptr, 0));
         }
         if (buffer->data().type() != C2BufferData::LINEAR) {
             // We expect linear output buffers from the component.
@@ -699,16 +697,7 @@
             // We expect one and only one linear block from the component.
             return nullptr;
         }
-        C2ReadView view = buffer->data().linearBlocks().front().map().get();
-        if (view.error() != C2_OK) {
-            // Mapping the linear block failed
-            return nullptr;
-        }
-        return new ABuffer(
-                // XXX: the data is supposed to be read-only. We don't have
-                // const equivalent of ABuffer however...
-                const_cast<uint8_t *>(view.data()),
-                view.capacity());
+        return ConstLinearBlockBuffer::allocate(mFormat, buffer->data().linearBlocks().front());
     }
 
     std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
@@ -737,8 +726,9 @@
 public:
     using FlexOutputBuffers::FlexOutputBuffers;
 
-    sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
-        return buffer ? new ABuffer(nullptr, 1) : new ABuffer(nullptr, 0);
+    sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
+        return new MediaCodecBuffer(
+                mFormat, buffer ? new ABuffer(nullptr, 1) : new ABuffer(nullptr, 0));
     }
 
     std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index f479644..71b737b 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -21,6 +21,7 @@
 #include "include/CallbackDataSource.h"
 
 #include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
 #include <media/IDataSource.h>
 #include <media/stagefright/foundation/ADebug.h>
 
@@ -34,7 +35,10 @@
       mIsClosed(false) {
     // Set up the buffer to read into.
     mMemory = mIDataSource->getIMemory();
-    mName = String8::format("CallbackDataSource(%s)", mIDataSource->toString().string());
+    mName = String8::format("CallbackDataSource(%d->%d, %s)",
+            getpid(),
+            IPCThreadState::self()->getCallingPid(),
+            mIDataSource->toString().string());
 
 }
 
diff --git a/media/libstagefright/InterfaceUtils.cpp b/media/libstagefright/InterfaceUtils.cpp
index 284e63b..70fbbd7 100644
--- a/media/libstagefright/InterfaceUtils.cpp
+++ b/media/libstagefright/InterfaceUtils.cpp
@@ -38,11 +38,13 @@
 }
 
 sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
-        MediaExtractor *extractor, const sp<RefBase> &plugin) {
+        MediaExtractor *extractor,
+        const sp<DataSource> &source,
+        const sp<RefBase> &plugin) {
     if (extractor == nullptr) {
         return nullptr;
     }
-    return RemoteMediaExtractor::wrap(extractor, plugin);
+    return RemoteMediaExtractor::wrap(extractor, source, plugin);
 }
 
 sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source) {
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index e79696c..bb72167 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -118,7 +118,7 @@
     String8 tmp;
     float confidence;
     sp<ExtractorPlugin> plugin;
-    creator = sniff(source, &tmp, &confidence, &meta, plugin);
+    creator = sniff(source.get(), &tmp, &confidence, &meta, plugin);
     if (!creator) {
         ALOGV("FAILED to autodetect media content.");
         return NULL;
@@ -128,8 +128,8 @@
     ALOGV("Autodetected media content as '%s' with confidence %.2f",
          mime, confidence);
 
-    MediaExtractor *ret = creator(source, meta);
-    return CreateIMediaExtractorFromMediaExtractor(ret, plugin);
+    MediaExtractor *ret = creator(source.get(), meta);
+    return CreateIMediaExtractorFromMediaExtractor(ret, source, plugin);
 }
 
 //static
@@ -165,7 +165,7 @@
 
 // static
 MediaExtractor::CreatorFunc MediaExtractorFactory::sniff(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta,
+        DataSourceBase *source, String8 *mimeType, float *confidence, sp<AMessage> *meta,
         sp<ExtractorPlugin> &plugin) {
     *mimeType = "";
     *confidence = 0.0f;
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 3ebee51..601c9fa 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -37,9 +37,12 @@
 static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
 
 RemoteMediaExtractor::RemoteMediaExtractor(
-        MediaExtractor *extractor, const sp<RefBase> &plugin)
+        MediaExtractor *extractor,
+        const sp<DataSource> &source,
+        const sp<RefBase> &plugin)
     :mExtractor(extractor),
-    mExtractorPlugin(plugin) {
+     mSource(source),
+     mExtractorPlugin(plugin) {
 
     mAnalyticsItem = nullptr;
     if (MEDIA_LOG) {
@@ -67,6 +70,8 @@
 
 RemoteMediaExtractor::~RemoteMediaExtractor() {
     delete mExtractor;
+    mSource->close();
+    mSource.clear();
     mExtractorPlugin = nullptr;
     // log the current record, provided it has some information worth recording
     if (MEDIA_LOG) {
@@ -129,19 +134,17 @@
     return mExtractor->name();
 }
 
-void RemoteMediaExtractor::release() {
-    return mExtractor->release();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
 // static
 sp<IMediaExtractor> RemoteMediaExtractor::wrap(
-        MediaExtractor *extractor, const sp<RefBase> &plugin) {
+        MediaExtractor *extractor,
+        const sp<DataSource> &source,
+        const sp<RefBase> &plugin) {
     if (extractor == nullptr) {
         return nullptr;
     }
-    return new RemoteMediaExtractor(extractor, plugin);
+    return new RemoteMediaExtractor(extractor, source, plugin);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e2db0f5..179e0e6 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -47,12 +47,6 @@
 StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
     ALOGV("~StagefrightMetadataRetriever()");
     clearMetadata();
-    // Explicitly release extractor before continuing with the destructor,
-    // some extractors might need to callback to close off the DataSource
-    // and we need to make sure it's still there.
-    if (mExtractor != NULL) {
-        mExtractor->release();
-    }
     if (mSource != NULL) {
         mSource->close();
     }
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
index 442c89e..ab81cdc 100644
--- a/media/libstagefright/codec2/include/C2.h
+++ b/media/libstagefright/codec2/include/C2.h
@@ -189,6 +189,7 @@
 #define C2_CONST __attribute__((const))
 #define C2_HIDE __attribute__((visibility("hidden")))
 #define C2_INTERNAL __attribute__((internal_linkage))
+#define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer")))
 
 #define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
     inline bool operator!=(const type &other) const { return !(*this == other); } \
@@ -221,13 +222,13 @@
 template<typename T>
 struct C2_HIDE _c2_cntr_compat_helper {
     template<typename U, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline static constexpr T get(const U &value) {
         return T(value);
     }
 
     template<typename U, typename E=typename std::enable_if<(sizeof(U) >= sizeof(T))>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline static constexpr T get(const c2_cntr_t<U, void> &value) {
         return T(value.mValue);
     }
@@ -281,7 +282,7 @@
     /**
      * Peek as underlying signed type.
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr typename std::make_signed<T>::type peek() const {
         return static_cast<typename std::make_signed<T>::type>(mValue);
     }
@@ -296,7 +297,7 @@
     /**
      * Peek as long long - e.g. for printing.
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr long long peekll() const {
         return (long long)mValue;
     }
@@ -304,7 +305,7 @@
     /**
      * Peek as unsigned long long - e.g. for printing.
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr unsigned long long peekull() const {
         return (unsigned long long)mValue;
     }
@@ -352,24 +353,24 @@
         return c2_cntr_t<T, void>(mValue op); \
     }
 
-    DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), +, +=)
-    DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), -, -=)
-    DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), *, *=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, +, +=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, -, -=)
+    DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, *, *=)
 
-    DEFINE_C2_CNTR_UNARY_OP(__attribute__((no_sanitize("integer"))), -)
-    DEFINE_C2_CNTR_UNARY_OP(__attribute__((no_sanitize("integer"))), +)
+    DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, -)
+    DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, +)
 
-    DEFINE_C2_CNTR_CREMENT_OP(__attribute__((no_sanitize("integer"))), ++)
-    DEFINE_C2_CNTR_CREMENT_OP(__attribute__((no_sanitize("integer"))), --)
+    DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, ++)
+    DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, --)
 
     template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr c2_cntr_t<T> operator<<(const U &value) const {
         return c2_cntr_t<T>(mValue << value);
     }
 
     template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline c2_cntr_t<T> &operator<<=(const U &value) {
         mValue <<= value;
         return *this;
@@ -378,12 +379,12 @@
     /**
      * Comparison operators
      */
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr bool operator<=(const c2_cntr_t<T> &other) const {
         return T(other.mValue - mValue) < HALF_RANGE;
     }
 
-    __attribute__((no_sanitize("integer")))
+    C2_ALLOW_OVERFLOW
     inline constexpr bool operator>=(const c2_cntr_t<T> &other) const {
         return T(mValue - other.mValue) < HALF_RANGE;
     }
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 2ca8222..45ad17f 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -126,9 +126,16 @@
      */
     bool isHW() const;
 
+    /**
+     * Null-fence. A fence that has fired.
+     */
+    constexpr C2Fence() : mImpl(nullptr) { }
+
 private:
     class Impl;
     std::shared_ptr<Impl> mImpl;
+    C2Fence(const std::shared_ptr<Impl> &impl);
+    friend struct _C2FenceFactory;
 };
 
 /**
@@ -245,13 +252,101 @@
 **************************************************************************************************/
 
 /**
+ * Basic segment math support.
+ */
+struct C2Segment {
+    uint32_t offset;
+    uint32_t size;
+
+    inline constexpr C2Segment(uint32_t offset_, uint32_t size_)
+        : offset(offset_),
+          size(size_) {
+    }
+
+    inline constexpr bool isEmpty() const {
+        return size == 0;
+    }
+
+    inline constexpr bool isValid() const {
+        return offset <= ~size;
+    }
+
+    inline constexpr operator bool() const {
+        return isValid() && !isEmpty();
+    }
+
+    inline constexpr bool operator!() const {
+        return !bool(*this);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool contains(const C2Segment &other) const {
+        if (!isValid() || !other.isValid()) {
+            return false;
+        } else {
+            return offset <= other.offset
+                    && offset + size >= other.offset + other.size;
+        }
+    }
+
+    inline constexpr bool operator==(const C2Segment &other) const {
+        if (!isValid()) {
+            return !other.isValid();
+        } else {
+            return offset == other.offset && size == other.size;
+        }
+    }
+
+    inline constexpr bool operator!=(const C2Segment &other) const {
+        return !operator==(other);
+    }
+
+    inline constexpr bool operator>=(const C2Segment &other) const {
+        return contains(other);
+    }
+
+    inline constexpr bool operator>(const C2Segment &other) const {
+        return contains(other) && !operator==(other);
+    }
+
+    inline constexpr bool operator<=(const C2Segment &other) const {
+        return other.contains(*this);
+    }
+
+    inline constexpr bool operator<(const C2Segment &other) const {
+        return other.contains(*this) && !operator==(other);
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t end() const {
+        return offset + size;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr C2Segment intersect(const C2Segment &other) const {
+        if (!isValid()) {
+            return *this;
+        } else if (!other.isValid()) {
+            return other;
+        } else {
+            return C2Segment(c2_max(offset, other.offset),
+                             c2_min(end(), other.end()) - c2_max(offset, other.offset));
+        }
+    }
+};
+
+/**
  * Common aspect for all objects that have a linear capacity.
  */
 class _C2LinearCapacityAspect {
 /// \name Linear capacity interface
 /// @{
 public:
-    inline uint32_t capacity() const { return mCapacity; }
+    inline constexpr uint32_t capacity() const { return mCapacity; }
+
+    inline constexpr operator C2Segment() const {
+        return C2Segment(0, mCapacity);
+    }
 
 protected:
 
@@ -263,10 +358,10 @@
     inline explicit _C2LinearCapacityAspect(size_t capacity) = delete;
 #endif
 
-    inline explicit _C2LinearCapacityAspect(uint32_t capacity)
+    inline explicit constexpr _C2LinearCapacityAspect(uint32_t capacity)
       : mCapacity(capacity) { }
 
-    inline explicit _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
+    inline explicit constexpr _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
         : mCapacity(parent == nullptr ? 0 : parent->capacity()) { }
 
 private:
@@ -283,23 +378,35 @@
 /// \name Linear range interface
 /// @{
 public:
-    inline uint32_t offset() const { return mOffset; }
-    inline uint32_t endOffset() const { return mOffset + mSize; }
-    inline uint32_t size() const { return mSize; }
+    inline constexpr uint32_t offset() const { return mOffset; }
+    inline constexpr uint32_t endOffset() const { return mOffset + mSize; }
+    inline constexpr uint32_t size() const { return mSize; }
+
+    inline constexpr operator C2Segment() const {
+        return C2Segment(mOffset, mSize);
+    }
 
 protected:
-    inline explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
+    // capacity range [0, capacity]
+    inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
         : _C2LinearCapacityAspect(parent),
           mOffset(0),
           mSize(capacity()) { }
 
-    inline _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
+    // copy constructor (no error check)
+    inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect &other)
+        : _C2LinearCapacityAspect(other.capacity()),
+          mOffset(other.offset()),
+          mSize(other.size()) { }
+
+    // subrange of capacity [0, capacity] & [size, size + offset]
+    inline constexpr _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
         : _C2LinearCapacityAspect(parent),
           mOffset(c2_min(offset, capacity())),
           mSize(c2_min(size, capacity() - mOffset)) { }
 
     // subsection of the two [offset, offset + size] ranges
-    inline _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
+    inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
         : _C2LinearCapacityAspect(parent == nullptr ? 0 : parent->capacity()),
           mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
           mSize(c2_min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) { }
@@ -312,28 +419,31 @@
 /// @}
 };
 
-class C2_HIDE _C2LinearCapacityBase : public _C2LinearCapacityAspect {
-public:
-    inline explicit _C2LinearCapacityBase(size_t capacity)
-        : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) {}
-};
-
 /**
  * Utility class for safe range calculations.
  */
 class C2LinearRange : public _C2LinearRangeAspect {
 public:
-    inline C2LinearRange(const _C2LinearCapacityBase &parent, size_t offset, size_t size)
-        : _C2LinearRangeAspect(&parent, offset, size) {}
+    inline constexpr C2LinearRange(const _C2LinearCapacityAspect &parent, size_t offset, size_t size)
+        : _C2LinearRangeAspect(&parent, offset, size) { }
+
+    inline constexpr C2LinearRange(const _C2LinearRangeAspect &parent, size_t offset, size_t size)
+        : _C2LinearRangeAspect(&parent, offset, size) { }
+
+    inline constexpr C2LinearRange intersect(size_t offset, size_t size) const {
+        return C2LinearRange(*this, offset, size);
+    }
 };
 
 /**
  * Utility class for simple capacity and range construction.
  */
-class C2LinearCapacity : public _C2LinearCapacityBase {
+class C2LinearCapacity : public _C2LinearCapacityAspect {
 public:
-    using _C2LinearCapacityBase::_C2LinearCapacityBase;
-    inline C2LinearRange range(size_t offset, size_t size) {
+    inline constexpr explicit C2LinearCapacity(size_t capacity)
+        : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) { }
+
+    inline constexpr C2LinearRange range(size_t offset, size_t size) const {
         return C2LinearRange(*this, offset, size);
     }
 };
@@ -348,6 +458,9 @@
     inline explicit _C2EditableLinearRange(const _C2LinearCapacityAspect *parent)
         : _C2LinearRangeAspect(parent) { }
 
+    inline _C2EditableLinearRange(const _C2LinearRangeAspect &other)
+        : _C2LinearRangeAspect(other) { }
+
     inline _C2EditableLinearRange(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
         : _C2LinearRangeAspect(parent, offset, size) { }
 
@@ -379,6 +492,7 @@
         mOffset = offset;
         return true;
     }
+
     /**
      * Sets the size to |size|. Returns true if successful, which is equivalent to
      * if 0 <= |size| <= capacity() - offset().
@@ -394,6 +508,7 @@
             return true;
         }
     }
+
     /**
      * Sets the offset to |offset| with best effort. Same as setOffset() except that offset will
      * be clamped to the buffer capacity.
@@ -402,16 +517,9 @@
      * on the order of the operations. Always set offset first to ensure proper size.
      */
     inline void setOffset_be(uint32_t offset) {
-        if (offset > capacity()) {
-            offset = capacity();
-        }
-        if (offset > mOffset + mSize) {
-            mSize = 0;
-        } else {
-            mSize = mOffset + mSize - offset;
-        }
-        mOffset = offset;
+        (void)setOffset(c2_min(offset, capacity()));
     }
+
     /**
      * Sets the size to |size| with best effort. Same as setSize() except that the selected region
      * will be clamped to the buffer capacity (e.g. size is clamped to [0, capacity() - offset()]).
@@ -420,11 +528,471 @@
      * on the order of the operations. Always set offset first to ensure proper size.
      */
     inline void setSize_be(uint32_t size) {
-        mSize = std::min(size, capacity() - mOffset);
+        mSize = c2_min(size, capacity() - mOffset);
     }
 /// @}
 };
 
+/**************************************************************************************************
+  ALLOCATIONS
+**************************************************************************************************/
+
+/// \defgroup allocator Allocation and memory placement
+/// @{
+
+/**
+ * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
+ * buffer layout.
+ *
+ * \note This struct has public fields without getters/setters. All methods are inline.
+ */
+struct C2MemoryUsage {
+// public:
+    // TODO: match these to gralloc1.h
+    enum Consumer : uint64_t {
+        // \todo do we need to distinguish often from rarely?
+        CPU_READ          = GRALLOC_USAGE_SW_READ_OFTEN,
+        RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_READ   = GRALLOC_USAGE_HW_TEXTURE,
+        HW_COMPOSER_READ  = GRALLOC_USAGE_HW_COMPOSER,
+        HW_CODEC_READ     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        READ_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    enum Producer : uint64_t {
+        CPU_WRITE          = GRALLOC_USAGE_SW_WRITE_OFTEN,
+        RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
+        HW_TEXTURE_WRITE   = GRALLOC_USAGE_HW_RENDER,
+        HW_COMPOSER_WRITE  = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
+        HW_CODEC_WRITE     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+        WRITE_PROTECTED    = GRALLOC_USAGE_PROTECTED,
+    };
+
+    uint64_t consumer; // e.g. input
+    uint64_t producer; // e.g. output
+};
+
+class C2LinearAllocation;
+class C2GraphicAllocation;
+
+/**
+ *  Allocators are used by the framework to allocate memory (allocations) for buffers. They can
+ *  support either 1D or 2D allocations.
+ *
+ *  \note In theory they could support both, but in practice, we will use only one or the other.
+ *
+ *  Never constructed on stack.
+ *
+ *  Allocators are provided by vendors.
+ */
+class C2Allocator {
+public:
+    /**
+     * Allocator ID type.
+     */
+    typedef uint32_t id_t;
+    enum : id_t {
+        BAD_ID = 0xBADD, // invalid allocator ID
+    };
+
+    /**
+     * Allocation types. This is a bitmask and is used in C2Allocator::Info
+     * to list the supported allocation types of an allocator.
+     */
+    enum type_t : uint32_t {
+        LINEAR  = 1 << 0, //
+        GRAPHIC = 1 << 1,
+    };
+
+    /**
+     * Information about an allocator.
+     *
+     * Allocators don't have a query API so all queriable information is stored here.
+     */
+    struct Traits {
+        C2String name;              ///< allocator name
+        id_t id;                    ///< allocator ID
+        type_t supportedTypes;      ///< supported allocation types
+        C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
+        C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
+    };
+
+    /**
+     * Returns the unique name of this allocator.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the name of this allocator.
+     * \retval an empty string if there was not enough memory to allocate the actual name.
+     */
+    virtual C2String getName() const = 0;
+
+    /**
+     * Returns a unique ID for this allocator. This ID is used to get this allocator from the
+     * allocator store, and to identify this allocator across all processes.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a unique ID for this allocator.
+     */
+    virtual id_t getId() const = 0;
+
+    /**
+     * Returns the allocator traits.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * Allocators don't have a full-fledged query API, only this method.
+     *
+     * \return allocator information
+     */
+    virtual std::shared_ptr<const Traits> getTraits() const = 0;
+
+    /**
+     * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
+     * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param capacity      the size of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param usage         the memory usage info for the requested allocation. \note that the
+     *                      returned allocation may be later used/mapped with different usage.
+     *                      The allocator should layout the buffer to be optimized for this usage,
+     *                      but must support any usage. One exception: protected buffers can
+     *                      only be used in a protected scenario.
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
+     *                      will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete the allocation
+     * \retval C2_TIMED_OUT the allocation timed out
+     * \retval C2_REFUSED   no permission to complete the allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t newLinearAllocation(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
+     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param handle      the handle for the existing allocation
+     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
+     *                    will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was recreated successfully
+     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+     * \retval C2_REFUSED   no permission to recreate the allocation
+     * \retval C2_BAD_VALUE invalid handle (caller error)
+     * \retval C2_OMITTED   this allocator does not support 1D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t priorLinearAllocation(
+            const C2Handle *handle __unused,
+            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
+     * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param width         the width of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param height        the height of requested allocation (the allocation could be slightly
+     *                      larger, e.g. to account for any system-required alignment)
+     * \param format        the pixel format of requested allocation. This could be a vendor
+     *                      specific format.
+     * \param usage         the memory usage info for the requested allocation. \note that the
+     *                      returned allocation may be later used/mapped with different usage.
+     *                      The allocator should layout the buffer to be optimized for this usage,
+     *                      but must support any usage. One exception: protected buffers can
+     *                      only be used in a protected scenario.
+     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
+     *                      will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete the allocation
+     * \retval C2_TIMED_OUT the allocation timed out
+     * \retval C2_REFUSED   no permission to complete the allocation
+     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+     */
+    virtual c2_status_t newGraphicAllocation(
+            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+            C2MemoryUsage usage __unused,
+            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * (Re)creates a 2D allocation from a native handle.  If successful, the allocation is stored
+     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+     *
+     * \param handle      the handle for the existing allocation
+     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
+     *                    will be stored here on failure
+     *
+     * \retval C2_OK        the allocation was recreated successfully
+     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+     * \retval C2_REFUSED   no permission to recreate the allocation
+     * \retval C2_BAD_VALUE invalid handle (caller error)
+     * \retval C2_OMITTED   this allocator does not support 2D allocations
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
+     */
+    virtual c2_status_t priorGraphicAllocation(
+            const C2Handle *handle __unused,
+            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+        *allocation = nullptr;
+        return C2_OMITTED;
+    }
+
+protected:
+    C2Allocator() = default;
+
+    virtual ~C2Allocator() = default;
+};
+
+/**
+ * \ingroup linear allocator
+ * 1D allocation interface.
+ */
+class C2LinearAllocation : public _C2LinearCapacityAspect {
+public:
+    /**
+     * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
+     * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
+     * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
+     * safe to access the buffer contents, then -1.
+     *
+     * \param offset          starting position of the portion to be mapped (this does not have to
+     *                      be page aligned)
+     * \param size            size of the portion to be mapped (this does not have to be page
+     *                      aligned)
+     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
+     *                      kSoftwareWrite.
+     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
+     *                      not-null, and acquire fence FD will be stored here on success, or -1
+     *                      on failure. If null, the mapping will be synchronous.
+     * \param addr            a pointer to where the starting address of the mapped portion will be
+     *                      stored. On failure, nullptr will be stored here.
+     *
+     * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
+     *       is no need for this for 1D buffers.
+     * \todo Do we need to support sync operation as we could just wait for the fence?
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_REFUSED   no permission to map the portion
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_DUPLICATE if the allocation is already mapped.
+     * \retval C2_NO_MEMORY not enough memory to complete the operation
+     * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
+     *                      the usage flags are invalid (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     */
+    virtual c2_status_t map(
+            size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
+            void **addr /* nonnull */) = 0;
+
+    /**
+     * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
+     * passed to |map|; otherwise, this operation is a no-op.
+     *
+     * \param addr            starting address of the mapped region
+     * \param size            size of the mapped region
+     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
+     *                      not-null, a release fence FD will be stored here on success, or -1
+     *                      on failure. This fence signals when the original allocation contains
+     *                      any changes that happened to the mapped region. If null, the unmapping
+     *                      will be synchronous.
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NOT_FOUND if the allocation was not mapped previously.
+     * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
+     *                      regions (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
+     */
+    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
+
+    /**
+     * Returns the allocator ID for this allocation. This is useful to put the handle into context.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Returns a pointer to the allocation handle.
+     */
+    virtual const C2Handle *handle() const = 0;
+
+    /**
+     * Returns true if this is the same allocation as |other|.
+     */
+    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
+
+protected:
+    // \todo should we limit allocation directly?
+    C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
+    virtual ~C2LinearAllocation() = default;
+};
+
+class C2CircularBlock;
+class C2LinearBlock;
+class C2GraphicBlock;
+
+/**
+ *  Block pools are used by components to obtain output buffers in an efficient way. They can
+ *  support either linear (1D), circular (1D) or graphic (2D) blocks.
+ *
+ *  Block pools decouple the recycling of memory/allocations from the components. They are meant to
+ *  be an opaque service (there are no public APIs other than obtaining blocks) provided by the
+ *  platform. Block pools are also meant to decouple allocations from memory used by buffers. This
+ *  is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
+ *  their name suggest, block pools maintain a pool of memory blocks. When a component asks for
+ *  a memory block, pools will try to return a free memory block already in the pool. If no such
+ *  block exists, they will allocate memory using the backing allocator and allot a block on that
+ *  allocation. When blocks are no longer used in the system, they are recycled back to the block
+ *  pool and are available as free blocks.
+ *
+ *  Never constructed on stack.
+ */
+class C2BlockPool {
+public:
+    /**
+     * Block pool ID type.
+     */
+    typedef uint64_t local_id_t;
+
+    enum : local_id_t {
+        BASIC_LINEAR = 0,  ///< ID of basic (unoptimized) block pool for fetching 1D blocks
+        BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
+        PLATFORM_START = 0x10,
+    };
+
+    /**
+     * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
+     * It is only valid in the current process.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return a local ID for this block pool.
+     */
+    virtual local_id_t getLocalId() const = 0;
+
+    /**
+     * Returns the ID of the backing allocator of this block pool.
+     *
+     * This method MUST be "non-blocking" and return within 1ms.
+     *
+     * \return the ID of the backing allocator of this block pool.
+     */
+    virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+    /**
+     * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
+     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param capacity the size of requested block.
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr will
+     *                 be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this pool does not support linear blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchLinearBlock(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
+     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param capacity the size of requested circular block. (note: the size of the obtained
+     *                 block could be slightly larger, e.g. to accommodate any system-required
+     *                 alignment)
+     * \param usage    the memory usage info for the requested block. Returned blocks will be
+     *                 optimized for this usage, but may be used with any usage. One exception:
+     *                 protected blocks/buffers can only be used in a protected scenario.
+     * \param block    pointer to where the obtained block shall be stored on success. nullptr
+     *                 will be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+     * \retval C2_OMITTED   this pool does not support circular blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchCircularBlock(
+            uint32_t capacity __unused, C2MemoryUsage usage __unused,
+            std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+    /**
+     * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
+     * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+     *
+     * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
+     *               to accommodate any system-required alignment)
+     * \param height the height of requested block (the obtained block could be slightly larger,
+     *               e.g. to accommodate any system-required alignment)
+     * \param format the pixel format of requested block. This could be a vendor specific format.
+     * \param usage  the memory usage info for the requested block. Returned blocks will be
+     *               optimized for this usage, but may be used with any usage. One exception:
+     *               protected blocks/buffers can only be used in a protected scenario.
+     * \param block  pointer to where the obtained block shall be stored on success. nullptr
+     *               will be stored here on failure
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_REFUSED   no permission to complete any required allocation
+     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
+     *                      error)
+     * \retval C2_OMITTED   this pool does not support 2D blocks
+     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+     */
+    virtual c2_status_t fetchGraphicBlock(
+            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+            C2MemoryUsage usage __unused,
+            std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+        *block = nullptr;
+        return C2_OMITTED;
+    }
+
+protected:
+    C2BlockPool() = default;
+
+    virtual ~C2BlockPool() = default;
+};
+
+/// @}
+
 // ================================================================================================
 //  BLOCKS
 // ================================================================================================
@@ -435,16 +1003,36 @@
 
 class C2LinearAllocation;
 
+/**
+ * A 1D block.
+ *
+ * \note capacity() is not meaningful for users of blocks; instead size() is the capacity of the
+ * usable portion. Use and offset() and size() if accessing the block directly through its handle
+ * to represent the allotted range of the underlying allocation to this block.
+ */
 class C2Block1D : public _C2LinearRangeAspect {
 public:
+    /**
+     * Returns the underlying handle for this allocation.
+     *
+     * \note that the block and its block pool has shared ownership of the handle
+     *       and if all references to the block are released, the underlying block
+     *       allocation may get reused even if a client keeps a clone of this handle.
+     */
     const C2Handle *handle() const;
 
-protected:
-    C2Block1D(std::shared_ptr<C2LinearAllocation> alloc);
-    C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+    /**
+     * Returns the allocator's ID that created the underlying allocation for this block. This
+     * provides the context for understanding the handle.
+     */
+    C2Allocator::id_t getAllocatorId() const;
 
-private:
+protected:
     class Impl;
+    /** construct a block. */
+    C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
+
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
 };
 
@@ -457,6 +1045,7 @@
 public:
     /**
      * \return pointer to the start of the block or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
      */
     const uint8_t *data() const;
 
@@ -476,13 +1065,20 @@
      */
     c2_status_t error() const;
 
+    /**
+     * Releases this view. This sets error to C2_NO_INIT.
+     */
+    //void release();
+
 protected:
-    C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data);
+    class Impl;
+    C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size);
     explicit C2ReadView(c2_status_t error);
 
 private:
-    class Impl;
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
+    uint32_t mOffset; /**< offset into the linear block backing this read view */
 };
 
 /**
@@ -496,11 +1092,13 @@
      * Start of the block.
      *
      * \return pointer to the start of the block or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
      */
     uint8_t *base();
 
     /**
      * \return pointer to the block at the current offset or nullptr on error.
+     *         This pointer is only valid during the lifetime of this view or until it is released.
      */
     uint8_t *data();
 
@@ -509,14 +1107,18 @@
      */
     c2_status_t error() const;
 
+    /**
+     * Releases this view. This sets error to C2_NO_INIT.
+     */
+    //void release();
+
 protected:
-    C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base);
+    class Impl;
+    C2WriteView(std::shared_ptr<Impl> impl);
     explicit C2WriteView(c2_status_t error);
 
 private:
-    class Impl;
-    /// \todo should this be unique_ptr to make this movable only - to avoid inconsistent regions
-    /// between copies.
+    friend struct _C2BlockFactory;
     std::shared_ptr<Impl> mImpl;
 };
 
@@ -554,12 +1156,10 @@
     C2Fence fence() const { return mFence; }
 
 protected:
-    C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
-    C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+    C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence mFence);
 
 private:
-    class Impl;
-    std::shared_ptr<Impl> mImpl;
+    friend struct _C2BlockFactory;
     C2Fence mFence;
 };
 
@@ -589,12 +1189,9 @@
     C2ConstLinearBlock share(size_t offset, size_t size, C2Fence fence);
 
 protected:
-    C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
-    C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+    C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
 
-private:
-    class Impl;
-    std::shared_ptr<Impl> mImpl;
+    friend struct _C2BlockFactory;
 };
 
 /// @}
@@ -800,27 +1397,26 @@
 
     // utility methods
 
-    inline bool isEmpty() const {
+    inline constexpr bool isEmpty() const {
         return width == 0 || height == 0;
     }
 
-    inline bool isValid() const {
+    inline constexpr bool isValid() const {
         return left <= ~width && top <= ~height;
     }
 
-    inline operator bool() const {
+    inline constexpr operator bool() const {
         return isValid() && !isEmpty();
     }
 
-    inline bool operator!() const {
+    inline constexpr bool operator!() const {
         return !bool(*this);
     }
 
-    inline bool contains(const C2Rect &other) const {
+    C2_ALLOW_OVERFLOW
+    inline constexpr bool contains(const C2Rect &other) const {
         if (!isValid() || !other.isValid()) {
             return false;
-        } else if (other.isEmpty()) {
-            return true;
         } else {
             return left <= other.left && top <= other.top
                     && left + width >= other.left + other.width
@@ -828,36 +1424,58 @@
         }
     }
 
-    inline bool operator==(const C2Rect &other) const {
+    inline constexpr bool operator==(const C2Rect &other) const {
         if (!isValid()) {
             return !other.isValid();
-        } else if (isEmpty()) {
-            return other.isEmpty();
         } else {
             return left == other.left && top == other.top
                     && width == other.width && height == other.height;
         }
     }
 
-    inline bool operator!=(const C2Rect &other) const {
+    inline constexpr bool operator!=(const C2Rect &other) const {
         return !operator==(other);
     }
 
-    inline bool operator>=(const C2Rect &other) const {
+    inline constexpr bool operator>=(const C2Rect &other) const {
         return contains(other);
     }
 
-    inline bool operator>(const C2Rect &other) const {
+    inline constexpr bool operator>(const C2Rect &other) const {
         return contains(other) && !operator==(other);
     }
 
-    inline bool operator<=(const C2Rect &other) const {
+    inline constexpr bool operator<=(const C2Rect &other) const {
         return other.contains(*this);
     }
 
-    inline bool operator<(const C2Rect &other) const {
+    inline constexpr bool operator<(const C2Rect &other) const {
         return other.contains(*this) && !operator==(other);
     }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t right() const {
+        return left + width;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr uint32_t bottom() const {
+        return top + height;
+    }
+
+    C2_ALLOW_OVERFLOW
+    inline constexpr C2Rect intersect(const C2Rect &other) const {
+        if (!isValid()) {
+            return *this;
+        } else if (!other.isValid()) {
+            return other;
+        } else {
+            return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
+                          c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
+                          c2_max(left, other.left),
+                          c2_max(top, other.top));
+        }
+    }
 };
 
 /**
@@ -1008,6 +1626,88 @@
 /// @}
 };
 
+/**
+ * \ingroup graphic allocator
+ * 2D allocation interface.
+ */
+class C2GraphicAllocation : public _C2PlanarCapacityAspect {
+public:
+    /**
+     * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
+     * memory for flexible access. On success, it fills out |layout| with the plane specifications
+     * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
+     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
+     * descriptor referring to an acquire sync fence object. If it is already safe to access the
+     * buffer contents, then -1.
+     *
+     * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
+     * from gralloc1 limitation.)
+     *
+     * \param rect            section to be mapped (this does not have to be aligned)
+     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
+     *                      kSoftwareWrite.
+     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
+     *                      not-null, and acquire fence FD will be stored here on success, or -1
+     *                      on failure. If null, the mapping will be synchronous.
+     * \param layout          a pointer to where the mapped planes' descriptors will be
+     *                      stored. On failure, nullptr will be stored here.
+     *
+     * \todo Do we need to support sync operation as we could just wait for the fence?
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_REFUSED   no permission to map the section
+     * \retval C2_DUPLICATE there is already a mapped region (caller error)
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NO_MEMORY not enough memory to complete the operation
+     * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
+     *                      usage flags are invalid (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+
+     */
+    virtual c2_status_t map(
+            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+            // TODO: return <addr, size> buffers with plane sizes
+            C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
+
+    /**
+     * Unmaps the last mapped rectangular section.
+     *
+     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
+     *                      not-null, a release fence FD will be stored here on success, or -1
+     *                      on failure. This fence signals when the original allocation contains
+     *                      any changes that happened to the mapped section. If null, the unmapping
+     *                      will be synchronous.
+     *
+     * \retval C2_OK        the operation was successful
+     * \retval C2_TIMED_OUT the operation timed out
+     * \retval C2_NOT_FOUND there is no mapped region (caller error)
+     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+     * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
+     */
+    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
+
+    /**
+     * Returns true if this is a valid allocation.
+     *
+     * \todo remove?
+     */
+    virtual bool isValid() const = 0;
+
+    /**
+     * Returns a pointer to the allocation handle.
+     */
+    virtual const C2Handle *handle() const = 0;
+
+    /**
+     * Returns true if this is the same allocation as |other|.
+     */
+    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
+
+protected:
+    using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
+    virtual ~C2GraphicAllocation() = default;
+};
+
 class C2GraphicAllocation;
 
 class C2Block2D : public _C2PlanarSection {
@@ -1323,9 +2023,33 @@
      * \return true iff there is a metadata with the parameter type attached to this buffer.
      */
     bool hasInfo(C2Param::Type index) const;
+
+    /**
+     * Removes a metadata from the buffer.
+     */
     std::shared_ptr<C2Info> removeInfo(C2Param::Type index);
     ///@}
 
+    /**
+     * Creates a buffer containing a single linear block.
+     *
+     * \param block the content of the buffer.
+     *
+     * \return shared pointer to the created buffer.
+     */
+    static std::shared_ptr<C2Buffer> CreateLinearBuffer(const C2ConstLinearBlock &block);
+
+    /**
+     * Creates a buffer containing a single graphic block.
+     *
+     * \param block the content of the buffer.
+     *
+     * \return shared pointer to the created buffer.
+     */
+    static std::shared_ptr<C2Buffer> CreateGraphicBuffer(const C2ConstGraphicBlock &block);
+
+
+
 protected:
     // no public constructor
     explicit C2Buffer(const std::vector<C2ConstLinearBlock> &blocks);
@@ -1361,540 +2085,6 @@
 
 /// @}
 
-/**************************************************************************************************
-  ALLOCATIONS
-**************************************************************************************************/
-
-/// \defgroup allocator Allocation and memory placement
-/// @{
-
-/**
- * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
- * buffer layout.
- *
- * \note This struct has public fields without getters/setters. All methods are inline.
- */
-struct C2MemoryUsage {
-// public:
-    // TODO: match these to gralloc1.h
-    enum Consumer : uint64_t {
-        // \todo do we need to distinguish often from rarely?
-        CPU_READ          = GRALLOC_USAGE_SW_READ_OFTEN,
-        RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
-        HW_TEXTURE_READ   = GRALLOC_USAGE_HW_TEXTURE,
-        HW_COMPOSER_READ  = GRALLOC_USAGE_HW_COMPOSER,
-        HW_CODEC_READ     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
-        READ_PROTECTED    = GRALLOC_USAGE_PROTECTED,
-    };
-
-    enum Producer : uint64_t {
-        CPU_WRITE          = GRALLOC_USAGE_SW_WRITE_OFTEN,
-        RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
-        HW_TEXTURE_WRITE   = GRALLOC_USAGE_HW_RENDER,
-        HW_COMPOSER_WRITE  = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
-        HW_CODEC_WRITE     = GRALLOC_USAGE_HW_VIDEO_ENCODER,
-        WRITE_PROTECTED    = GRALLOC_USAGE_PROTECTED,
-    };
-
-    uint64_t consumer; // e.g. input
-    uint64_t producer; // e.g. output
-};
-
-/**
- * \ingroup linear allocator
- * 1D allocation interface.
- */
-class C2LinearAllocation : public _C2LinearCapacityAspect {
-public:
-    /**
-     * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
-     * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
-     * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
-     * safe to access the buffer contents, then -1.
-     *
-     * \param offset          starting position of the portion to be mapped (this does not have to
-     *                      be page aligned)
-     * \param size            size of the portion to be mapped (this does not have to be page
-     *                      aligned)
-     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
-     *                      kSoftwareWrite.
-     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
-     * \param addr            a pointer to where the starting address of the mapped portion will be
-     *                      stored. On failure, nullptr will be stored here.
-     *
-     * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
-     *       is no need for this for 1D buffers.
-     * \todo Do we need to support sync operation as we could just wait for the fence?
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_REFUSED   no permission to map the portion
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_DUPLICATE if the allocation is already mapped.
-     * \retval C2_NO_MEMORY not enough memory to complete the operation
-     * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
-     *                      the usage flags are invalid (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     */
-    virtual c2_status_t map(
-            size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
-            void **addr /* nonnull */) = 0;
-
-    /**
-     * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
-     * passed to |map|; otherwise, this operation is a no-op.
-     *
-     * \param addr            starting address of the mapped region
-     * \param size            size of the mapped region
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
-     *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped region. If null, the unmapping
-     *                      will be synchronous.
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NOT_FOUND if the allocation was not mapped previously.
-     * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
-     *                      regions (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     * \retval C2_REFUSED   no permission to unmap the portion (unexpected - system)
-     */
-    virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
-
-    /**
-     * Returns true if this is a valid allocation.
-     *
-     * \todo remove?
-     */
-    virtual bool isValid() const = 0;
-
-    /**
-     * Returns a pointer to the allocation handle.
-     */
-    virtual const C2Handle *handle() const = 0;
-
-    /**
-     * Returns true if this is the same allocation as |other|.
-     */
-    virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
-
-protected:
-    // \todo should we limit allocation directly?
-    C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
-    virtual ~C2LinearAllocation() = default;
-};
-
-/**
- * \ingroup graphic allocator
- * 2D allocation interface.
- */
-class C2GraphicAllocation : public _C2PlanarCapacityAspect {
-public:
-    /**
-     * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
-     * memory for flexible access. On success, it fills out |layout| with the plane specifications
-     * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
-     * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
-     * descriptor referring to an acquire sync fence object. If it is already safe to access the
-     * buffer contents, then -1.
-     *
-     * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
-     * from gralloc1 limitation.)
-     *
-     * \param rect            section to be mapped (this does not have to be aligned)
-     * \param usage           the desired usage. \todo this must be kSoftwareRead and/or
-     *                      kSoftwareWrite.
-     * \param fenceFd         a pointer to a file descriptor if an async mapping is requested. If
-     *                      not-null, and acquire fence FD will be stored here on success, or -1
-     *                      on failure. If null, the mapping will be synchronous.
-     * \param layout          a pointer to where the mapped planes' descriptors will be
-     *                      stored. On failure, nullptr will be stored here.
-     *
-     * \todo Do we need to support sync operation as we could just wait for the fence?
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_REFUSED   no permission to map the section
-     * \retval C2_DUPLICATE there is already a mapped region (caller error)
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NO_MEMORY not enough memory to complete the operation
-     * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
-     *                      usage flags are invalid (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-
-     */
-    virtual c2_status_t map(
-            C2Rect rect, C2MemoryUsage usage, int *fenceFd,
-            // TODO: return <addr, size> buffers with plane sizes
-            C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
-
-    /**
-     * Unmaps the last mapped rectangular section.
-     *
-     * \param fenceFd         a pointer to a file descriptor if an async unmapping is requested. If
-     *                      not-null, a release fence FD will be stored here on success, or -1
-     *                      on failure. This fence signals when the original allocation contains
-     *                      any changes that happened to the mapped section. If null, the unmapping
-     *                      will be synchronous.
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_NOT_FOUND there is no mapped region (caller error)
-     * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-     * \retval C2_REFUSED   no permission to unmap the section (unexpected - system)
-     */
-    virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
-
-    /**
-     * Returns true if this is a valid allocation.
-     *
-     * \todo remove?
-     */
-    virtual bool isValid() const = 0;
-
-    /**
-     * Returns a pointer to the allocation handle.
-     */
-    virtual const C2Handle *handle() const = 0;
-
-    /**
-     * Returns true if this is the same allocation as |other|.
-     */
-    virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
-
-protected:
-    using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
-    virtual ~C2GraphicAllocation() = default;
-};
-
-/**
- *  Allocators are used by the framework to allocate memory (allocations) for buffers. They can
- *  support either 1D or 2D allocations.
- *
- *  \note In theory they could support both, but in practice, we will use only one or the other.
- *
- *  Never constructed on stack.
- *
- *  Allocators are provided by vendors.
- */
-class C2Allocator {
-public:
-    /**
-     * Allocator ID type.
-     */
-    typedef uint32_t id_t;
-
-    /**
-     * Allocation types. This is a bitmask and is used in C2Allocator::Info
-     * to list the supported allocation types of an allocator.
-     */
-    enum type_t : uint32_t {
-        LINEAR  = 1 << 0, //
-        GRAPHIC = 1 << 1,
-    };
-
-    /**
-     * Information about an allocator.
-     *
-     * Allocators don't have a query API so all queriable information is stored here.
-     */
-    struct Traits {
-        C2String name;              ///< allocator name
-        id_t id;                    ///< allocator ID
-        type_t supportedTypes;      ///< supported allocation types
-        C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
-        C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
-    };
-
-    /**
-     * Returns the unique name of this allocator.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return the name of this allocator.
-     * \retval an empty string if there was not enough memory to allocate the actual name.
-     */
-    virtual C2String getName() const = 0;
-
-    /**
-     * Returns a unique ID for this allocator. This ID is used to get this allocator from the
-     * allocator store, and to identify this allocator across all processes.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return a unique ID for this allocator.
-     */
-    virtual id_t getId() const = 0;
-
-    /**
-     * Returns the allocator traits.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * Allocators don't have a full-fledged query API, only this method.
-     *
-     * \return allocator information
-     */
-    virtual std::shared_ptr<const Traits> getTraits() const = 0;
-
-    /**
-     * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
-     * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param capacity      the size of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param usage         the memory usage info for the requested allocation. \note that the
-     *                      returned allocation may be later used/mapped with different usage.
-     *                      The allocator should layout the buffer to be optimized for this usage,
-     *                      but must support any usage. One exception: protected buffers can
-     *                      only be used in a protected scenario.
-     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
-     *                      will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete the allocation
-     * \retval C2_TIMED_OUT the allocation timed out
-     * \retval C2_REFUSED   no permission to complete the allocation
-     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this allocator does not support 1D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
-     */
-    virtual c2_status_t newLinearAllocation(
-            uint32_t capacity __unused, C2MemoryUsage usage __unused,
-            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
-     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param handle      the handle for the existing allocation
-     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
-     *                    will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was recreated successfully
-     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
-     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
-     * \retval C2_REFUSED   no permission to recreate the allocation
-     * \retval C2_BAD_VALUE invalid handle (caller error)
-     * \retval C2_OMITTED   this allocator does not support 1D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
-     */
-    virtual c2_status_t priorLinearAllocation(
-            const C2Handle *handle __unused,
-            std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
-     * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param width         the width of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param height        the height of requested allocation (the allocation could be slightly
-     *                      larger, e.g. to account for any system-required alignment)
-     * \param format        the pixel format of requested allocation. This could be a vendor
-     *                      specific format.
-     * \param usage         the memory usage info for the requested allocation. \note that the
-     *                      returned allocation may be later used/mapped with different usage.
-     *                      The allocator should layout the buffer to be optimized for this usage,
-     *                      but must support any usage. One exception: protected buffers can
-     *                      only be used in a protected scenario.
-     * \param allocation    pointer to where the allocation shall be stored on success. nullptr
-     *                      will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete the allocation
-     * \retval C2_TIMED_OUT the allocation timed out
-     * \retval C2_REFUSED   no permission to complete the allocation
-     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this allocator does not support 2D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
-     */
-    virtual c2_status_t newGraphicAllocation(
-            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
-            C2MemoryUsage usage __unused,
-            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * (Re)creates a 2D allocation from a native handle.  If successful, the allocation is stored
-     * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
-     *
-     * \param handle      the handle for the existing allocation
-     * \param allocation  pointer to where the allocation shall be stored on success. nullptr
-     *                    will be stored here on failure
-     *
-     * \retval C2_OK        the allocation was recreated successfully
-     * \retval C2_NO_MEMORY not enough memory to recreate the allocation
-     * \retval C2_TIMED_OUT the recreation timed out (unexpected)
-     * \retval C2_REFUSED   no permission to recreate the allocation
-     * \retval C2_BAD_VALUE invalid handle (caller error)
-     * \retval C2_OMITTED   this allocator does not support 2D allocations
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
-     */
-    virtual c2_status_t priorGraphicAllocation(
-            const C2Handle *handle __unused,
-            std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
-        *allocation = nullptr;
-        return C2_OMITTED;
-    }
-
-protected:
-    C2Allocator() = default;
-
-    virtual ~C2Allocator() = default;
-};
-
-/**
- *  Block pools are used by components to obtain output buffers in an efficient way. They can
- *  support either linear (1D), circular (1D) or graphic (2D) blocks.
- *
- *  Block pools decouple the recycling of memory/allocations from the components. They are meant to
- *  be an opaque service (there are no public APIs other than obtaining blocks) provided by the
- *  platform. Block pools are also meant to decouple allocations from memory used by buffers. This
- *  is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
- *  their name suggest, block pools maintain a pool of memory blocks. When a component asks for
- *  a memory block, pools will try to return a free memory block already in the pool. If no such
- *  block exists, they will allocate memory using the backing allocator and allot a block on that
- *  allocation. When blocks are no longer used in the system, they are recycled back to the block
- *  pool and are available as free blocks.
- *
- *  Never constructed on stack.
- */
-class C2BlockPool {
-public:
-    /**
-     * Block pool ID type.
-     */
-    typedef uint64_t local_id_t;
-
-    enum : local_id_t {
-        BASIC_LINEAR = 0,  ///< ID of basic (unoptimized) block pool for fetching 1D blocks
-        BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
-        PLATFORM_START = 0x10,
-    };
-
-    /**
-     * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
-     * It is only valid in the current process.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return a local ID for this block pool.
-     */
-    virtual local_id_t getLocalId() const = 0;
-
-    /**
-     * Returns the ID of the backing allocator of this block pool.
-     *
-     * This method MUST be "non-blocking" and return within 1ms.
-     *
-     * \return the ID of the backing allocator of this block pool.
-     */
-    virtual C2Allocator::id_t getAllocatorId() const = 0;
-
-    /**
-     * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
-     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
-     *
-     * \param capacity the size of requested block.
-     * \param usage    the memory usage info for the requested block. Returned blocks will be
-     *                 optimized for this usage, but may be used with any usage. One exception:
-     *                 protected blocks/buffers can only be used in a protected scenario.
-     * \param block    pointer to where the obtained block shall be stored on success. nullptr will
-     *                 be stored here on failure
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_REFUSED   no permission to complete any required allocation
-     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this pool does not support linear blocks
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
-     */
-    virtual c2_status_t fetchLinearBlock(
-            uint32_t capacity __unused, C2MemoryUsage usage __unused,
-            std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
-        *block = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
-     * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
-     *
-     * \param capacity the size of requested circular block. (note: the size of the obtained
-     *                 block could be slightly larger, e.g. to accommodate any system-required
-     *                 alignment)
-     * \param usage    the memory usage info for the requested block. Returned blocks will be
-     *                 optimized for this usage, but may be used with any usage. One exception:
-     *                 protected blocks/buffers can only be used in a protected scenario.
-     * \param block    pointer to where the obtained block shall be stored on success. nullptr
-     *                 will be stored here on failure
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_REFUSED   no permission to complete any required allocation
-     * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
-     * \retval C2_OMITTED   this pool does not support circular blocks
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
-     */
-    virtual c2_status_t fetchCircularBlock(
-            uint32_t capacity __unused, C2MemoryUsage usage __unused,
-            std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
-        *block = nullptr;
-        return C2_OMITTED;
-    }
-
-    /**
-     * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
-     * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
-     *
-     * \param width  the width of requested block (the obtained block could be slightly larger, e.g.
-     *               to accommodate any system-required alignment)
-     * \param height the height of requested block (the obtained block could be slightly larger,
-     *               e.g. to accommodate any system-required alignment)
-     * \param format the pixel format of requested block. This could be a vendor specific format.
-     * \param usage  the memory usage info for the requested block. Returned blocks will be
-     *               optimized for this usage, but may be used with any usage. One exception:
-     *               protected blocks/buffers can only be used in a protected scenario.
-     * \param block  pointer to where the obtained block shall be stored on success. nullptr
-     *               will be stored here on failure
-     *
-     * \retval C2_OK        the operation was successful
-     * \retval C2_NO_MEMORY not enough memory to complete any required allocation
-     * \retval C2_TIMED_OUT the operation timed out
-     * \retval C2_REFUSED   no permission to complete any required allocation
-     * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
-     *                      error)
-     * \retval C2_OMITTED   this pool does not support 2D blocks
-     * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
-     */
-    virtual c2_status_t fetchGraphicBlock(
-            uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
-            C2MemoryUsage usage __unused,
-            std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
-        *block = nullptr;
-        return C2_OMITTED;
-    }
-
-protected:
-    C2BlockPool() = default;
-
-    virtual ~C2BlockPool() = default;
-};
-
-/// @}
-
 /// \cond INTERNAL
 
 /// \todo These are no longer used
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index aa0974a..721966b 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -696,6 +696,7 @@
         DEFAULT_GRAPHIC,    ///< basic graphic allocator type
         PLATFORM_START = 0x10,
         VENDOR_START   = 0x100,
+        BAD_ID         = C2Allocator::BAD_ID, ///< DO NOT USE
     };
 
     /**
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index a310717..2de43c8 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -29,10 +29,10 @@
 class C2BufferTest : public ::testing::Test {
 public:
     C2BufferTest()
-        : mLinearAllocator(std::make_shared<C2AllocatorIon>()),
+        : mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
           mSize(0u),
           mAddr(nullptr),
-          mGraphicAllocator(std::make_shared<C2AllocatorGralloc>()) {
+          mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) {
     }
 
     ~C2BufferTest() = default;
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index a5ea511..155583d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -540,7 +540,7 @@
     return C2_OK;
 }
 
-C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+C2AllocatorGralloc::C2AllocatorGralloc(id_t) : mImpl(new Impl) {}
 
 C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
 
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index 34c68bb..4328a8d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -119,14 +119,14 @@
         size_t offset, size_t size, C2MemoryUsage usage, int *fence,
         void **addr /* nonnull */) override;
     virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd) override;
-    virtual bool isValid() const override;
     virtual ~C2AllocationIon() override;
     virtual const C2Handle *handle() const override;
+    virtual id_t getAllocatorId() const override;
     virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const override;
 
     // internal methods
-    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
-    C2AllocationIon(int ionFd, size_t size, int shareFd);
+    C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
+    C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id);
 
     c2_status_t status() const;
 
@@ -154,10 +154,11 @@
      *                  invalid if err is not 0.
      * \param err       errno during buffer allocation or import
      */
-    Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, int err)
+    Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
         : mIonFd(ionFd),
           mHandle(bufferFd, capacity),
           mBuffer(buffer),
+          mId(id),
           mInit(c2_map_errno<ENOMEM, EACCES, EINVAL>(err)),
           mMapFd(-1),
           mMapSize(0) {
@@ -183,10 +184,10 @@
      * \return created ion allocation (implementation) which may be invalid if the
      * import failed.
      */
-    static Impl *Import(int ionFd, size_t capacity, int bufferFd) {
+    static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id) {
         ion_user_handle_t buffer = -1;
         int ret = ion_import(ionFd, bufferFd, &buffer);
-        return new Impl(ionFd, capacity, bufferFd, buffer, ret);
+        return new Impl(ionFd, capacity, bufferFd, buffer, id, ret);
     }
 
     /**
@@ -201,7 +202,7 @@
      * \return created ion allocation (implementation) which may be invalid if the
      * allocation failed.
      */
-    static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags) {
+    static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
         int bufferFd = -1;
         ion_user_handle_t buffer = -1;
         int ret = ion_alloc(ionFd, size, align, heapMask, flags, &buffer);
@@ -213,7 +214,7 @@
                 buffer = -1;
             }
         }
-        return new Impl(ionFd, size, bufferFd, buffer, ret);
+        return new Impl(ionFd, size, bufferFd, buffer, id, ret);
     }
 
     c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
@@ -311,10 +312,19 @@
         return &mHandle;
     }
 
+    C2Allocator::id_t getAllocatorId() const {
+        return mId;
+    }
+
+    ion_user_handle_t ionHandle() const {
+        return mBuffer;
+    }
+
 private:
     int mIonFd;
     C2HandleIon mHandle;
     ion_user_handle_t mBuffer;
+    C2Allocator::id_t mId;
     c2_status_t mInit;
     int mMapFd; // only one for now
     void *mMapAddr;
@@ -331,17 +341,21 @@
     return mImpl->unmap(addr, size, fenceFd);
 }
 
-bool C2AllocationIon::isValid() const {
-    return mImpl->status() == C2_OK;
-}
-
 c2_status_t C2AllocationIon::status() const {
     return mImpl->status();
 }
 
+C2Allocator::id_t C2AllocationIon::getAllocatorId() const {
+    return mImpl->getAllocatorId();
+}
+
 bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
-    return other != nullptr &&
-        other->handle(); // TODO
+    if (!other || other->getAllocatorId() != getAllocatorId()) {
+        return false;
+    }
+    // get user handle to compare objects
+    std::shared_ptr<C2AllocationIon> otherAsIon = std::static_pointer_cast<C2AllocationIon>(other);
+    return mImpl->ionHandle() == otherAsIon->mImpl->ionHandle();
 }
 
 const C2Handle *C2AllocationIon::handle() const {
@@ -352,21 +366,28 @@
     delete mImpl;
 }
 
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align,
+                                 unsigned heapMask, unsigned flags, C2Allocator::id_t id)
     : C2LinearAllocation(size),
-      mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags)) { }
+      mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags, id)) { }
 
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id)
     : C2LinearAllocation(size),
-      mImpl(Impl::Import(ionFd, size, shareFd)) { }
+      mImpl(Impl::Import(ionFd, size, shareFd, id)) { }
 
 /* ======================================= ION ALLOCATOR ====================================== */
-C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
+C2AllocatorIon::C2AllocatorIon(id_t id)
+    : mInit(C2_OK),
+      mIonFd(ion_open()) {
     if (mIonFd < 0) {
         switch (errno) {
         case ENOENT:    mInit = C2_OMITTED; break;
         default:        mInit = c2_map_errno<EACCES>(errno); break;
         }
+    } else {
+        C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
+        Traits traits = { "android.allocator.ion", id, LINEAR, minUsage, maxUsage };
+        mTraits = std::make_shared<Traits>(traits);
     }
 }
 
@@ -377,11 +398,15 @@
 }
 
 C2Allocator::id_t C2AllocatorIon::getId() const {
-    return 0; /// \todo implement ID
+    return mTraits->id;
 }
 
 C2String C2AllocatorIon::getName() const {
-    return "android.allocator.ion";
+    return mTraits->name;
+}
+
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorIon::getTraits() const {
+    return mTraits;
 }
 
 c2_status_t C2AllocatorIon::newLinearAllocation(
@@ -410,7 +435,7 @@
 #endif
 
     std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags);
+        = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
     c2_status_t ret = alloc->status();
     if (ret == C2_OK) {
         *allocation = alloc;
@@ -432,7 +457,7 @@
     // TODO: get capacity and validate it
     const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
     std::shared_ptr<C2AllocationIon> alloc
-        = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd());
+        = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
     c2_status_t ret = alloc->status();
     if (ret == C2_OK) {
         *allocation = alloc;
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 4ab3e05..ff92679 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -21,49 +21,46 @@
 #include <map>
 
 #include <C2BufferPriv.h>
+#include <C2BlockInternal.h>
 
 namespace android {
 
 namespace {
 
+// This anonymous namespace contains the helper classes that allow our implementation to create
+// block/buffer objects.
+//
 // Inherit from the parent, share with the friend.
-
-class DummyCapacityAspect : public _C2LinearCapacityAspect {
-    using _C2LinearCapacityAspect::_C2LinearCapacityAspect;
-    friend class ::android::C2ReadView;
-    friend class ::android::C2ConstLinearBlock;
-};
-
-class C2DefaultReadView : public C2ReadView {
+class ReadViewBuddy : public C2ReadView {
     using C2ReadView::C2ReadView;
     friend class ::android::C2ConstLinearBlock;
 };
 
-class C2DefaultWriteView : public C2WriteView {
+class WriteViewBuddy : public C2WriteView {
     using C2WriteView::C2WriteView;
     friend class ::android::C2LinearBlock;
 };
 
-class C2AcquirableReadView : public C2Acquirable<C2ReadView> {
-    using C2Acquirable::C2Acquirable;
-    friend class ::android::C2ConstLinearBlock;
-};
-
-class C2AcquirableWriteView : public C2Acquirable<C2WriteView> {
-    using C2Acquirable::C2Acquirable;
-    friend class ::android::C2LinearBlock;
-};
-
-class C2DefaultConstLinearBlock : public C2ConstLinearBlock {
+class ConstLinearBlockBuddy : public C2ConstLinearBlock {
     using C2ConstLinearBlock::C2ConstLinearBlock;
     friend class ::android::C2LinearBlock;
 };
 
-class C2DefaultLinearBlock : public C2LinearBlock {
+class LinearBlockBuddy : public C2LinearBlock {
     using C2LinearBlock::C2LinearBlock;
     friend class ::android::C2BasicLinearBlockPool;
 };
 
+class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2ConstLinearBlock;
+};
+
+class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
+    using C2Acquirable::C2Acquirable;
+    friend class ::android::C2LinearBlock;
+};
+
 class C2DefaultGraphicView : public C2GraphicView {
     using C2GraphicView::C2GraphicView;
     friend class ::android::C2ConstGraphicBlock;
@@ -99,255 +96,230 @@
 
 /* ========================================== 1D BLOCK ========================================= */
 
-class C2Block1D::Impl {
+struct C2_HIDE _C2BlockPoolData;
+
+/**
+ * This class is the base class for all 1D block and view implementations.
+ *
+ * This is basically just a placeholder for the underlying 1D allocation and the range of the
+ * alloted portion to this block. There is also a placeholder for a blockpool data.
+ */
+class C2_HIDE _C2Block1DImpl : public _C2LinearRangeAspect {
 public:
-    const C2Handle *handle() const {
-        return mAllocation->handle();
+    _C2Block1DImpl(const std::shared_ptr<C2LinearAllocation> &alloc,
+            const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
+            size_t offset = 0, size_t size = ~(size_t)0)
+        : _C2LinearRangeAspect(alloc.get(), offset, size),
+          mAllocation(alloc),
+          mPoolData(poolData) { }
+
+    _C2Block1DImpl(const _C2Block1DImpl &other, size_t offset = 0, size_t size = ~(size_t)0)
+        : _C2LinearRangeAspect(&other, offset, size),
+          mAllocation(other.mAllocation),
+          mPoolData(other.mPoolData) { }
+
+    /** returns const pool data  */
+    std::shared_ptr<const _C2BlockPoolData> poolData() const {
+        return mPoolData;
     }
 
-    Impl(std::shared_ptr<C2LinearAllocation> alloc)
-        : mAllocation(alloc) {}
+    /** returns native handle */
+    const C2Handle *handle() const {
+        return mAllocation ? mAllocation->handle() : nullptr;
+    }
+
+    /** returns the allocator's ID */
+    C2Allocator::id_t getAllocatorId() const {
+        // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
+        return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
+    }
+
+    std::shared_ptr<C2LinearAllocation> getAllocation() const {
+        return mAllocation;
+    }
 
 private:
     std::shared_ptr<C2LinearAllocation> mAllocation;
+    std::shared_ptr<_C2BlockPoolData> mPoolData;
 };
 
-const C2Handle *C2Block1D::handle() const {
-    return mImpl->handle();
-};
-
-C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc)
-    : _C2LinearRangeAspect(alloc.get()), mImpl(new Impl(alloc)) {
-}
-
-C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
-    : _C2LinearRangeAspect(alloc.get(), offset, size), mImpl(new Impl(alloc)) {
-}
-
-class C2ReadView::Impl {
+/**
+ * This class contains the mapped data pointer, and the potential error.
+ *
+ * range is the mapped range of the underlying allocation (which is part of the allotted
+ * range).
+ */
+class C2_HIDE _C2MappedBlock1DImpl : public _C2Block1DImpl {
 public:
-    explicit Impl(const uint8_t *data)
-        : mData(data), mError(C2_OK) {}
+    _C2MappedBlock1DImpl(const _C2Block1DImpl &block, uint8_t *data,
+                         size_t offset = 0, size_t size = ~(size_t)0)
+        : _C2Block1DImpl(block, offset, size), mData(data), mError(C2_OK) { }
 
-    explicit Impl(c2_status_t error)
-        : mData(nullptr), mError(error) {}
+    _C2MappedBlock1DImpl(c2_status_t error)
+        : _C2Block1DImpl(nullptr), mData(nullptr), mError(error) {
+        // CHECK(error != C2_OK);
+    }
 
     const uint8_t *data() const {
         return mData;
     }
 
+    uint8_t *data() {
+        return mData;
+    }
+
     c2_status_t error() const {
         return mError;
     }
 
 private:
-    const uint8_t *mData;
+    uint8_t *mData;
     c2_status_t mError;
 };
 
-C2ReadView::C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data)
-    : _C2LinearCapacityAspect(parent), mImpl(std::make_shared<Impl>(data)) {}
+/**
+ * Block implementation.
+ */
+class C2Block1D::Impl : public _C2Block1DImpl {
+    using _C2Block1DImpl::_C2Block1DImpl;
+};
 
-C2ReadView::C2ReadView(c2_status_t error)
-    : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)) {}
+const C2Handle *C2Block1D::handle() const {
+    return mImpl->handle();
+};
 
-const uint8_t *C2ReadView::data() const {
-    return mImpl->data();
+C2Allocator::id_t C2Block1D::getAllocatorId() const {
+    return mImpl->getAllocatorId();
+};
+
+C2Block1D::C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+    // always clamp subrange to parent (impl) range for safety
+    : _C2LinearRangeAspect(impl.get(), range.offset(), range.size()), mImpl(impl) {
 }
 
-C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
-    if (offset > capacity()) {
-        offset = capacity();
-    }
-    if (size > capacity() - offset) {
-        size = capacity() - offset;
-    }
-    // TRICKY: newCapacity will just be used to grab the size.
-    DummyCapacityAspect newCapacity((uint32_t)size);
-    return C2ReadView(&newCapacity, data() + offset);
+/**
+ * Read view implementation.
+ *
+ * range of Impl is the mapped range of the underlying allocation (which is part of the allotted
+ * range). range of View is 0 to capacity() (not represented as an actual range). This maps to a
+ * subrange of Impl range starting at mImpl->offset() + _mOffset.
+ */
+class C2ReadView::Impl : public _C2MappedBlock1DImpl {
+    using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
+};
+
+C2ReadView::C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size)
+    : _C2LinearCapacityAspect(C2LinearCapacity(impl->size()).range(offset, size).size()),
+      mImpl(impl),
+      mOffset(C2LinearCapacity(impl->size()).range(offset, size).offset()) { }
+
+C2ReadView::C2ReadView(c2_status_t error)
+    : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)), mOffset(0u) {
+    // CHECK(error != C2_OK);
+}
+
+const uint8_t *C2ReadView::data() const {
+    return mImpl->error() ? nullptr : mImpl->data() + mOffset;
 }
 
 c2_status_t C2ReadView::error() const {
     return mImpl->error();
 }
 
-class C2WriteView::Impl {
-public:
-    explicit Impl(uint8_t *base)
-        : mBase(base), mError(C2_OK) {}
+C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
+    C2LinearRange subRange(*this, offset, size);
+    return C2ReadView(mImpl, mOffset + subRange.offset(), subRange.size());
+}
 
-    explicit Impl(c2_status_t error)
-        : mBase(nullptr), mError(error) {}
-
-    uint8_t *base() const {
-        return mBase;
-    }
-
-    c2_status_t error() const {
-        return mError;
-    }
-
-private:
-    uint8_t *mBase;
-    c2_status_t mError;
+/**
+ * Write view implementation.
+ */
+class C2WriteView::Impl : public _C2MappedBlock1DImpl {
+    using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
 };
 
-C2WriteView::C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base)
-    : _C2EditableLinearRange(parent), mImpl(std::make_shared<Impl>(base)) {}
+C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
+// UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
+// this is what we have to do.
+    : _C2EditableLinearRange(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
 
 C2WriteView::C2WriteView(c2_status_t error)
     : _C2EditableLinearRange(nullptr), mImpl(std::make_shared<Impl>(error)) {}
 
-uint8_t *C2WriteView::base() { return mImpl->base(); }
+uint8_t *C2WriteView::base() { return mImpl->data(); }
 
-uint8_t *C2WriteView::data() { return mImpl->base() + offset(); }
+uint8_t *C2WriteView::data() { return mImpl->data() + offset(); }
 
 c2_status_t C2WriteView::error() const { return mImpl->error(); }
 
-class C2ConstLinearBlock::Impl {
-public:
-    explicit Impl(std::shared_ptr<C2LinearAllocation> alloc)
-        : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
-
-    ~Impl() {
-        if (mBase != nullptr) {
-            // TODO: fence
-            c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
-            if (err != C2_OK) {
-                // TODO: Log?
-            }
-        }
-    }
-
-    C2ConstLinearBlock subBlock(size_t offset, size_t size) const {
-        return C2ConstLinearBlock(mAllocation, offset, size);
-    }
-
-    void map(size_t offset, size_t size) {
-        if (mBase == nullptr) {
-            void *base = nullptr;
-            mError = mAllocation->map(
-                    offset, size, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
-            // TODO: fence
-            if (mError == C2_OK) {
-                mBase = (uint8_t *)base;
-                mSize = size;
-            }
-        }
-    }
-
-    const uint8_t *base() const { return mBase; }
-
-    c2_status_t error() const { return mError; }
-
-private:
-    std::shared_ptr<C2LinearAllocation> mAllocation;
-    uint8_t *mBase;
-    size_t mSize;
-    c2_status_t mError;
-};
-
-C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
-    : C2Block1D(alloc), mImpl(std::make_shared<Impl>(alloc)) {}
-
-C2ConstLinearBlock::C2ConstLinearBlock(
-        std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
-    : C2Block1D(alloc, offset, size), mImpl(std::make_shared<Impl>(alloc)) {}
+/**
+ * Const linear block implementation.
+ */
+C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence fence)
+    : C2Block1D(impl, range), mFence(fence) { }
 
 C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
-    mImpl->map(offset(), size());
-    if (mImpl->base() == nullptr) {
-        C2DefaultReadView view(mImpl->error());
-        return C2AcquirableReadView(mImpl->error(), mFence, view);
+    void *base = nullptr;
+    uint32_t len = size();
+    c2_status_t error = mImpl->getAllocation()->map(
+            offset(), len, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
+    // TODO: wait on fence
+    if (error == C2_OK) {
+        std::shared_ptr<ReadViewBuddy::Impl> rvi = std::shared_ptr<ReadViewBuddy::Impl>(
+                new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
+                [base, len](ReadViewBuddy::Impl *i) {
+                    (void)i->getAllocation()->unmap(base, len, nullptr);
+        });
+        return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
+    } else {
+        return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(error));
     }
-    DummyCapacityAspect newCapacity(size());
-    C2DefaultReadView view(&newCapacity, mImpl->base());
-    return C2AcquirableReadView(mImpl->error(), mFence, view);
 }
 
-C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset, size_t size) const {
-    return mImpl->subBlock(offset, size);
+C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset_, size_t size_) const {
+    C2LinearRange subRange(*mImpl, offset_, size_);
+    return C2ConstLinearBlock(mImpl, subRange, mFence);
 }
 
-class C2LinearBlock::Impl {
-public:
-    Impl(std::shared_ptr<C2LinearAllocation> alloc)
-        : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
-
-    ~Impl() {
-        if (mBase != nullptr) {
-            // TODO: fence
-            c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
-            if (err != C2_OK) {
-                // TODO: Log?
-            }
-        }
-    }
-
-    void map(size_t capacity) {
-        if (mBase == nullptr) {
-            void *base = nullptr;
-            // TODO: fence
-            mError = mAllocation->map(
-                    0u,
-                    capacity,
-                    { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
-                    nullptr,
-                    &base);
-            if (mError == C2_OK) {
-                mBase = (uint8_t *)base;
-                mSize = capacity;
-            }
-        }
-    }
-
-    C2ConstLinearBlock share(size_t offset, size_t size, C2Fence &fence) {
-        // TODO
-        (void) fence;
-        return C2DefaultConstLinearBlock(mAllocation, offset, size);
-    }
-
-    uint8_t *base() const { return mBase; }
-
-    c2_status_t error() const { return mError; }
-
-    C2Fence fence() const { return mFence; }
-
-private:
-    std::shared_ptr<C2LinearAllocation> mAllocation;
-    uint8_t *mBase;
-    size_t mSize;
-    c2_status_t mError;
-    C2Fence mFence;
-};
-
-C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
-    : C2Block1D(alloc),
-      mImpl(new Impl(alloc)) {}
-
-C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
-    : C2Block1D(alloc, offset, size),
-      mImpl(new Impl(alloc)) {}
+/**
+ * Linear block implementation.
+ */
+C2LinearBlock::C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+    : C2Block1D(impl, range) { }
 
 C2Acquirable<C2WriteView> C2LinearBlock::map() {
-    mImpl->map(capacity());
-    if (mImpl->base() == nullptr) {
-        C2DefaultWriteView view(mImpl->error());
-        return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
+    void *base = nullptr;
+    uint32_t len = size();
+    c2_status_t error = mImpl->getAllocation()->map(
+            offset(), len, { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, nullptr, &base);
+    // TODO: wait on fence
+    if (error == C2_OK) {
+        std::shared_ptr<WriteViewBuddy::Impl> rvi = std::shared_ptr<WriteViewBuddy::Impl>(
+                new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
+                [base, len](WriteViewBuddy::Impl *i) {
+                    (void)i->getAllocation()->unmap(base, len, nullptr);
+        });
+        return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
+    } else {
+        return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(error));
     }
-    C2DefaultWriteView view(this, mImpl->base());
-    view.setOffset_be(offset());
-    view.setSize_be(size());
-    return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
 }
 
-C2ConstLinearBlock C2LinearBlock::share(size_t offset, size_t size, C2Fence fence) {
-    return mImpl->share(offset, size, fence);
+C2ConstLinearBlock C2LinearBlock::share(size_t offset_, size_t size_, C2Fence fence) {
+    return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
+}
+
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+        const std::shared_ptr<C2LinearAllocation> &alloc,
+        const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
+    std::shared_ptr<C2Block1D::Impl> impl =
+        std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
+    return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
 }
 
 C2BasicLinearBlockPool::C2BasicLinearBlockPool(
         const std::shared_ptr<C2Allocator> &allocator)
-  : mAllocator(allocator) {}
+  : mAllocator(allocator) { }
 
 c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
         uint32_t capacity,
@@ -361,7 +333,7 @@
         return err;
     }
 
-    block->reset(new C2DefaultLinearBlock(alloc));
+    *block = _C2BlockFactory::CreateLinearBlock(alloc);
 
     return C2_OK;
 }
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
index a49fd24..05b46c3 100644
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -40,14 +40,9 @@
  * \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
  * \todo Make this allocator store extendable
  */
-class C2PlatformAllocatorStore : public C2AllocatorStore {
+class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
 public:
-    enum : id_t {
-        ION = PLATFORM_START,
-        GRALLOC,
-    };
-
-    C2PlatformAllocatorStore(
+    C2PlatformAllocatorStoreImpl(
         /* ionmapper */
     );
 
@@ -71,10 +66,10 @@
     std::shared_ptr<C2Allocator> fetchGrallocAllocator();
 };
 
-C2PlatformAllocatorStore::C2PlatformAllocatorStore() {
+C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
 }
 
-c2_status_t C2PlatformAllocatorStore::fetchAllocator(
+c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
         id_t id, std::shared_ptr<C2Allocator> *const allocator) {
     allocator->reset();
     switch (id) {
@@ -98,32 +93,32 @@
     return C2_OK;
 }
 
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchIonAllocator() {
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
     static std::mutex mutex;
     static std::weak_ptr<C2Allocator> ionAllocator;
     std::lock_guard<std::mutex> lock(mutex);
     std::shared_ptr<C2Allocator> allocator = ionAllocator.lock();
     if (allocator == nullptr) {
-        allocator = std::make_shared<C2AllocatorIon>();
+        allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
         ionAllocator = allocator;
     }
     return allocator;
 }
 
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchGrallocAllocator() {
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
     static std::mutex mutex;
     static std::weak_ptr<C2Allocator> grallocAllocator;
     std::lock_guard<std::mutex> lock(mutex);
     std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
     if (allocator == nullptr) {
-        allocator = std::make_shared<C2AllocatorGralloc>();
+        allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
         grallocAllocator = allocator;
     }
     return allocator;
 }
 
 std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
-    return std::make_shared<C2PlatformAllocatorStore>();
+    return std::make_shared<C2PlatformAllocatorStoreImpl>();
 }
 
 c2_status_t GetCodec2BlockPool(
@@ -408,6 +403,8 @@
     mComponents.emplace("c2.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
     mComponents.emplace("c2.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
     mComponents.emplace("c2.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
+    mComponents.emplace("c2.google.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
+    mComponents.emplace("c2.google.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
 }
 
 c2_status_t C2PlatformComponentStore::copyBuffer(
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
index 56fa317..0e1a3ac 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -61,7 +61,7 @@
             const C2Handle *handle,
             std::shared_ptr<C2GraphicAllocation> *allocation) override;
 
-    C2AllocatorGralloc();
+    C2AllocatorGralloc(id_t id = 0);
 
     c2_status_t status() const;
 
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
index bb815f9..716eae0 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -33,9 +33,7 @@
 
     virtual C2String getName() const override;
 
-    virtual std::shared_ptr<const Traits> getTraits() const override {
-        return nullptr; // \todo
-    }
+    virtual std::shared_ptr<const Traits> getTraits() const override;
 
     virtual c2_status_t newLinearAllocation(
             uint32_t capacity, C2MemoryUsage usage,
@@ -45,13 +43,14 @@
             const C2Handle *handle,
             std::shared_ptr<C2LinearAllocation> *allocation) override;
 
-    C2AllocatorIon();
+    C2AllocatorIon(id_t id);
 
     virtual c2_status_t status() const { return mInit; }
 
     virtual ~C2AllocatorIon() override;
 
 private:
+    std::shared_ptr<const Traits> mTraits;
     c2_status_t mInit;
     int mIonFd;
     usage_mapper_fn mUsageMapper;
diff --git a/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
new file mode 100644
index 0000000..cfea104
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
@@ -0,0 +1,89 @@
+/*
+ * 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 STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+#define STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+
+#include <C2Component.h>
+
+#include <functional>
+#include <memory>
+
+namespace android {
+
+/**
+ * Component factory object that enables to create a component and/or interface from a dynamically
+ * linked library. This is needed because the component/interfaces are managed objects, but we
+ * cannot safely create a managed object and pass it in C.
+ *
+ * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
+ * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
+ * derives from enable_shared_from_this.
+ *
+ */
+class C2ComponentFactory {
+public:
+    typedef std::function<void(::android::C2Component*)> ComponentDeleter;
+    typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;
+
+    /**
+     * Creates a component.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param id        component ID for the created component
+     * \param component shared pointer where the created component is stored. Cleared on
+     *                  failure and updated on success.
+     *
+     * \retval C2_OK        the component was created successfully
+     * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
+     *
+     * \retval C2_NO_MEMORY not enough memory to create the component
+     */
+    virtual c2_status_t createComponent(
+            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+            ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
+
+    /**
+     * Creates a component interface.
+     *
+     * This method SHALL return within 100ms.
+     *
+     * \param id        component interface ID for the created interface
+     * \param interface shared pointer where the created interface is stored. Cleared on
+     *                  failure and updated on success.
+     *
+     * \retval C2_OK        the component interface was created successfully
+     * \retval C2_TIMED_OUT could not create the component interface within the time limit
+     *                      (unexpected)
+     * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
+     *                      (unexpected)
+     *
+     * \retval C2_NO_MEMORY not enough memory to create the component interface
+     */
+    virtual c2_status_t createInterface(
+            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+            InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
+
+    virtual ~C2ComponentFactory() = default;
+
+    typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
+    typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
+};
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
index 2281dab..76b02ed 100644
--- a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -18,8 +18,8 @@
 #define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
 
 #include <C2Component.h>
+#include <C2ComponentFactory.h>
 
-#include <functional>
 #include <memory>
 
 namespace android {
@@ -31,6 +31,34 @@
 std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
 
 /**
+ * Platform allocator store IDs
+ */
+class C2PlatformAllocatorStore : public C2AllocatorStore {
+public:
+    enum : id_t {
+        /**
+         * ID of the ion backed platform allocator.
+         *
+         * C2Handle consists of:
+         *   fd  shared ion buffer handle
+         *   int size (lo 32 bits)
+         *   int size (hi 32 bits)
+         *   int magic '\xc2io\x00'
+         */
+        ION = PLATFORM_START,
+
+        /**
+         * ID of the gralloc backed platform allocator.
+         *
+         * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
+         * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2GrallocHandle
+         * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
+         */
+        GRALLOC,
+    };
+};
+
+/**
  * Retrieves a block pool for a component.
  *
  * \param id        the local ID of the block pool
@@ -54,73 +82,10 @@
         std::shared_ptr<C2BlockPool> *pool);
 
 /**
- * Component factory object that enables to create a component and/or interface from a dynamically
- * linked library. This is needed because the component/interfaces are managed objects, but we
- * cannot safely create a managed object and pass it in C.
- *
- * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
- * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
- * derives from enable_shared_from_this.
- *
- */
-class C2ComponentFactory {
-public:
-    typedef std::function<void(::android::C2Component*)> ComponentDeleter;
-    typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;
-
-    /**
-     * Creates a component.
-     *
-     * This method SHALL return within 100ms.
-     *
-     * \param id        component ID for the created component
-     * \param component shared pointer where the created component is stored. Cleared on
-     *                  failure and updated on success.
-     *
-     * \retval C2_OK        the component was created successfully
-     * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
-     * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
-     *
-     * \retval C2_NO_MEMORY not enough memory to create the component
-     */
-    virtual c2_status_t createComponent(
-            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
-            ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
-
-    /**
-     * Creates a component interface.
-     *
-     * This method SHALL return within 100ms.
-     *
-     * \param id        component interface ID for the created interface
-     * \param interface shared pointer where the created interface is stored. Cleared on
-     *                  failure and updated on success.
-     *
-     * \retval C2_OK        the component interface was created successfully
-     * \retval C2_TIMED_OUT could not create the component interface within the time limit
-     *                      (unexpected)
-     * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
-     *                      (unexpected)
-     *
-     * \retval C2_NO_MEMORY not enough memory to create the component interface
-     */
-    virtual c2_status_t createInterface(
-            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
-            InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
-
-    virtual ~C2ComponentFactory() = default;
-
-    typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
-    typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
-};
-
-/**
  * Returns the platform component store.
  * \retval nullptr if the platform component store could not be obtained
  */
 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();
-
-
 } // namespace android
 
 #endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
new file mode 100644
index 0000000..c84d1fb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
@@ -0,0 +1,41 @@
+/*
+ * 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_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+#define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
+#include <C2Buffer.h>
+
+namespace android {
+
+struct _C2BlockPoolData;
+
+/**
+ * Interface for creating blocks by block pool/buffer passing implementations.
+ */
+struct C2_HIDE _C2BlockFactory {
+    static
+    std::shared_ptr<C2LinearBlock> C2_HIDE CreateLinearBlock(
+            const std::shared_ptr<C2LinearAllocation> &alloc,
+            const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
+            size_t offset = 0,
+            size_t size = ~(size_t)0);
+};
+
+}
+
+#endif // ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
index 3d97d8c..58a0a4d 100644
--- a/media/libstagefright/codecs/g711/dec/Android.bp
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -1,4 +1,79 @@
 cc_library_shared {
+    name: "libstagefright_soft_c2g711alawdec",
+//    vendor_available: true,
+//    vndk: {
+//        enabled: true,
+//    },
+
+    srcs: [
+        "C2SoftG711.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-DALAW",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libstagefright_foundation",
+        "libstagefright_simple_c2component",
+    ],
+}
+
+cc_library_shared {
+    name: "libstagefright_soft_c2g711mlawdec",
+//    vendor_available: true,
+//    vndk: {
+//        enabled: true,
+//    },
+
+    srcs: [
+        "C2SoftG711.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+        diag: {
+            cfi: true,
+        },
+    },
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libstagefright_codec2",
+        "libstagefright_codec2_vndk",
+        "libstagefright_foundation",
+        "libstagefright_simple_c2component",
+    ],
+}
+
+cc_library_shared {
     name: "libstagefright_soft_g711dec",
     vendor_available: true,
     vndk: {
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
new file mode 100644
index 0000000..a26dbb9
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftG711"
+#include <utils/Log.h>
+
+#include "C2SoftG711.h"
+
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#ifdef ALAW
+#define COMPONENT_NAME "g711a"
+#else
+#define COMPONENT_NAME "g711m"
+#endif
+
+namespace android {
+
+C2SoftG711::C2SoftG711(const char *name, c2_node_id_t id)
+    : SimpleC2Component(
+            SimpleC2Interface::Builder(name, id)
+            .inputFormat(C2FormatCompressed)
+            .outputFormat(C2FormatAudio)
+            .build()) {
+}
+
+C2SoftG711::~C2SoftG711() {
+    onRelease();
+}
+
+c2_status_t C2SoftG711::onInit() {
+    mSignalledOutputEos = false;
+    return C2_OK;
+}
+
+c2_status_t C2SoftG711::onStop() {
+    mSignalledOutputEos = false;
+    return C2_OK;
+}
+
+void C2SoftG711::onReset() {
+    (void)onStop();
+}
+
+void C2SoftG711::onRelease() {
+}
+
+c2_status_t C2SoftG711::onFlush_sm() {
+    return onStop();
+}
+
+void C2SoftG711::process(
+        const std::unique_ptr<C2Work> &work,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    work->result = C2_OK;
+    work->workletsProcessed = 0u;
+    if (mSignalledOutputEos) {
+        work->result = C2_BAD_VALUE;
+        return;
+    }
+
+    const C2ConstLinearBlock &inBuffer =
+	work->input.buffers[0]->data().linearBlocks().front();
+    C2ReadView rView = inBuffer.map().get();
+    size_t inOffset = inBuffer.offset();
+    size_t inSize = inBuffer.size();
+    int outSize =  inSize * sizeof(int16_t);
+    if (inSize && rView.error()) {
+        ALOGE("read view map failed %d", rView.error());
+        work->result = C2_CORRUPTED;
+        return;
+    }
+    bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+
+    ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
+          (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
+
+    if (inSize == 0) {
+        work->worklets.front()->output.flags = work->input.flags;
+        work->worklets.front()->output.buffers.clear();
+        work->worklets.front()->output.ordinal = work->input.ordinal;
+        work->workletsProcessed = 1u;
+        if (eos) {
+            mSignalledOutputEos = true;
+            ALOGV("signalled EOS");
+        }
+        return;
+    }
+
+    uint8_t *inputptr = const_cast<uint8_t *>(rView.data() + inOffset);
+
+    std::shared_ptr<C2LinearBlock> block;
+    C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+    c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
+    if (err != C2_OK) {
+        ALOGE("fetchLinearBlock for Output failed with status %d", err);
+        work->result = C2_NO_MEMORY;
+        return;
+    }
+    C2WriteView wView = block->map().get();
+    if (wView.error()) {
+        ALOGE("write view map failed %d", wView.error());
+        work->result = C2_CORRUPTED;
+        return;
+    }
+    int16_t *outputptr = reinterpret_cast<int16_t *>(wView.data());
+
+#ifdef ALAW
+    DecodeALaw(outputptr, inputptr, inSize);
+#else
+    DecodeMLaw(outputptr, inputptr, inSize);
+#endif
+
+    work->worklets.front()->output.flags = work->input.flags;
+    work->worklets.front()->output.buffers.clear();
+    work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
+    work->worklets.front()->output.ordinal = work->input.ordinal;
+    work->workletsProcessed = 1u;
+
+    if (eos) {
+        mSignalledOutputEos = true;
+        ALOGV("signalled EOS");
+    }
+}
+
+c2_status_t C2SoftG711::drain(
+        uint32_t drainMode,
+        const std::shared_ptr<C2BlockPool> &pool) {
+    (void) pool;
+    if (drainMode == NO_DRAIN) {
+        ALOGW("drain with NO_DRAIN: no-op");
+        return C2_OK;
+    }
+    if (drainMode == DRAIN_CHAIN) {
+        ALOGW("DRAIN_CHAIN not supported");
+        return C2_OMITTED;
+    }
+
+    return C2_OK;
+}
+
+#ifdef ALAW
+void C2SoftG711::DecodeALaw(
+        int16_t *out, const uint8_t *in, size_t inSize) {
+    while (inSize > 0) {
+        inSize--;
+        int32_t x = *in++;
+
+        int32_t ix = x ^ 0x55;
+        ix &= 0x7f;
+
+        int32_t iexp = ix >> 4;
+        int32_t mant = ix & 0x0f;
+
+        if (iexp > 0) {
+            mant += 16;
+        }
+
+        mant = (mant << 4) + 8;
+
+        if (iexp > 1) {
+            mant = mant << (iexp - 1);
+        }
+
+        *out++ = (x > 127) ? mant : -mant;
+    }
+}
+#else
+void C2SoftG711::DecodeMLaw(
+        int16_t *out, const uint8_t *in, size_t inSize) {
+    while (inSize > 0) {
+        inSize--;
+        int32_t x = *in++;
+
+        int32_t mantissa = ~x;
+        int32_t exponent = (mantissa >> 4) & 7;
+        int32_t segment = exponent + 1;
+        mantissa &= 0x0f;
+
+        int32_t step = 4 << segment;
+
+        int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
+
+        *out++ = (x < 0x80) ? -abs : abs;
+    }
+}
+#endif
+
+class C2SoftG711DecFactory : public C2ComponentFactory {
+public:
+    virtual c2_status_t createComponent(
+            c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+            std::function<void(::android::C2Component*)> deleter) override {
+        *component = std::shared_ptr<C2Component>(new C2SoftG711(COMPONENT_NAME, id), deleter);
+        return C2_OK;
+    }
+
+    virtual c2_status_t createInterface(
+            c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+            std::function<void(::android::C2ComponentInterface*)> deleter) override {
+        *interface =
+                SimpleC2Interface::Builder(COMPONENT_NAME, id, deleter)
+                .inputFormat(C2FormatCompressed)
+                .outputFormat(C2FormatAudio)
+                .build();
+        return C2_OK;
+    }
+
+    virtual ~C2SoftG711DecFactory() override = default;
+};
+
+}  // namespace android
+
+extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+    ALOGV("in %s", __func__);
+    return new ::android::C2SoftG711DecFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+    ALOGV("in %s", __func__);
+    delete factory;
+}
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.h b/media/libstagefright/codecs/g711/dec/C2SoftG711.h
new file mode 100644
index 0000000..eed38c9
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/C2SoftG711.h
@@ -0,0 +1,56 @@
+/*
+ * 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 C2_SOFT_G711_H_
+#define C2_SOFT_G711_H_
+
+#include <SimpleC2Component.h>
+
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct C2SoftG711 : public SimpleC2Component {
+    C2SoftG711(const char *name, c2_node_id_t id);
+    virtual ~C2SoftG711();
+
+    // From SimpleC2Component
+    c2_status_t onInit() override;
+    c2_status_t onStop() override;
+    void onReset() override;
+    void onRelease() override;
+    c2_status_t onFlush_sm() override;
+    void process(
+            const std::unique_ptr<C2Work> &work,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+    c2_status_t drain(
+            uint32_t drainMode,
+            const std::shared_ptr<C2BlockPool> &pool) override;
+private:
+    bool mSignalledOutputEos;
+
+#ifdef ALAW
+    void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
+#else
+    void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
+#endif
+
+    DISALLOW_EVIL_CONSTRUCTORS(C2SoftG711);
+};
+
+}  // namespace android
+
+#endif  // C2_SOFT_G711_H_
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 61403be..f4bba59 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -30,7 +30,7 @@
 
 static const size_t kMaxMetadataSize = 3 * 1024 * 1024;
 
-struct MemorySource : public DataSource {
+struct MemorySource : public DataSourceBase {
     MemorySource(const uint8_t *data, size_t size)
         : mData(data),
           mSize(size) {
@@ -56,7 +56,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(MemorySource);
 };
 
-ID3::ID3(const sp<DataSource> &source, bool ignoreV1, off64_t offset)
+ID3::ID3(DataSourceBase *source, bool ignoreV1, off64_t offset)
     : mIsValid(false),
       mData(NULL),
       mSize(0),
@@ -77,7 +77,7 @@
       mFirstFrameOffset(0),
       mVersion(ID3_UNKNOWN),
       mRawSize(0) {
-    sp<MemorySource> source = new (std::nothrow) MemorySource(data, size);
+    MemorySource *source = new (std::nothrow) MemorySource(data, size);
 
     if (source == NULL)
         return;
@@ -87,6 +87,7 @@
     if (!mIsValid && !ignoreV1) {
         mIsValid = parseV1(source);
     }
+    delete source;
 }
 
 ID3::~ID3() {
@@ -118,7 +119,7 @@
     return true;
 }
 
-bool ID3::parseV2(const sp<DataSource> &source, off64_t offset) {
+bool ID3::parseV2(DataSourceBase *source, off64_t offset) {
 struct id3_header {
     char id[3];
     uint8_t version_major;
@@ -960,7 +961,7 @@
     return NULL;
 }
 
-bool ID3::parseV1(const sp<DataSource> &source) {
+bool ID3::parseV1(DataSourceBase *source) {
     const size_t V1_TAG_SIZE = 128;
 
     off64_t size;
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 442a3ff..86e6adf 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -72,7 +72,7 @@
     sp<FileSource> file = new FileSource(path);
     CHECK_EQ(file->initCheck(), (status_t)OK);
 
-    ID3 tag(file);
+    ID3 tag(file.get());
     if (!tag.isValid()) {
         printf("FAIL %s\n", path);
     } else {
diff --git a/media/libstagefright/include/Codec2Buffer.h b/media/libstagefright/include/Codec2Buffer.h
index 0272cea..6d85e83 100644
--- a/media/libstagefright/include/Codec2Buffer.h
+++ b/media/libstagefright/include/Codec2Buffer.h
@@ -24,30 +24,48 @@
 
 namespace android {
 
-class C2Buffer;
-
 /**
  * MediaCodecBuffer implementation wraps around C2LinearBlock.
  */
-class Codec2Buffer : public MediaCodecBuffer {
+class LinearBlockBuffer : public MediaCodecBuffer {
 public:
-    static sp<Codec2Buffer> allocate(
+    static sp<LinearBlockBuffer> allocate(
             const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block);
 
-    virtual ~Codec2Buffer() = default;
+    virtual ~LinearBlockBuffer() = default;
 
     C2ConstLinearBlock share();
 
 private:
-    Codec2Buffer(
+    LinearBlockBuffer(
             const sp<AMessage> &format,
-            const sp<ABuffer> &buffer,
+            C2WriteView &&writeView,
             const std::shared_ptr<C2LinearBlock> &block);
-    Codec2Buffer() = delete;
+    LinearBlockBuffer() = delete;
 
+    C2WriteView mWriteView;
     std::shared_ptr<C2LinearBlock> mBlock;
 };
 
+/**
+ * MediaCodecBuffer implementation wraps around C2ConstLinearBlock.
+ */
+class ConstLinearBlockBuffer : public MediaCodecBuffer {
+public:
+    static sp<ConstLinearBlockBuffer> allocate(
+            const sp<AMessage> &format, const C2ConstLinearBlock &block);
+
+    virtual ~ConstLinearBlockBuffer() = default;
+
+private:
+    ConstLinearBlockBuffer(
+            const sp<AMessage> &format,
+            C2ReadView &&readView);
+    ConstLinearBlockBuffer() = delete;
+
+    C2ReadView mReadView;
+};
+
 }  // namespace android
 
 #endif  // CODEC2_BUFFER_H_
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 11682f8..7c2391e 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -22,7 +22,7 @@
 
 namespace android {
 
-class DataSource;
+class DataSourceBase;
 class String8;
 
 struct ID3 {
@@ -35,7 +35,7 @@
         ID3_V2_4,
     };
 
-    explicit ID3(const sp<DataSource> &source, bool ignoreV1 = false, off64_t offset = 0);
+    explicit ID3(DataSourceBase *source, bool ignoreV1 = false, off64_t offset = 0);
     ID3(const uint8_t *data, size_t size, bool ignoreV1 = false);
     ~ID3();
 
@@ -85,8 +85,8 @@
     // only valid for IDV2+
     size_t mRawSize;
 
-    bool parseV1(const sp<DataSource> &source);
-    bool parseV2(const sp<DataSource> &source, off64_t offset);
+    bool parseV1(DataSourceBase *source);
+    bool parseV2(DataSourceBase *source, off64_t offset);
     void removeUnsynchronization();
     bool removeUnsynchronizationV2_4(bool iTunesHack);
 
diff --git a/media/libstagefright/include/media/stagefright/InterfaceUtils.h b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
index ceeaf31..568c735 100644
--- a/media/libstagefright/include/media/stagefright/InterfaceUtils.h
+++ b/media/libstagefright/include/media/stagefright/InterfaceUtils.h
@@ -41,7 +41,9 @@
 
 // Creates an IMediaExtractor wrapper to the given MediaExtractor.
 sp<IMediaExtractor> CreateIMediaExtractorFromMediaExtractor(
-        MediaExtractor *extractor, const sp<RefBase> &plugin);
+        MediaExtractor *extractor,
+        const sp<DataSource> &source,
+        const sp<RefBase> &plugin);
 
 // Creates a MediaSource which wraps the given IMediaSource object.
 sp<MediaSource> CreateMediaSourceFromIMediaSource(const sp<IMediaSource> &source);
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index 4610359..4d2f4f0 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -56,7 +56,7 @@
     static void RegisterExtractor(
             const sp<ExtractorPlugin> &plugin, List<sp<ExtractorPlugin>> &pluginList);
 
-    static MediaExtractor::CreatorFunc sniff(const sp<DataSource> &source,
+    static MediaExtractor::CreatorFunc sniff(DataSourceBase *source,
             String8 *mimeType, float *confidence, sp<AMessage> *meta,
             sp<ExtractorPlugin> &plugin);
 
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
index 78f3a84..22a8210 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaExtractor.h
@@ -28,7 +28,10 @@
 // IMediaExtractor wrapper to the MediaExtractor.
 class RemoteMediaExtractor : public BnMediaExtractor {
 public:
-    static sp<IMediaExtractor> wrap(MediaExtractor *extractor, const sp<RefBase> &plugin);
+    static sp<IMediaExtractor> wrap(
+            MediaExtractor *extractor,
+            const sp<DataSource> &source,
+            const sp<RefBase> &plugin);
 
     virtual ~RemoteMediaExtractor();
     virtual size_t countTracks();
@@ -41,15 +44,18 @@
     virtual void setUID(uid_t uid);
     virtual status_t setMediaCas(const HInterfaceToken &casToken);
     virtual const char * name();
-    virtual void release();
 
 private:
     MediaExtractor *mExtractor;
+    sp<DataSource> mSource;
     sp<RefBase> mExtractorPlugin;
 
     MediaAnalyticsItem *mAnalyticsItem;
 
-    explicit RemoteMediaExtractor(MediaExtractor *extractor, const sp<RefBase> &plugin);
+    explicit RemoteMediaExtractor(
+            MediaExtractor *extractor,
+            const sp<DataSource> &source,
+            const sp<RefBase> &plugin);
 
     DISALLOW_EVIL_CONSTRUCTORS(RemoteMediaExtractor);
 };
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
index aabbc69..eaf404c 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
@@ -31,6 +31,7 @@
     void onPlaybackStateChanged(in Bundle state);
     void onPlaylistChanged(in List<Bundle> playlist);
     void onPlaylistParamsChanged(in Bundle params);
+    void onPlaybackInfoChanged(in Bundle playbackInfo);
 
     /**
      * Called only when the controller is created with service's token.
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 41dfd00..6ee79a0 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -74,6 +74,8 @@
     private List<MediaItem2> mPlaylist;
     @GuardedBy("mLock")
     private PlaylistParams mPlaylistParams;
+    @GuardedBy("mLock")
+    private PlaybackInfo mPlaybackInfo;
 
     // Assignment should be used with the lock hold, but should be used without a lock to prevent
     // potential deadlock.
@@ -293,12 +295,6 @@
     }
 
     @Override
-    public PlaybackInfo getPlaybackInfo_impl() {
-        // TODO(jaewan): Implement
-        return null;
-    }
-
-    @Override
     public void prepareFromUri_impl(Uri uri, Bundle extras) {
         // TODO(jaewan): Implement
     }
@@ -413,6 +409,13 @@
     }
 
     @Override
+    public PlaybackInfo getPlaybackInfo_impl() {
+        synchronized (mLock) {
+            return mPlaybackInfo;
+        }
+    }
+
+    @Override
     public void setPlaylistParams_impl(PlaylistParams params) {
         if (params == null) {
             throw new IllegalArgumentException("PlaylistParams should not be null!");
@@ -449,6 +452,18 @@
         });
     }
 
+    private void pushPlaybackInfoChanges(final PlaybackInfo info) {
+        synchronized (mLock) {
+            mPlaybackInfo = info;
+        }
+        mCallbackExecutor.execute(() -> {
+            if (!mInstance.isConnected()) {
+                return;
+            }
+            mCallback.onPlaybackInfoChanged(info);
+        });
+    }
+
     private void pushPlaylistChanges(final List<Bundle> list) {
         final List<MediaItem2> playlist = new ArrayList<>();
         for (int i = 0; i < list.size(); i++) {
@@ -603,6 +618,19 @@
         }
 
         @Override
+        public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
+            final MediaController2Impl controller;
+            try {
+                controller = getController();
+            } catch (IllegalStateException e) {
+                Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+                return;
+            }
+            controller.pushPlaybackInfoChanges(
+                    PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
+        }
+
+        @Override
         public void onConnectionChanged(IMediaSession2 sessionBinder, Bundle commandGroup)
                 throws RuntimeException {
             final MediaController2Impl controller;
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index 54c8d41..77bd334 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -28,7 +28,7 @@
 import android.media.MediaSession2.ControllerInfo;
 import android.media.MediaSessionService2;
 import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
 import android.media.update.MediaLibraryService2Provider;
 import android.os.Bundle;
 
@@ -68,7 +68,7 @@
         private final MediaLibrarySessionCallback mCallback;
 
         public MediaLibrarySessionImpl(Context context,
-                MediaPlayerInterface player, String id, VolumeProvider volumeProvider,
+                MediaPlayerInterface player, String id, VolumeProvider2 volumeProvider,
                 int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
                 MediaLibrarySessionCallback callback) {
             super(context, player, id, volumeProvider, ratingType, sessionActivity,
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index f820cdc..cde98d2 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -21,15 +21,19 @@
 import static android.media.SessionToken2.TYPE_SESSION;
 import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
 
+import android.Manifest.permission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.Manifest.permission;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaController2;
+import android.media.MediaController2.PlaybackInfo;
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2;
 import android.media.MediaMetadata2;
@@ -48,14 +52,13 @@
 import android.media.MediaSessionService2;
 import android.media.PlaybackState2;
 import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
 import android.media.session.MediaSessionManager;
 import android.media.update.MediaSession2Provider;
-import android.media.update.MediaSession2Provider.CommandButtonProvider;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcelable;
 import android.os.Process;
-import android.os.IBinder;
 import android.os.ResultReceiver;
 import android.support.annotation.GuardedBy;
 import android.text.TextUtils;
@@ -80,11 +83,16 @@
     private final SessionCallback mCallback;
     private final MediaSession2Stub mSessionStub;
     private final SessionToken2 mSessionToken;
+    private final AudioManager mAudioManager;
     private final List<PlaybackListenerHolder> mListeners = new ArrayList<>();
 
     @GuardedBy("mLock")
     private MediaPlayerInterface mPlayer;
     @GuardedBy("mLock")
+    private VolumeProvider2 mVolumeProvider;
+    @GuardedBy("mLock")
+    private PlaybackInfo mPlaybackInfo;
+    @GuardedBy("mLock")
     private MyPlaybackListener mListener;
     @GuardedBy("mLock")
     private PlaylistParams mPlaylistParams;
@@ -103,8 +111,8 @@
      * @param ratingType
      * @param sessionActivity
      */
-    public MediaSession2Impl(Context context, MediaPlayerInterface player,
-            String id, VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+    public MediaSession2Impl(Context context, MediaPlayerInterface player, String id,
+            VolumeProvider2 volumeProvider, int ratingType, PendingIntent sessionActivity,
             Executor callbackExecutor, SessionCallback callback) {
         // TODO(jaewan): Keep other params.
         mInstance = createInstance();
@@ -116,6 +124,7 @@
         mCallback = callback;
         mCallbackExecutor = callbackExecutor;
         mSessionStub = new MediaSession2Stub(this);
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         // Infer type from the id and package name.
         String libraryService = getServiceName(context, MediaLibraryService2.SERVICE_INTERFACE, id);
@@ -135,6 +144,8 @@
         }
 
         setPlayerLocked(player);
+        mVolumeProvider = volumeProvider;
+        mPlaybackInfo = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
 
         // Ask server for the sanity check, and starts
         // Sanity check for making session ID unique 'per package' cannot be done in here.
@@ -178,12 +189,8 @@
         return serviceName;
     }
 
-    // TODO(jaewan): Add explicit release() and do not remove session object with the
-    //               setPlayer(null). Token can be available when player is null, and
-    //               controller can also attach to session.
     @Override
-    public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider volumeProvider)
-            throws IllegalArgumentException {
+    public void setPlayer_impl(MediaPlayerInterface player) {
         ensureCallingThread();
         if (player == null) {
             throw new IllegalArgumentException("player shouldn't be null");
@@ -191,9 +198,37 @@
         if (player == mPlayer) {
             return;
         }
+        PlaybackInfo info =
+                createPlaybackInfo(null /* VolumeProvider */, player.getAudioAttributes());
         synchronized (mLock) {
             setPlayerLocked(player);
+            mVolumeProvider = null;
+            mPlaybackInfo = info;
         }
+        mSessionStub.notifyPlaybackInfoChanged(info);
+    }
+
+    @Override
+    public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider2 volumeProvider)
+            throws IllegalArgumentException {
+        ensureCallingThread();
+        if (player == null) {
+            throw new IllegalArgumentException("player shouldn't be null");
+        }
+        if (volumeProvider == null) {
+            throw new IllegalArgumentException("volumeProvider shouldn't be null");
+        }
+        if (player == mPlayer) {
+            return;
+        }
+
+        PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
+        synchronized (mLock) {
+            setPlayerLocked(player);
+            mVolumeProvider = volumeProvider;
+            mPlaybackInfo = info;
+        }
+        mSessionStub.notifyPlaybackInfoChanged(info);
     }
 
     private void setPlayerLocked(MediaPlayerInterface player) {
@@ -206,6 +241,29 @@
         player.addPlaybackListener(mCallbackExecutor, mListener);
     }
 
+    private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
+        PlaybackInfo info;
+        if (volumeProvider == null) {
+            int stream = attrs == null ? AudioManager.STREAM_MUSIC : attrs.getVolumeControlStream();
+            info = PlaybackInfoImpl.createPlaybackInfo(
+                    mContext,
+                    PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+                    attrs,
+                    VolumeProvider2.VOLUME_CONTROL_ABSOLUTE,
+                    mAudioManager.getStreamMaxVolume(stream),
+                    mAudioManager.getStreamVolume(stream));
+        } else {
+            info = PlaybackInfoImpl.createPlaybackInfo(
+                    mContext,
+                    PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
+                    attrs,
+                    volumeProvider.getControlType(),
+                    volumeProvider.getMaxVolume(),
+                    volumeProvider.getCurrentVolume());
+        }
+        return info;
+    }
+
     @Override
     public void close_impl() {
         // Stop system service from listening this session first.
@@ -320,10 +378,6 @@
     //////////////////////////////////////////////////////////////////////////////////////
     // TODO(jaewan): Implement follows
     //////////////////////////////////////////////////////////////////////////////////////
-    @Override
-    public void setPlayer_impl(MediaPlayerInterface player) {
-        // TODO(jaewan): Implement
-    }
 
     @Override
     public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
@@ -1032,7 +1086,7 @@
         String mId;
         Executor mCallbackExecutor;
         C mCallback;
-        VolumeProvider mVolumeProvider;
+        VolumeProvider2 mVolumeProvider;
         int mRatingType;
         PendingIntent mSessionActivity;
 
@@ -1058,7 +1112,7 @@
             mId = "";
         }
 
-        public void setVolumeProvider_impl(VolumeProvider volumeProvider) {
+        public void setVolumeProvider_impl(VolumeProvider2 volumeProvider) {
             mVolumeProvider = volumeProvider;
         }
 
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 1f71187..5d3a06e 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -17,6 +17,7 @@
 package com.android.media;
 
 import android.content.Context;
+import android.media.MediaController2;
 import android.media.MediaItem2;
 import android.media.MediaLibraryService2.LibraryRoot;
 import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
@@ -130,6 +131,7 @@
                 // Controller may be died prematurely.
             }
             if (accept) {
+                // TODO(jaewan): We need to send current PlaybackInfo.
                 // If connection is accepted, notify the current state to the controller.
                 // It's needed because we cannot call synchronous calls between session/controller.
                 // Note: We're doing this after the onConnectionChanged(), but there's no guarantee
@@ -390,6 +392,21 @@
         }
     }
 
+    public void notifyPlaybackInfoChanged(MediaController2.PlaybackInfo playbackInfo) {
+        final List<ControllerInfo> list = getControllers();
+        for (int i = 0; i < list.size(); i++) {
+            IMediaSession2Callback callbackBinder =
+                    ControllerInfoImpl.from(list.get(i)).getControllerBinder();
+            try {
+                callbackBinder.onPlaybackInfoChanged(
+                        ((PlaybackInfoImpl) playbackInfo.getProvider()).toBundle());
+            } catch (RemoteException e) {
+                Log.w(TAG, "Controller is gone", e);
+                // TODO(jaewan): What to do when the controller is gone?
+            }
+        }
+    }
+
     public void sendCustomCommand(ControllerInfo controller, Command command, Bundle args,
             ResultReceiver receiver) {
         if (receiver != null && controller == null) {
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 661e252..46812e7 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -64,7 +64,7 @@
 import android.media.update.SessionToken2Provider;
 import android.media.update.StaticProvider;
 import android.media.update.VideoView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
 import android.media.update.VolumeProvider2Provider;
 import android.os.Bundle;
 import android.os.IInterface;
@@ -205,16 +205,17 @@
     }
 
     @Override
-    public MediaControlView2Provider createMediaControlView2(
-            MediaControlView2 instance, ViewProvider superProvider) {
-        return new MediaControlView2Impl(instance, superProvider);
+    public MediaControlView2Provider createMediaControlView2(MediaControlView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
+            @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        return new MediaControlView2Impl(instance, superProvider, privateProvider);
     }
 
     @Override
     public VideoView2Provider createVideoView2(
-            VideoView2 instance, ViewProvider superProvider,
+            VideoView2 instance, ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
             @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        return new VideoView2Impl(instance, superProvider, attrs, defStyleAttr, defStyleRes);
+        return new VideoView2Impl(instance, superProvider, privateProvider);
     }
 
     @Override
diff --git a/packages/MediaComponents/src/com/android/widget/BaseLayout.java b/packages/MediaComponents/src/com/android/widget/BaseLayout.java
new file mode 100644
index 0000000..fb6471d
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/BaseLayout.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.graphics.drawable.Drawable;
+import android.media.update.ViewGroupProvider;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
+
+import java.util.ArrayList;
+
+public class BaseLayout extends ViewGroupImpl {
+    private final ViewGroup mInstance;
+    private final ViewGroupProvider mSuperProvider;
+    private final ViewGroupProvider mPrivateProvider;
+
+    private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+    public BaseLayout(ViewGroup instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        super(instance, superProvider, privateProvider);
+        mInstance = instance;
+        mSuperProvider = superProvider;
+        mPrivateProvider = privateProvider;
+    }
+
+    @Override
+    public boolean checkLayoutParams_impl(LayoutParams p) {
+        return p instanceof MarginLayoutParams;
+    }
+
+    @Override
+    public LayoutParams generateDefaultLayoutParams_impl() {
+        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+        return new MarginLayoutParams(mInstance.getContext(), attrs);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
+        if (lp instanceof MarginLayoutParams) {
+            return lp;
+        }
+        return new MarginLayoutParams(lp);
+    }
+
+    @Override
+    public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+        int count = mInstance.getChildCount();
+
+        final boolean measureMatchParentChildren =
+                View.MeasureSpec.getMode(widthMeasureSpec) != View.MeasureSpec.EXACTLY ||
+                        View.MeasureSpec.getMode(heightMeasureSpec) != View.MeasureSpec.EXACTLY;
+        mMatchParentChildren.clear();
+
+        int maxHeight = 0;
+        int maxWidth = 0;
+        int childState = 0;
+
+        for (int i = 0; i < count; i++) {
+            final View child = mInstance.getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                mPrivateProvider.measureChildWithMargins_impl(
+                        child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+                maxWidth = Math.max(maxWidth,
+                        child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
+                maxHeight = Math.max(maxHeight,
+                        child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
+                childState = childState | child.getMeasuredState();
+                if (measureMatchParentChildren) {
+                    if (lp.width == LayoutParams.MATCH_PARENT ||
+                            lp.height == LayoutParams.MATCH_PARENT) {
+                        mMatchParentChildren.add(child);
+                    }
+                }
+            }
+        }
+
+        // Account for padding too
+        maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
+        maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
+
+        // Check against our minimum height and width
+        maxHeight = Math.max(maxHeight, mPrivateProvider.getSuggestedMinimumHeight_impl());
+        maxWidth = Math.max(maxWidth, mPrivateProvider.getSuggestedMinimumWidth_impl());
+
+        // Check against our foreground's minimum height and width
+        final Drawable drawable = mInstance.getForeground();
+        if (drawable != null) {
+            maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+            maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+        }
+
+        mPrivateProvider.setMeasuredDimension_impl(
+                mInstance.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+                mInstance.resolveSizeAndState(maxHeight, heightMeasureSpec,
+                        childState << View.MEASURED_HEIGHT_STATE_SHIFT));
+
+        count = mMatchParentChildren.size();
+        if (count > 1) {
+            for (int i = 0; i < count; i++) {
+                final View child = mMatchParentChildren.get(i);
+                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+                final int childWidthMeasureSpec;
+                if (lp.width == LayoutParams.MATCH_PARENT) {
+                    final int width = Math.max(0, mInstance.getMeasuredWidth()
+                            - getPaddingLeftWithForeground() - getPaddingRightWithForeground()
+                            - lp.leftMargin - lp.rightMargin);
+                    childWidthMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                            width, View.MeasureSpec.EXACTLY);
+                } else {
+                    childWidthMeasureSpec = mInstance.getChildMeasureSpec(widthMeasureSpec,
+                            getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
+                                    lp.leftMargin + lp.rightMargin,
+                            lp.width);
+                }
+
+                final int childHeightMeasureSpec;
+                if (lp.height == LayoutParams.MATCH_PARENT) {
+                    final int height = Math.max(0, mInstance.getMeasuredHeight()
+                            - getPaddingTopWithForeground() - getPaddingBottomWithForeground()
+                            - lp.topMargin - lp.bottomMargin);
+                    childHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+                            height, View.MeasureSpec.EXACTLY);
+                } else {
+                    childHeightMeasureSpec = mInstance.getChildMeasureSpec(heightMeasureSpec,
+                            getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
+                                    lp.topMargin + lp.bottomMargin,
+                            lp.height);
+                }
+
+                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+            }
+        }
+    }
+
+    @Override
+    public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+        final int count = mInstance.getChildCount();
+
+        final int parentLeft = getPaddingLeftWithForeground();
+        final int parentRight = right - left - getPaddingRightWithForeground();
+
+        final int parentTop = getPaddingTopWithForeground();
+        final int parentBottom = bottom - top - getPaddingBottomWithForeground();
+
+        for (int i = 0; i < count; i++) {
+            final View child = mInstance.getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+                final int width = child.getMeasuredWidth();
+                final int height = child.getMeasuredHeight();
+
+                int childLeft;
+                int childTop;
+
+                childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
+                        lp.leftMargin - lp.rightMargin;
+
+                childTop = parentTop + (parentBottom - parentTop - height) / 2 +
+                        lp.topMargin - lp.bottomMargin;
+
+                child.layout(childLeft, childTop, childLeft + width, childTop + height);
+            }
+        }
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState_impl() {
+        return false;
+    }
+
+    private int getPaddingLeftWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingLeft(), 0) :
+                mInstance.getPaddingLeft() + 0;
+    }
+
+    private int getPaddingRightWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingRight(), 0) :
+                mInstance.getPaddingRight() + 0;
+    }
+
+    private int getPaddingTopWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingTop(), 0) :
+                mInstance.getPaddingTop() + 0;
+    }
+
+    private int getPaddingBottomWithForeground() {
+        return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingBottom(), 0) :
+                mInstance.getPaddingBottom() + 0;
+    }
+}
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 138232e..1cdaaee 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -21,8 +21,10 @@
 import android.media.session.MediaController;
 import android.media.session.PlaybackState;
 import android.media.update.MediaControlView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
 import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -46,11 +48,10 @@
 import java.util.List;
 import java.util.Locale;
 
-public class MediaControlView2Impl implements MediaControlView2Provider {
+public class MediaControlView2Impl extends BaseLayout implements MediaControlView2Provider {
     private static final String TAG = "MediaControlView2";
 
     private final MediaControlView2 mInstance;
-    private final ViewProvider mSuperProvider;
 
     static final String ARGUMENT_KEY_FULLSCREEN = "fullScreen";
 
@@ -63,7 +64,7 @@
     private static final int REWIND_TIME_MS = 10000;
     private static final int FORWARD_TIME_MS = 30000;
 
-    private final AccessibilityManager mAccessibilityManager;
+    private AccessibilityManager mAccessibilityManager;
 
     private MediaController mController;
     private MediaController.TransportControls mControls;
@@ -113,10 +114,14 @@
     private MediaRouteButton mRouteButton;
     private MediaRouteSelector mRouteSelector;
 
-    public MediaControlView2Impl(
-            MediaControlView2 instance, ViewProvider superProvider) {
+    public MediaControlView2Impl(MediaControlView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        super(instance, superProvider, privateProvider);
         mInstance = instance;
-        mSuperProvider = superProvider;
+    }
+
+    @Override
+    public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         mAccessibilityManager = AccessibilityManager.getInstance(mInstance.getContext());
 
         // Inflate MediaControlView2 from XML
@@ -144,11 +149,6 @@
     }
 
     @Override
-    public boolean isShowing_impl() {
-        return (mInstance.getVisibility() == View.VISIBLE) ? true : false;
-    }
-
-    @Override
     public void setButtonVisibility_impl(int button, int visibility) {
         switch (button) {
             case MediaControlView2.BUTTON_PLAY_PAUSE:
@@ -233,39 +233,6 @@
     }
 
     @Override
-    public void onVisibilityAggregated_impl(boolean invisible) {
-        int visibility = mInstance.getVisibility();
-        if (mCurrentVisibility != visibility) {
-            mInstance.setVisibility(visibility);
-            mCurrentVisibility = visibility;
-
-            if (visibility == View.VISIBLE) {
-                setProgress();
-                disableUnsupportedButtons();
-                // cause the progress bar to be updated even if mShowing
-                // was already true.  This happens, for example, if we're
-                // paused with the progress bar showing the user hits play.
-                mInstance.post(mShowProgress);
-                resetFadeOutRunnable();
-            } else if (visibility == View.GONE) {
-                mInstance.removeCallbacks(mShowProgress);
-                // Remove existing call to mFadeOut to avoid from being called later.
-                mInstance.removeCallbacks(mFadeOut);
-            }
-        }
-    }
-
-    @Override
-    public void onAttachedToWindow_impl() {
-        mSuperProvider.onAttachedToWindow_impl();
-    }
-
-    @Override
-    public void onDetachedFromWindow_impl() {
-        mSuperProvider.onDetachedFromWindow_impl();
-    }
-
-    @Override
     public CharSequence getAccessibilityClassName_impl() {
         return MediaControlView2.class.getName();
     }
@@ -283,12 +250,9 @@
     }
 
     @Override
-    public void onFinishInflate_impl() {
-        mSuperProvider.onFinishInflate_impl();
-    }
-
-    @Override
     public void setEnabled_impl(boolean enabled) {
+        super.setEnabled_impl(enabled);
+
         if (mPlayPauseButton != null) {
             mPlayPauseButton.setEnabled(enabled);
         }
@@ -308,7 +272,31 @@
             mProgress.setEnabled(enabled);
         }
         disableUnsupportedButtons();
-        mSuperProvider.setEnabled_impl(enabled);
+    }
+
+    @Override
+    public void onVisibilityAggregated_impl(boolean invisible) {
+        super.onVisibilityAggregated_impl(invisible);
+
+        int visibility = mInstance.getVisibility();
+        if (mCurrentVisibility != visibility) {
+            mInstance.setVisibility(visibility);
+            mCurrentVisibility = visibility;
+
+            if (visibility == View.VISIBLE) {
+                setProgress();
+                disableUnsupportedButtons();
+                // cause the progress bar to be updated even if mShowing
+                // was already true.  This happens, for example, if we're
+                // paused with the progress bar showing the user hits play.
+                mInstance.post(mShowProgress);
+                resetFadeOutRunnable();
+            } else if (visibility == View.GONE) {
+                mInstance.removeCallbacks(mShowProgress);
+                // Remove existing call to mFadeOut to avoid from being called later.
+                mInstance.removeCallbacks(mFadeOut);
+            }
+        }
     }
 
     public void setRouteSelector(MediaRouteSelector selector) {
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 7218150..9f207b1 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -39,17 +39,16 @@
 import android.media.session.MediaSession;
 import android.media.session.PlaybackState;
 import android.media.update.VideoView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
-import android.widget.FrameLayout.LayoutParams;
+import android.view.ViewGroup.LayoutParams;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
 
@@ -67,12 +66,12 @@
 import java.util.Map;
 import java.util.concurrent.Executor;
 
-public class VideoView2Impl implements VideoView2Provider, VideoViewInterface.SurfaceListener {
+public class VideoView2Impl extends BaseLayout
+        implements VideoView2Provider, VideoViewInterface.SurfaceListener {
     private static final String TAG = "VideoView2";
     private static final boolean DEBUG = true; // STOPSHIP: Log.isLoggable(TAG, Log.DEBUG);
 
     private final VideoView2 mInstance;
-    private final ViewProvider mSuperProvider;
 
     private static final int STATE_ERROR = -1;
     private static final int STATE_IDLE = 0;
@@ -82,7 +81,7 @@
     private static final int STATE_PAUSED = 4;
     private static final int STATE_PLAYBACK_COMPLETED = 5;
 
-    private final AudioManager mAudioManager;
+    private AudioManager mAudioManager;
     private AudioAttributes mAudioAttributes;
     private int mAudioFocusType = AudioManager.AUDIOFOCUS_GAIN; // legacy focus gain
 
@@ -127,11 +126,14 @@
     // Refer: https://docs.google.com/document/d/1nzAfns6i2hJ3RkaUre3QMT6wsDedJ5ONLiA_OOBFFX8/edit
     private float mFallbackSpeed;  // keep the original speed before 'pause' is called.
 
-    public VideoView2Impl(VideoView2 instance, ViewProvider superProvider,
-            @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public VideoView2Impl(VideoView2 instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        super(instance, superProvider, privateProvider);
         mInstance = instance;
-        mSuperProvider = superProvider;
+    }
 
+    @Override
+    public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         mVideoWidth = 0;
         mVideoHeight = 0;
         mSpeed = 1.0f;
@@ -150,7 +152,6 @@
         mSurfaceView = new VideoSurfaceView(mInstance.getContext());
         LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
                 LayoutParams.MATCH_PARENT);
-        params.gravity = Gravity.CENTER;
         mTextureView.setLayoutParams(params);
         mSurfaceView.setLayoutParams(params);
         mTextureView.setSurfaceListener(this);
@@ -397,7 +398,7 @@
 
     @Override
     public void onAttachedToWindow_impl() {
-        mSuperProvider.onAttachedToWindow_impl();
+        super.onAttachedToWindow_impl();
 
         // Create MediaSession
         mMediaSession = new MediaSession(mInstance.getContext(), "VideoView2MediaSession");
@@ -412,8 +413,8 @@
 
     @Override
     public void onDetachedFromWindow_impl() {
-        Log.e(TAG, ".... Debugging. onDetachedFromWindow_impl()");
-        mSuperProvider.onDetachedFromWindow_impl();
+        super.onDetachedFromWindow_impl();
+
         mMediaSession.release();
         mMediaSession = null;
         mMediaController = null;
@@ -434,7 +435,8 @@
                 && isInPlaybackState() && mMediaControlView != null) {
             toggleMediaControlViewVisibility();
         }
-        return mSuperProvider.onTouchEvent_impl(ev);
+
+        return super.onTouchEvent_impl(ev);
     }
 
     @Override
@@ -443,17 +445,8 @@
                 && isInPlaybackState() && mMediaControlView != null) {
             toggleMediaControlViewVisibility();
         }
-        return mSuperProvider.onTrackballEvent_impl(ev);
-    }
 
-    @Override
-    public void onFinishInflate_impl() {
-        mSuperProvider.onFinishInflate_impl();
-    }
-
-    @Override
-    public void setEnabled_impl(boolean enabled) {
-        mSuperProvider.setEnabled_impl(enabled);
+        return super.onTrackballEvent_impl(ev);
     }
 
     ///////////////////////////////////////////////////
@@ -700,7 +693,7 @@
     }
 
     private void toggleMediaControlViewVisibility() {
-        if (mMediaControlView.isShowing()) {
+        if (mMediaControlView.getVisibility() == View.VISIBLE) {
             mMediaControlView.setVisibility(View.GONE);
         } else {
             mMediaControlView.setVisibility(View.VISIBLE);
diff --git a/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java b/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java
new file mode 100644
index 0000000..8598bb2
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.media.update.ViewGroupProvider;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+public abstract class ViewGroupImpl implements ViewGroupProvider {
+    private final ViewGroupProvider mSuperProvider;
+
+    public ViewGroupImpl(ViewGroup instance,
+            ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+        mSuperProvider = superProvider;
+    }
+
+    @Override
+    public void onAttachedToWindow_impl() {
+        mSuperProvider.onAttachedToWindow_impl();
+    }
+
+    @Override
+    public void onDetachedFromWindow_impl() {
+        mSuperProvider.onDetachedFromWindow_impl();
+    }
+
+    @Override
+    public CharSequence getAccessibilityClassName_impl() {
+        return mSuperProvider.getAccessibilityClassName_impl();
+    }
+
+    @Override
+    public boolean onTouchEvent_impl(MotionEvent ev) {
+        return mSuperProvider.onTouchEvent_impl(ev);
+    }
+
+    @Override
+    public boolean onTrackballEvent_impl(MotionEvent ev) {
+        return mSuperProvider.onTrackballEvent_impl(ev);
+    }
+
+    @Override
+    public void onFinishInflate_impl() {
+        mSuperProvider.onFinishInflate_impl();
+    }
+
+    @Override
+    public void setEnabled_impl(boolean enabled) {
+        mSuperProvider.setEnabled_impl(enabled);
+    }
+
+    @Override
+    public void onVisibilityAggregated_impl(boolean isVisible) {
+        mSuperProvider.onVisibilityAggregated_impl(isVisible);
+    }
+
+    @Override
+    public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+        mSuperProvider.onLayout_impl(changed, left, top, right, bottom);
+    }
+
+    @Override
+    public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+        mSuperProvider.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    public int getSuggestedMinimumWidth_impl() {
+        return mSuperProvider.getSuggestedMinimumWidth_impl();
+    }
+
+    @Override
+    public int getSuggestedMinimumHeight_impl() {
+        return mSuperProvider.getSuggestedMinimumHeight_impl();
+    }
+
+    @Override
+    public void setMeasuredDimension_impl(int measuredWidth, int measuredHeight) {
+        mSuperProvider.setMeasuredDimension_impl(measuredWidth, measuredHeight);
+    }
+
+    @Override
+    public boolean checkLayoutParams_impl(ViewGroup.LayoutParams p) {
+        return mSuperProvider.checkLayoutParams_impl(p);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateDefaultLayoutParams_impl() {
+        return mSuperProvider.generateDefaultLayoutParams_impl();
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+        return mSuperProvider.generateLayoutParams_impl(attrs);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams_impl(ViewGroup.LayoutParams lp) {
+        return mSuperProvider.generateLayoutParams_impl(lp);
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState_impl() {
+        return mSuperProvider.shouldDelayChildPressedState_impl();
+    }
+
+    @Override
+    public void measureChildWithMargins_impl(View child,
+        int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
+        mSuperProvider.measureChildWithMargins_impl(child,
+                parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+    }
+}
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index 38475a8..4cd8177 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -128,6 +128,13 @@
         }
 
         @Override
+        public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+            if (mCallbackProxy != null) {
+                mCallbackProxy.onPlaybackInfoChanged(info);
+            }
+        }
+
+        @Override
         public void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {
             super.onCustomCommand(command, args, receiver);
             mCallbackProxy.onCustomCommand(command, args, receiver);
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index ff8c2b7..43a6c2c 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -16,10 +16,16 @@
 
 package android.media;
 
+import static android.media.AudioAttributes.CONTENT_TYPE_MUSIC;
+import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
-import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 
 import android.media.MediaPlayerInterface.PlaybackListener;
 import android.media.MediaSession2.Builder;
@@ -36,19 +42,17 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
 
-import java.util.ArrayList;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import static org.junit.Assert.*;
-
 /**
  * Tests {@link MediaSession2}.
  */
@@ -105,6 +109,48 @@
     }
 
     @Test
+    public void testSetPlayerWithVolumeProvider() throws Exception {
+        MockPlayer player = new MockPlayer(0);
+        AudioAttributes attrs = new AudioAttributes.Builder()
+                .setContentType(CONTENT_TYPE_MUSIC)
+                .build();
+        player.setAudioAttributes(attrs);
+
+        final int maxVolume = 100;
+        final int currentVolume = 23;
+        final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
+        VolumeProvider2 volumeProvider =
+                new VolumeProvider2(mContext, volumeControlType, maxVolume, currentVolume) { };
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        final TestControllerCallbackInterface callback = new TestControllerCallbackInterface() {
+            @Override
+            public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+                assertEquals(MediaController2.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+                        info.getPlaybackType());
+                assertEquals(attrs, info.getAudioAttributes());
+                assertEquals(volumeControlType, info.getPlaybackType());
+                assertEquals(maxVolume, info.getMaxVolume());
+                assertEquals(currentVolume, info.getCurrentVolume());
+                latch.countDown();
+            }
+        };
+
+        final MediaController2 controller = createController(mSession.getToken(), true, callback);
+        assertNull(controller.getPlaybackInfo());
+
+        mSession.setPlayer(player, volumeProvider);
+        assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+        MediaController2.PlaybackInfo infoOut = controller.getPlaybackInfo();
+        assertEquals(MediaController2.PlaybackInfo.PLAYBACK_TYPE_REMOTE, infoOut.getPlaybackType());
+        assertEquals(attrs, infoOut.getAudioAttributes());
+        assertEquals(volumeControlType, infoOut.getPlaybackType());
+        assertEquals(maxVolume, infoOut.getMaxVolume());
+        assertEquals(currentVolume, infoOut.getCurrentVolume());
+    }
+
+    @Test
     public void testPlay() throws Exception {
         sHandler.postAndSync(() -> {
             mSession.play();
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index 5d94b17..513fa29 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -63,6 +63,7 @@
         // Add methods in ControllerCallback/BrowserCallback that you want to test.
         default void onPlaylistChanged(List<MediaItem2> playlist) {}
         default void onPlaylistParamsChanged(MediaSession2.PlaylistParams params) {}
+        default void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {}
 
         // Currently empty. Add methods in ControllerCallback/BrowserCallback that you want to test.
         default void onPlaybackStateChanged(PlaybackState2 state) { }
@@ -241,6 +242,13 @@
                 mCallbackProxy.onPlaylistParamsChanged(params);
             }
         }
+
+        @Override
+        public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+            if (mCallbackProxy != null) {
+                mCallbackProxy.onPlaybackInfoChanged(info);
+            }
+        }
     }
 
     public class TestMediaController extends MediaController2 implements TestControllerInterface {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 592273e..e7140c2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1984,7 +1984,7 @@
     for (size_t i = 0; i < fakeNum; i++) {
         struct audio_microphone_characteristic_t characteristics;
         sprintf(characteristics.device_id, "microphone:%zu", i);
-        characteristics.type = fakeTypes[i];
+        characteristics.device = fakeTypes[i];
         sprintf(characteristics.address, "");
         characteristics.location = AUDIO_MICROPHONE_LOCATION_MAINBODY;
         characteristics.group = 0;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 14d7e2e..24d862f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7051,7 +7051,7 @@
     // Fake data
     struct audio_microphone_characteristic_t characteristic;
     sprintf(characteristic.device_id, "builtin_mic");
-    characteristic.type = AUDIO_DEVICE_IN_BUILTIN_MIC;
+    characteristic.device = AUDIO_DEVICE_IN_BUILTIN_MIC;
     sprintf(characteristic.address, "");
     characteristic.location = AUDIO_MICROPHONE_LOCATION_MAINBODY;
     characteristic.group = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9ba8bb7..324201b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2400,7 +2400,7 @@
 
     Vector<camera3_stream_t*> streams;
     streams.setCapacity(config.num_streams);
-    std::vector<uint32_t> outBufSizes(mOutputStreams.size(), 0);
+    std::vector<uint32_t> bufferSizes(config.num_streams, 0);
 
 
     if (mInputStream != NULL) {
@@ -2435,7 +2435,9 @@
 
         if (outputStream->format == HAL_PIXEL_FORMAT_BLOB &&
                 outputStream->data_space == HAL_DATASPACE_V0_JFIF) {
-            outBufSizes[i] = static_cast<uint32_t>(
+            size_t k = i + ((mInputStream != nullptr) ? 1 : 0); // Input stream if present should
+                                                                // always occupy the initial entry.
+            bufferSizes[k] = static_cast<uint32_t>(
                     getJpegBufferSize(outputStream->width, outputStream->height));
         }
     }
@@ -2446,7 +2448,7 @@
     // max_buffers, usage, priv fields.
 
     const camera_metadata_t *sessionBuffer = sessionParams.getAndLock();
-    res = mInterface->configureStreams(sessionBuffer, &config, outBufSizes);
+    res = mInterface->configureStreams(sessionBuffer, &config, bufferSizes);
     sessionParams.unlock(sessionBuffer);
 
     if (res == BAD_VALUE) {
@@ -3504,7 +3506,7 @@
 }
 
 status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
-        camera3_stream_configuration *config, const std::vector<uint32_t>& outputBufferSizes) {
+        camera3_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
     ATRACE_NAME("CameraHal::configureStreams");
     if (!valid()) return INVALID_OPERATION;
     status_t res = OK;
@@ -3545,7 +3547,7 @@
         dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
         dst3_2.rotation = mapToStreamRotation((camera3_stream_rotation_t) src->rotation);
         dst3_4.v3_2 = dst3_2;
-        dst3_4.bufferSize = outputBufferSizes[i];
+        dst3_4.bufferSize = bufferSizes[i];
         if (src->physical_camera_id != nullptr) {
             dst3_4.physicalCameraId = src->physical_camera_id;
         }
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ccd9d7a..12cb6b4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -283,7 +283,7 @@
                 /*out*/ camera_metadata_t **requestTemplate);
         status_t configureStreams(const camera_metadata_t *sessionParams,
                 /*inout*/ camera3_stream_configuration *config,
-                const std::vector<uint32_t>& outputBufferSizes);
+                const std::vector<uint32_t>& bufferSizes);
         status_t processCaptureRequest(camera3_capture_request_t *request);
         status_t processBatchCaptureRequests(
                 std::vector<camera3_capture_request_t*>& requests,